PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Symfony/Component/Process/Tests/AbstractProcessTest.php

https://github.com/ptheg/symfony
PHP | 367 lines | 263 code | 61 blank | 43 comment | 9 complexity | 0ae2120c76e982685d035f8af4930e52 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Process\Tests;
  11. use Symfony\Component\Process\Process;
  12. /**
  13. * @author Robert Schรถnthal <seroscho@googlemail.com>
  14. */
  15. abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
  16. {
  17. protected abstract function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array());
  18. /**
  19. * @expectedException Symfony\Component\Process\Exception\InvalidArgumentException
  20. */
  21. public function testNegativeTimeoutFromConstructor()
  22. {
  23. $this->getProcess('', null, null, null, -1);
  24. }
  25. /**
  26. * @expectedException Symfony\Component\Process\Exception\InvalidArgumentException
  27. */
  28. public function testNegativeTimeoutFromSetter()
  29. {
  30. $p = $this->getProcess('');
  31. $p->setTimeout(-1);
  32. }
  33. public function testNullTimeout()
  34. {
  35. $p = $this->getProcess('');
  36. $p->setTimeout(10);
  37. $p->setTimeout(null);
  38. $this->assertNull($p->getTimeout());
  39. }
  40. /**
  41. * tests results from sub processes
  42. *
  43. * @dataProvider responsesCodeProvider
  44. */
  45. public function testProcessResponses($expected, $getter, $code)
  46. {
  47. $p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code)));
  48. $p->run();
  49. $this->assertSame($expected, $p->$getter());
  50. }
  51. /**
  52. * tests results from sub processes
  53. *
  54. * @dataProvider pipesCodeProvider
  55. */
  56. public function testProcessPipes($expected, $code)
  57. {
  58. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  59. $this->markTestSkipped('Test hangs on Windows & PHP due to https://bugs.php.net/bug.php?id=60120 and https://bugs.php.net/bug.php?id=51800');
  60. }
  61. $p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code)));
  62. $p->setStdin($expected);
  63. $p->run();
  64. $this->assertSame($expected, $p->getOutput());
  65. $this->assertSame($expected, $p->getErrorOutput());
  66. }
  67. public function chainedCommandsOutputProvider()
  68. {
  69. return array(
  70. array('11', ';', '1'),
  71. array('22', '&&', '2'),
  72. );
  73. }
  74. /**
  75. *
  76. * @dataProvider chainedCommandsOutputProvider
  77. */
  78. public function testChainedCommandsOutput($expected, $operator, $input)
  79. {
  80. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  81. $this->markTestSkipped('Does it work on windows ?');
  82. }
  83. $process = $this->getProcess(sprintf('echo -n %s %s echo -n %s', $input, $operator, $input));
  84. $process->run();
  85. $this->assertEquals($expected, $process->getOutput());
  86. }
  87. public function testCallbackIsExecutedForOutput()
  88. {
  89. $p = $this->getProcess(sprintf('php -r %s', escapeshellarg('echo \'foo\';')));
  90. $called = false;
  91. $p->run(function ($type, $buffer) use (&$called) {
  92. $called = $buffer === 'foo';
  93. });
  94. $this->assertTrue($called, 'The callback should be executed with the output');
  95. }
  96. public function testGetErrorOutput()
  97. {
  98. $p = new Process(sprintf('php -r %s', escapeshellarg('ini_set(\'display_errors\',\'on\');$n=0;while($n<3){echo $a;$n++;}')));
  99. $p->run();
  100. $this->assertEquals(3, preg_match_all('/PHP Notice/', $p->getErrorOutput(), $matches));
  101. }
  102. public function testGetIncrementalErrorOutput()
  103. {
  104. $p = new Process(sprintf('php -r %s', escapeshellarg('ini_set(\'display_errors\',\'on\');usleep(50000);$n=0;while($n<3){echo $a;$n++;}')));
  105. $p->start();
  106. while ($p->isRunning()) {
  107. $this->assertLessThanOrEqual(1, preg_match_all('/PHP Notice/', $p->getIncrementalOutput(), $matches));
  108. usleep(20000);
  109. }
  110. }
  111. public function testGetOutput()
  112. {
  113. $p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while($n<3){echo \' foo \';$n++;}')));
  114. $p->run();
  115. $this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches));
  116. }
  117. public function testGetIncrementalOutput()
  118. {
  119. $p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while($n<3){echo \' foo \';usleep(50000);$n++;}')));
  120. $p->start();
  121. while ($p->isRunning()) {
  122. $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches));
  123. usleep(20000);
  124. }
  125. }
  126. public function testExitCodeCommandFailed()
  127. {
  128. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  129. $this->markTestSkipped('Windows does not support POSIX exit code');
  130. }
  131. // such command run in bash return an exitcode 127
  132. $process = $this->getProcess('nonexistingcommandIhopeneversomeonewouldnameacommandlikethis');
  133. $process->run();
  134. $this->assertGreaterThan(0, $process->getExitCode());
  135. }
  136. public function testExitCodeText()
  137. {
  138. $process = $this->getProcess('');
  139. $r = new \ReflectionObject($process);
  140. $p = $r->getProperty('exitcode');
  141. $p->setAccessible(true);
  142. $p->setValue($process, 2);
  143. $this->assertEquals('Misuse of shell builtins', $process->getExitCodeText());
  144. }
  145. public function testStartIsNonBlocking()
  146. {
  147. $process = $this->getProcess('php -r "sleep(4);"');
  148. $start = microtime(true);
  149. $process->start();
  150. $end = microtime(true);
  151. $this->assertLessThan(1 , $end-$start);
  152. }
  153. public function testUpdateStatus()
  154. {
  155. $process = $this->getProcess('php -h');
  156. $process->run();
  157. $this->assertTrue(strlen($process->getOutput()) > 0);
  158. }
  159. public function testGetExitCode()
  160. {
  161. $process = $this->getProcess('php -m');
  162. $process->run();
  163. $this->assertEquals(0, $process->getExitCode());
  164. }
  165. public function testStatus()
  166. {
  167. $process = $this->getProcess('php -r "sleep(1);"');
  168. $this->assertFalse($process->isRunning());
  169. $this->assertFalse($process->isStarted());
  170. $this->assertFalse($process->isTerminated());
  171. $this->assertSame(Process::STATUS_READY, $process->getStatus());
  172. $process->start();
  173. $this->assertTrue($process->isRunning());
  174. $this->assertTrue($process->isStarted());
  175. $this->assertFalse($process->isTerminated());
  176. $this->assertSame(Process::STATUS_STARTED, $process->getStatus());
  177. $process->wait();
  178. $this->assertFalse($process->isRunning());
  179. $this->assertTrue($process->isStarted());
  180. $this->assertTrue($process->isTerminated());
  181. $this->assertSame(Process::STATUS_TERMINATED, $process->getStatus());
  182. }
  183. public function testStop()
  184. {
  185. $process = $this->getProcess('php -r "while (true) {}"');
  186. $process->start();
  187. $this->assertTrue($process->isRunning());
  188. $process->stop();
  189. $this->assertFalse($process->isRunning());
  190. }
  191. public function testIsSuccessful()
  192. {
  193. $process = $this->getProcess('php -m');
  194. $process->run();
  195. $this->assertTrue($process->isSuccessful());
  196. }
  197. public function testIsNotSuccessful()
  198. {
  199. $process = $this->getProcess('php -r "while (true) {}"');
  200. $process->start();
  201. $this->assertTrue($process->isRunning());
  202. $process->stop();
  203. $this->assertFalse($process->isSuccessful());
  204. }
  205. public function testProcessIsNotSignaled()
  206. {
  207. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  208. $this->markTestSkipped('Windows does not support POSIX signals');
  209. }
  210. $process = $this->getProcess('php -m');
  211. $process->run();
  212. $this->assertFalse($process->hasBeenSignaled());
  213. }
  214. public function testProcessWithoutTermSignal()
  215. {
  216. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  217. $this->markTestSkipped('Windows does not support POSIX signals');
  218. }
  219. $process = $this->getProcess('php -m');
  220. $process->run();
  221. $this->assertEquals(0, $process->getTermSignal());
  222. }
  223. public function testProcessIsSignaledIfStopped()
  224. {
  225. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  226. $this->markTestSkipped('Windows does not support POSIX signals');
  227. }
  228. $process = $this->getProcess('php -r "while (true) {}"');
  229. $process->start();
  230. $process->stop();
  231. $this->assertTrue($process->hasBeenSignaled());
  232. }
  233. public function testProcessWithTermSignal()
  234. {
  235. if (defined('PHP_WINDOWS_VERSION_BUILD')) {
  236. $this->markTestSkipped('Windows does not support POSIX signals');
  237. }
  238. $process = $this->getProcess('php -r "while (true) {}"');
  239. $process->start();
  240. $process->stop();
  241. $this->assertEquals(SIGTERM, $process->getTermSignal());
  242. }
  243. public function testRestart()
  244. {
  245. $process1 = $this->getProcess('php -r "echo getmypid();"');
  246. $process1->run();
  247. $process2 = $process1->restart();
  248. usleep(300000); // wait for output
  249. // Ensure that both processed finished and the output is numeric
  250. $this->assertFalse($process1->isRunning());
  251. $this->assertFalse($process2->isRunning());
  252. $this->assertTrue(is_numeric($process1->getOutput()));
  253. $this->assertTrue(is_numeric($process2->getOutput()));
  254. // Ensure that restart returned a new process by check that the output is different
  255. $this->assertNotEquals($process1->getOutput(), $process2->getOutput());
  256. }
  257. public function testPhpDeadlock()
  258. {
  259. $this->markTestSkipped('Can course php to hang');
  260. // Sleep doesn't work as it will allow the process to handle signals and close
  261. // file handles from the other end.
  262. $process = $this->getProcess('php -r "while (true) {}"');
  263. $process->start();
  264. // PHP will deadlock when it tries to cleanup $process
  265. }
  266. public function responsesCodeProvider()
  267. {
  268. return array(
  269. //expected output / getter / code to execute
  270. //array(1,'getExitCode','exit(1);'),
  271. //array(true,'isSuccessful','exit();'),
  272. array('output', 'getOutput', 'echo \'output\';'),
  273. );
  274. }
  275. public function pipesCodeProvider()
  276. {
  277. $variations = array(
  278. 'fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);',
  279. 'include \'' . __DIR__ . '/ProcessTestHelper.php\';',
  280. );
  281. $baseData = str_repeat('*', 1024);
  282. $codes = array();
  283. foreach (array(1, 16, 64, 1024, 4096) as $size) {
  284. $data = str_repeat($baseData, $size) . '!';
  285. foreach ($variations as $code) {
  286. $codes[] = array($data, $code);
  287. }
  288. }
  289. return $codes;
  290. }
  291. /**
  292. * provides default method names for simple getter/setter
  293. */
  294. public function methodProvider()
  295. {
  296. $defaults = array(
  297. array('CommandLine'),
  298. array('Timeout'),
  299. array('WorkingDirectory'),
  300. array('Env'),
  301. array('Stdin'),
  302. array('Options')
  303. );
  304. return $defaults;
  305. }
  306. }