/** * @dataProvider nonBlockingProvider * * @param $timeout * @param bool $wait * @param bool $finish * @param string $output * @param string $expectedOutput */ public function testNonBlocking($timeout, $wait, $finish, $output, $expectedOutput) { $this->pid->shouldReceive("getPid")->withArgs([true])->andThrow("Silktide\\Teamster\\Exception\\PidException"); $this->pid->shouldReceive("cleanPid")->once()->andReturn(true); // seems we need to use a real file and can't mock the filesystem $outFile = __DIR__ . "/output/output"; $spec = $this->setupOutFile($outFile); // setup command $command = "php -r \"\\\$s = microtime(true); do {usleep({$timeout} / 4);} while (microtime(true) - \\\$s < {$timeout} / 1000000); echo '{$output}';\""; // do the test $runner = new ProcessRunner($this->pidFactory, $spec, "dud", 1, 5, 5); $runner->execute($command, false); $this->assertTrue($runner->isRunning($this->pid)); if ($wait) { usleep($timeout * 2); } if ($finish) { $runner->finish($this->pid); } $this->assertFalse($runner->isRunning($this->pid)); $this->assertEquals($expectedOutput, file_get_contents($outFile)); }
public function testStart() { $this->input->shouldReceive("getArgument")->andReturn("start"); $pid = getmypid(); $this->pid->shouldReceive("getPid")->andReturn($pid); $poolCommand = "pool:command"; // test when pool is already running $command = new PoolControlCommand($this->runnerFactory, $this->pidFactory, "pool.pid", $poolCommand); try { $command->execute($this->input, $this->output); $this->fail("Should not be able to start a pool when one is already running"); } catch (ProcessException $e) { } // test when pool is stopped $noPidFile = "no.pid"; $noPid = \Mockery::mock("Silktide\\Teamster\\Pool\\Pid\\PidInterface")->shouldIgnoreMissing(true); $noPid->shouldReceive("getPid")->atLeast()->times(1)->andThrow("Silktide\\Teamster\\Exception\\PidException"); $noPidFactory = \Mockery::mock("Silktide\\Teamster\\Pool\\Pid\\PidFactoryInterface"); $noPidFactory->shouldReceive("create")->withArgs([$noPidFile])->once()->andReturn($noPid); $this->runner->shouldReceive("execute")->withArgs([$poolCommand, false])->once(); $command = new PoolControlCommand($this->runnerFactory, $noPidFactory, $noPidFile, $poolCommand); $command->execute($this->input, $this->output); }
/** * {@inheritDoc} * @throws RunnerException */ public function finish(PidInterface $pid = null) { if (!is_resource($this->process)) { // no process to close, make sure the PID file is removed if (!empty($pid)) { $pid->cleanPid(); } return; } // check if the process is still running $status = proc_get_status($this->process); if ($status["running"]) { // terminate the process kindly proc_terminate($this->process, SIGTERM); $startTime = microtime(true); $terminating = false; do { if (!$terminating && microtime(true) - $startTime > self::TERMINATE_TIMEOUT) { // terminate the process with extreme prejudice proc_terminate($this->process, SIGKILL); $terminating = true; } // ... and wait for confirmation usleep(self::PROCESS_CHECK_INTERVAL); $status = proc_get_status($this->process); } while ($status["running"]); } // close the pipes $this->closePipes(); if (proc_close($this->process) === false) { throw new RunnerException("Could not close process"); } $this->process = null; if (!empty($pid) && !$pid->cleanPid()) { // error deleting the PID file, DO NOT CONTINUE throw new RunnerException("Could not release the PID file"); } }