nul" : "sleep 2"; /** * @expectedException \Amp\Process\StatusError */ public function testMultipleExecution() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); yield $process->start(); yield $process->start(); }); } public function testIsRunning() { Loop::run(function () { $process = new Process(\DIRECTORY_SEPARATOR === "\\" ? "cmd /c exit 42" : "exit 42"); yield $process->start(); $promise = $process->join(); $this->assertTrue($process->isRunning()); yield $promise; $this->assertFalse($process->isRunning()); }); } public function testExecuteResolvesToExitCode() { Loop::run(function () { $process = new Process(\DIRECTORY_SEPARATOR === "\\" ? "cmd /c exit 42" : "exit 42"); yield $process->start(); $code = yield $process->join(); $this->assertSame(42, $code); $this->assertFalse($process->isRunning()); }); } public function testCommandCanRun() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); $this->assertInternalType('int', yield $process->start()); $this->assertSame(0, yield $process->join()); }); } public function testProcessCanTerminate() { if (\DIRECTORY_SEPARATOR === "\\") { $this->markTestSkipped("Signals are not supported on Windows"); } Loop::run(function () { $process = new Process(self::CMD_PROCESS_SLOW); yield $process->start(); $process->signal(0); $this->assertSame(0, yield $process->join()); }); } public function testGetWorkingDirectoryIsDefault() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); $this->assertSame(\getcwd(), $process->getWorkingDirectory()); }); } public function testGetWorkingDirectoryIsCustomized() { Loop::run(function () { $process = new Process(self::CMD_PROCESS, __DIR__); $this->assertSame(__DIR__, $process->getWorkingDirectory()); }); } public function testGetEnv() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); $this->assertSame([], $process->getEnv()); }); } public function testGetStdin() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); yield $process->start(); $this->assertInstanceOf(ProcessOutputStream::class, $process->getStdin()); yield $process->join(); }); } public function testGetStdout() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); yield $process->start(); $this->assertInstanceOf(ProcessInputStream::class, $process->getStdout()); yield $process->join(); }); } public function testGetStderr() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); yield $process->start(); $this->assertInstanceOf(ProcessInputStream::class, $process->getStderr()); yield $process->join(); }); } public function testProcessEnvIsValid() { Loop::run(function () { $process = new Process(self::CMD_PROCESS, null, [ 'test' => 'foobar', 'PATH' => \getenv('PATH'), 'SystemRoot' => \getenv('SystemRoot') ?: '', // required on Windows for process wrapper ]); yield $process->start(); $this->assertSame('foobar', $process->getEnv()['test']); yield $process->join(); }); } /** * @expectedException \Error */ public function testProcessEnvIsInvalid() { $process = new Process(self::CMD_PROCESS, null, [ ['error_value'] ]); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process has not been started or has not completed starting. */ public function testGetStdinIsStatusError() { $process = new Process(self::CMD_PROCESS, null, []); $process->getStdin(); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process has not been started or has not completed starting. */ public function testGetStdoutIsStatusError() { $process = new Process(self::CMD_PROCESS, null, []); $process->getStdout(); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process has not been started or has not completed starting. */ public function testGetStderrIsStatusError() { $process = new Process(self::CMD_PROCESS, null, []); $process->getStderr(); } /** * @expectedException \Error * @expectedExceptionMessage Cloning is not allowed! */ public function testProcessCantBeCloned() { $process = new Process(self::CMD_PROCESS); clone $process; } /** * @expectedException \Amp\Process\ProcessException * @expectedExceptionMessage The process was killed */ public function testKillImmediately() { Loop::run(function () { $process = new Process(self::CMD_PROCESS_SLOW); $process->start(); $process->kill(); yield $process->join(); }); } /** * @expectedException \Amp\Process\ProcessException * @expectedExceptionMessage The process was killed */ public function testKillThenReadStdout() { Loop::run(function () { $process = new Process(self::CMD_PROCESS_SLOW); $process->start(); yield new Delayed(100); // Give process a chance to start, otherwise a different error is thrown. $process->kill(); $this->assertNull(yield $process->getStdout()->read()); yield $process->join(); }); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process has not been started. */ public function testProcessHasNotBeenStartedWithJoin() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); yield $process->join(); }); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process has not been started or has not completed starting. */ public function testProcessHasNotBeenStartedWithGetPid() { $process = new Process(self::CMD_PROCESS); $process->getPid(); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process is not running. */ public function testProcessIsNotRunningWithKill() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); $process->kill(); }); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process is not running. */ public function testProcessIsNotRunningWithSignal() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); $process->signal(0); }); } /** * @expectedException \Amp\Process\StatusError * @expectedExceptionMessage Process has not been started. */ public function testProcessHasBeenStarted() { Loop::run(function () { $process = new Process(self::CMD_PROCESS); yield $process->join(); }); } public function testCommand() { $process = new Process([self::CMD_PROCESS]); $this->assertSame(\implode(" ", \array_map("escapeshellarg", [self::CMD_PROCESS])), $process->getCommand()); } public function testOptions() { $process = new Process(self::CMD_PROCESS); $this->assertSame([], $process->getOptions()); } public function getProcessCounts(): array { return \array_map(function (int $count): array { return [$count]; }, \range(2, 32, 2)); } /** * @dataProvider getProcessCounts * * @param int $count */ public function testSpawnMultipleProcesses(int $count) { Loop::run(function () use ($count) { $processes = []; for ($i = 0; $i < $count; ++$i) { $command = \DIRECTORY_SEPARATOR === "\\" ? "cmd /c exit $i" : "exit $i"; $processes[] = new Process(self::CMD_PROCESS_SLOW . " && " . $command); } $promises = []; foreach ($processes as $process) { $process->start(); $promises[] = $process->join(); } $this->assertSame(\range(0, $count - 1), yield $promises); }); } public function testReadOutputAfterExit() { Loop::run(function () { $process = new Process(["php", __DIR__ . "/bin/worker.php"]); yield $process->start(); $process->getStdin()->write("exit 2"); $this->assertSame("..", yield $process->getStdout()->read()); $this->assertSame(0, yield $process->join()); }); } public function testReadOutputAfterExitWithLongOutput() { Loop::run(function () { $process = new Process(["php", __DIR__ . "/bin/worker.php"]); yield $process->start(); $count = 128 * 1024 + 1; $process->getStdin()->write("exit " . $count); $this->assertSame(\str_repeat(".", $count), yield new Message($process->getStdout())); $this->assertSame(0, yield $process->join()); }); } public function testKillPHPImmediatly() { Loop::run(function () { $socket = \stream_socket_server("tcp://0.0.0.0:10000", $errno, $errstr); $this->assertNotFalse($socket); $process = new Process(["php", __DIR__ . "/bin/socket-worker.php"]); yield $process->start(); $conn = \stream_socket_accept($socket); $this->assertSame('start', \fread($conn, 5)); $process->kill(); $this->assertEmpty(\fread($conn, 3)); }); } public function testSignal() { Loop::run(function () { $process = new Process(["php", __DIR__ . "/bin/signal-process.php"]); yield $process->start(); yield new Delayed(100); // Give process time to set up single handler. $process->signal(\SIGTERM); $this->assertSame(42, yield $process->join()); }); } public function testDebugInfo() { Loop::run(function () { $process = new Process(["php", __DIR__ . "/bin/worker.php"], __DIR__); $this->assertSame([ 'command' => "'php' '" . __DIR__ . "/bin/worker.php'", 'cwd' => __DIR__, 'env' => [], 'options' => [], 'pid' => null, 'status' => -1, ], $process->__debugInfo()); yield $process->start(); $debug = $process->__debugInfo(); $this->assertInternalType('int', $debug['pid']); $this->assertSame(ProcessStatus::RUNNING, $debug['status']); }); } }