[Process] Trow exceptions in case a Process method is supposed to be called after termination
This commit is contained in:
parent
0ae685878c
commit
449fe01992
@ -296,13 +296,11 @@ class Process
|
||||
*
|
||||
* @throws RuntimeException When process timed out
|
||||
* @throws RuntimeException When process stopped after receiving signal
|
||||
* @throws LogicException When process is not started
|
||||
* @throws LogicException When process is not yet started
|
||||
*/
|
||||
public function wait($callback = null)
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new LogicException(sprintf('Process must be started before calling %s', __FUNCTION__));
|
||||
}
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$this->updateStatus(false);
|
||||
if (null !== $callback) {
|
||||
@ -377,9 +375,7 @@ class Process
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new LogicException(sprintf('Process must be started before calling %s', __FUNCTION__));
|
||||
}
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$this->readPipes(false, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
|
||||
|
||||
@ -392,10 +388,14 @@ class Process
|
||||
* In comparison with the getOutput method which always return the whole
|
||||
* output, this one returns the new output since the last call.
|
||||
*
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @return string The process output since the last call
|
||||
*/
|
||||
public function getIncrementalOutput()
|
||||
{
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$data = $this->getOutput();
|
||||
|
||||
$latest = substr($data, $this->incrementalOutputOffset);
|
||||
@ -415,9 +415,7 @@ class Process
|
||||
*/
|
||||
public function getErrorOutput()
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new LogicException(sprintf('Process must be started before calling %s', __FUNCTION__));
|
||||
}
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$this->readPipes(false, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
|
||||
|
||||
@ -431,10 +429,14 @@ class Process
|
||||
* whole error output, this one returns the new error output since the last
|
||||
* call.
|
||||
*
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @return string The process error output since the last call
|
||||
*/
|
||||
public function getIncrementalErrorOutput()
|
||||
{
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$data = $this->getErrorOutput();
|
||||
|
||||
$latest = substr($data, $this->incrementalErrorOutputOffset);
|
||||
@ -446,7 +448,7 @@ class Process
|
||||
/**
|
||||
* Returns the exit code returned by the process.
|
||||
*
|
||||
* @return integer The exit status code
|
||||
* @return null|integer The exit status code, null if the Process is not terminated
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled
|
||||
*
|
||||
@ -469,14 +471,18 @@ class Process
|
||||
* This method relies on the Unix exit code status standardization
|
||||
* and might not be relevant for other operating systems.
|
||||
*
|
||||
* @return string A string representation for the exit status code
|
||||
* @return null|string A string representation for the exit status code, null if the Process is not terminated.
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled
|
||||
*
|
||||
* @see http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
* @see http://en.wikipedia.org/wiki/Unix_signal
|
||||
*/
|
||||
public function getExitCodeText()
|
||||
{
|
||||
$exitcode = $this->getExitCode();
|
||||
if (null === $exitcode = $this->getExitCode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
|
||||
}
|
||||
@ -501,11 +507,14 @@ class Process
|
||||
* @return Boolean
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
* @throws LogicException In case the process is not terminated.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasBeenSignaled()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
if ($this->isSigchildEnabled()) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
|
||||
}
|
||||
@ -523,11 +532,14 @@ class Process
|
||||
* @return integer
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
* @throws LogicException In case the process is not terminated.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getTermSignal()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
if ($this->isSigchildEnabled()) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
|
||||
}
|
||||
@ -544,10 +556,14 @@ class Process
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @throws LogicException In case the process is not terminated.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasBeenStopped()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->processInformation['stopped'];
|
||||
@ -560,10 +576,14 @@ class Process
|
||||
*
|
||||
* @return integer
|
||||
*
|
||||
* @throws LogicException In case the process is not terminated.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getStopSignal()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->processInformation['stopsig'];
|
||||
@ -945,6 +965,10 @@ class Process
|
||||
*/
|
||||
public function checkTimeout()
|
||||
{
|
||||
if ($this->status !== self::STATUS_STARTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
|
||||
$this->stop(0);
|
||||
|
||||
@ -1162,4 +1186,32 @@ class Process
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the process is running or terminated, throws a LogicException if the process has a not started.
|
||||
*
|
||||
* @param $functionName The function name that was called.
|
||||
*
|
||||
* @throws LogicException If the process has not run.
|
||||
*/
|
||||
private function requireProcessIsStarted($functionName)
|
||||
{
|
||||
if (!$this->isStarted()) {
|
||||
throw new LogicException(sprintf('Process must be started before calling %s.', $functionName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the process is terminated, throws a LogicException if the process has a status different than `terminated`.
|
||||
*
|
||||
* @param $functionName The function name that was called.
|
||||
*
|
||||
* @throws LogicException If the process is not yet terminated.
|
||||
*/
|
||||
private function requireProcessIsTerminated($functionName)
|
||||
{
|
||||
if (!$this->isTerminated()) {
|
||||
throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,6 +272,12 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($process->isSuccessful());
|
||||
}
|
||||
|
||||
public function testExitCodeTextIsNullWhenExitCodeIsNull()
|
||||
{
|
||||
$process = $this->getProcess('');
|
||||
$this->assertNull($process->getExitCodeText());
|
||||
}
|
||||
|
||||
public function testExitCodeText()
|
||||
{
|
||||
$process = $this->getProcess('');
|
||||
@ -512,6 +518,19 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertLessThan($timeout + Process::TIMEOUT_PRECISION, $duration);
|
||||
}
|
||||
|
||||
public function testCheckTimeoutOnNonStartedProcess()
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(3);"');
|
||||
$process->checkTimeout();
|
||||
}
|
||||
|
||||
public function testCheckTimeoutOnTerminatedProcess()
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process->run();
|
||||
$process->checkTimeout();
|
||||
}
|
||||
|
||||
public function testCheckTimeoutOnStartedProcess()
|
||||
{
|
||||
$timeout = 0.5;
|
||||
@ -618,33 +637,52 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\LogicException
|
||||
* @expectedExceptionMessage Process must be started before calling getOutput
|
||||
* @dataProvider provideMethodsThatNeedARunningProcess
|
||||
*/
|
||||
public function testGetOutputProcessNotStarted()
|
||||
public function testMethodsThatNeedARunningProcess($method)
|
||||
{
|
||||
$process = $this->getProcess('php -m');
|
||||
$process->getOutput();
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\LogicException', sprintf('Process must be started before calling %s.', $method));
|
||||
call_user_func(array($process, $method));
|
||||
}
|
||||
|
||||
public function provideMethodsThatNeedARunningProcess()
|
||||
{
|
||||
return array(
|
||||
array('getOutput'),
|
||||
array('getIncrementalOutput'),
|
||||
array('getErrorOutput'),
|
||||
array('getIncrementalErrorOutput'),
|
||||
array('wait'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\LogicException
|
||||
* @expectedExceptionMessage Process must be started before calling getErrorOutput
|
||||
* @dataProvider provideMethodsThatNeedATerminatedProcess
|
||||
*/
|
||||
public function testGetErrorOutputProcessNotStarted()
|
||||
public function testMethodsThatNeedATerminatedProcess($method)
|
||||
{
|
||||
$process = $this->getProcess('php -m');
|
||||
$process->getErrorOutput();
|
||||
$process = $this->getProcess('php -r "sleep(1);"');
|
||||
$process->start();
|
||||
try {
|
||||
call_user_func(array($process, $method));
|
||||
$process->stop(0);
|
||||
$this->fail('A LogicException must have been thrown');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('Symfony\Component\Process\Exception\LogicException', $e);
|
||||
$this->assertEquals(sprintf('Process must be terminated before calling %s.', $method), $e->getMessage());
|
||||
}
|
||||
$process->stop(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\LogicException
|
||||
* @expectedExceptionMessage Process must be started before calling wait
|
||||
*/
|
||||
public function testWaitProcessWithoutTimeoutNotStarted()
|
||||
public function provideMethodsThatNeedATerminatedProcess()
|
||||
{
|
||||
$process = $this->getProcess('php -m')->setTimeout(null);
|
||||
$process->wait();
|
||||
return array(
|
||||
array('hasBeenSignaled'),
|
||||
array('getTermSignal'),
|
||||
array('hasBeenStopped'),
|
||||
array('getStopSignal'),
|
||||
);
|
||||
}
|
||||
|
||||
private function verifyPosixIsEnabled()
|
||||
|
Reference in New Issue
Block a user