From 8c45107856894b43883786275d92963a6b9ff450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Mon, 30 Nov 2015 14:03:45 +0100 Subject: [PATCH 01/12] [FrameworkBundle] [Translation] Fixed translations not written when no translations directory in update command --- .../FrameworkBundle/Command/TranslationUpdateCommand.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 64143f6e21..f8bd0159fc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -188,9 +188,11 @@ EOF } } - if ($bundleTransPath) { - $writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale'))); + if (!$bundleTransPath) { + $bundleTransPath = end($transPaths).'translations'; } + + $writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale'))); } $output->newLine(); From 6e279c5f8acebafa6fd6b1a291705831b4b637cf Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Fri, 4 Dec 2015 02:22:26 +0100 Subject: [PATCH 02/12] [FrameworkBundle] prevent cache:clear creating too long paths --- .../Bundle/FrameworkBundle/Command/CacheClearCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 5deafaf0fb..049179075a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -54,7 +54,9 @@ EOF protected function execute(InputInterface $input, OutputInterface $output) { $realCacheDir = $this->getContainer()->getParameter('kernel.cache_dir'); - $oldCacheDir = $realCacheDir.'_old'; + // the old cache dir name must not be longer than the real one to avoid exceeding + // the maximum length of a directory or file path within it (esp. Windows MAX_PATH) + $oldCacheDir = substr($realCacheDir, 0, -1).('~' === substr($realCacheDir, -1) ? '+' : '~'); $filesystem = $this->getContainer()->get('filesystem'); if (!is_writable($realCacheDir)) { @@ -75,7 +77,7 @@ EOF // the warmup cache dir name must have the same length than the real one // to avoid the many problems in serialized resources files $realCacheDir = realpath($realCacheDir); - $warmupDir = substr($realCacheDir, 0, -1).'_'; + $warmupDir = substr($realCacheDir, 0, -1).('_' === substr($realCacheDir, -1) ? '-' : '_'); if ($filesystem->exists($warmupDir)) { $filesystem->remove($warmupDir); @@ -100,8 +102,6 @@ EOF */ protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = true) { - $this->getContainer()->get('filesystem')->remove($warmupDir); - // create a temporary kernel $realKernel = $this->getContainer()->get('kernel'); $realKernelClass = get_class($realKernel); From 604174c963ff36f3d9680045b8fa43f349dd3732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Tue, 24 Nov 2015 11:52:35 +0000 Subject: [PATCH 03/12] Suggested Process dependency The `server:run` command requires the Process component. --- src/Symfony/Bundle/FrameworkBundle/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 9983848d7b..e68290ec1b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -48,7 +48,8 @@ "symfony/finder": "For using the translation loader and cache warmer", "symfony/form": "For using forms", "symfony/validator": "For using validation", - "symfony/serializer": "For using the serializer service" + "symfony/serializer": "For using the serializer service", + "symfony/process": "For using the server:run command" }, "autoload": { "psr-0": { "Symfony\\Bundle\\FrameworkBundle\\": "" }, From 99d174176afb9538ba921c3c47a3c049da8efc16 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 6 Dec 2015 23:20:00 +0100 Subject: [PATCH 04/12] disable server:run cmd without Process component --- .../Bundle/FrameworkBundle/Command/ServerRunCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php index 78468a5b7e..d417357cf3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php @@ -34,6 +34,10 @@ class ServerRunCommand extends ContainerAwareCommand return false; } + if (!class_exists('Symfony\Component\Process\Process')) { + return false; + } + return parent::isEnabled(); } From d18fb9bbbe2dd2893da4663e8350d8590146071d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Faugeron?= Date: Tue, 24 Nov 2015 11:52:35 +0000 Subject: [PATCH 05/12] Suggested Process dependency The `server:run` command requires the Process component. --- src/Symfony/Bundle/FrameworkBundle/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 29ff39c46f..a8c772ec68 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -54,7 +54,8 @@ "symfony/serializer": "For using the serializer service", "symfony/validator": "For using validation", "symfony/yaml": "For using the debug:config and lint:yaml commands", - "doctrine/cache": "For using alternative cache drivers" + "doctrine/cache": "For using alternative cache drivers", + "symfony/process": "For using the server:run command" }, "autoload": { "psr-4": { "Symfony\\Bundle\\FrameworkBundle\\": "" }, From dd82b6459dd7dd8967c8dfbfb49f67dd0c66a5fd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 6 Dec 2015 23:23:13 +0100 Subject: [PATCH 06/12] list all server command names in suggestion --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index a8c772ec68..90c3619e4d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -55,7 +55,7 @@ "symfony/validator": "For using validation", "symfony/yaml": "For using the debug:config and lint:yaml commands", "doctrine/cache": "For using alternative cache drivers", - "symfony/process": "For using the server:run command" + "symfony/process": "For using the server:run, server:start, server:stop, and server:status commands" }, "autoload": { "psr-4": { "Symfony\\Bundle\\FrameworkBundle\\": "" }, From 972c4caae856cb1d437e335f00463d3560599de6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 6 Dec 2015 23:25:30 +0100 Subject: [PATCH 07/12] disable server commands without Process component --- .../Bundle/FrameworkBundle/Command/ServerCommand.php | 4 ++++ .../FrameworkBundle/Command/ServerRunCommand.php | 12 ------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php index b979a19f0f..acf71c6666 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php @@ -27,6 +27,10 @@ abstract class ServerCommand extends ContainerAwareCommand return false; } + if (!class_exists('Symfony\Component\Process\Process')) { + return false; + } + return parent::isEnabled(); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php index 6af52feaae..78b0bd4ee2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerRunCommand.php @@ -25,18 +25,6 @@ use Symfony\Component\Process\ProcessBuilder; */ class ServerRunCommand extends ServerCommand { - /** - * {@inheritdoc} - */ - public function isEnabled() - { - if (PHP_VERSION_ID < 50400 || defined('HHVM_VERSION')) { - return false; - } - - return parent::isEnabled(); - } - /** * {@inheritdoc} */ From f9a811b4de3f278d42f76c0cb99e88f169fd69b5 Mon Sep 17 00:00:00 2001 From: Michel Weimerskirch Date: Sat, 5 Dec 2015 10:34:52 +0100 Subject: [PATCH 08/12] [Validator] Updated Luxembourgish translations for 2.8 | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes Conflicts: src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf --- .../Resources/translations/validators.lb.xlf | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf index 2138ea9c01..6b518a2810 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf @@ -24,11 +24,11 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Dir sollt mindestens {{ limit }} Méiglechkeete wielen. + Et muss mindestens {{ limit }} Méiglechkeet ausgewielt ginn.|Et musse mindestens {{ limit }} Méiglechkeeten ausgewielt ginn. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Dir sollt héchstens {{ limit }} Méiglechkeete wielen. + Et dierf héchstens {{ limit }} Méiglechkeet ausgewielt ginn.|Et dierfen héchstens {{ limit }} Méiglechkeeten ausgewielt ginn. One or more of the given values is invalid. @@ -278,6 +278,22 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Dëse Wäert sollt net identesch si mat {{ compared_value_type }} {{ compared_value }}. + + An empty file is not allowed. + En eidele Fichier ass net erlaabt. + + + The host could not be resolved. + Den Domain-Numm konnt net opgeléist ginn. + + + This value does not match the expected {{ charset }} charset. + Dëse Wäert entsprécht net dem erwaarten Zeechesaz {{ charset }}. + + + This is not a valid Business Identifier Code (BIC). + Dëst ass kee gëltege "Business Identifier Code" (BIC). + From ccb67d7bd22845a25a7cc85de37aeb4582466b2c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 7 Dec 2015 10:45:14 +0100 Subject: [PATCH 09/12] [Process] Always call proc_close --- src/Symfony/Component/Process/Process.php | 11 +---------- .../Component/Process/Tests/AbstractProcessTest.php | 11 ++++------- .../Process/Tests/SigchildDisabledProcessTest.php | 6 +----- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 9aeb8f91e8..2b7da31d2f 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -157,16 +157,7 @@ class Process public function __destruct() { - if ($this->isRunning()) { - $this->doSignal(15, false); - usleep(10000); - } - if ($this->isRunning()) { - usleep(100000); - $this->doSignal(9, false); - } - - // Don't call ->stop() nor ->close() since we don't want to wait for the subprocess here + $this->stop(0); } public function __clone() diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php index 2777411da5..ef1c28eef0 100644 --- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php +++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php @@ -709,26 +709,23 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase */ public function testCheckTimeoutOnStartedProcess() { - $timeout = 0.5; - $precision = 100000; $process = $this->getProcess(self::$phpBin.' -r "sleep(3);"'); - $process->setTimeout($timeout); - $start = microtime(true); + $process->setTimeout(0.5); $process->start(); + $start = microtime(true); try { while ($process->isRunning()) { $process->checkTimeout(); - usleep($precision); + usleep(100000); } $this->fail('A RuntimeException should have been raised'); } catch (RuntimeException $e) { } $duration = microtime(true) - $start; - $this->assertLessThan($timeout + $precision, $duration); - $this->assertFalse($process->isSuccessful()); + $this->assertLessThan(1, $duration); throw $e; } diff --git a/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php b/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php index f0adb1faa4..7e41b83529 100644 --- a/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php +++ b/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php @@ -85,13 +85,9 @@ class SigchildDisabledProcessTest extends AbstractProcessTest parent::testProcessWithoutTermSignal(); } - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ public function testCheckTimeoutOnStartedProcess() { - parent::testCheckTimeoutOnStartedProcess(); + $this->markTestSkipped('Stopping with signal is not supported in sigchild environment'); } /** From 6110bd9c6026e4fdc3455921d299c686b7b7a80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Simon=20Maria=20Mo=CC=88llers?= Date: Tue, 3 Nov 2015 21:41:27 +0100 Subject: [PATCH 10/12] [Serializer] Fixed on array of objects in . --- .../Mapping/ClassMetadataInterface.php | 4 +- .../Normalizer/AbstractNormalizer.php | 2 +- .../Fixtures/AbstractNormalizerDummy.php | 60 ++++++++++++ .../Normalizer/AbstractNormalizerTest.php | 91 +++++++++++++++++++ 4 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/AbstractNormalizerDummy.php create mode 100644 src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php diff --git a/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php b/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php index c967666bd7..095587d896 100644 --- a/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php +++ b/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php @@ -14,7 +14,9 @@ namespace Symfony\Component\Serializer\Mapping; /** * Stores metadata needed for serializing and deserializing objects of specific class. * - * Primarily, the metadata stores the list of attributes to serialize or deserialize. + * Primarily, the metadata stores the set of attributes to serialize or deserialize. + * + * There may only exist one metadata for each attribute according to its name. * * @author Kévin Dunglas */ diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 55c60c0f95..554f36c585 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -259,7 +259,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N } } - return array_unique($allowedAttributes); + return $allowedAttributes; } /** diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/AbstractNormalizerDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/AbstractNormalizerDummy.php new file mode 100644 index 0000000000..27b2f24f53 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/AbstractNormalizerDummy.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; + +/** + * Provides a dummy Normalizer which extends the AbstractNormalizer. + * + * @author Konstantin S. M. Möllers + */ +class AbstractNormalizerDummy extends AbstractNormalizer +{ + /** + * {@inheritdoc} + */ + public function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false) + { + return parent::getAllowedAttributes($classOrObject, $context, $attributesAsString); + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = null, array $context = array()) + { + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = null, array $context = array()) + { + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return true; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php new file mode 100644 index 0000000000..84b9cb18c3 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -0,0 +1,91 @@ + + */ +class AbstractNormalizerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var AbstractNormalizerDummy + */ + private $normalizer; + + /** + * @var ClassMetadataFactoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $classMetadata; + + protected function setUp() + { + $loader = $this->getMock('Symfony\Component\Serializer\Mapping\Loader\LoaderChain', [], [[]]); + $this->classMetadata = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', [], [$loader]); + $this->normalizer = new AbstractNormalizerDummy($this->classMetadata); + } + + public function testGetAllowedAttributesAsString() + { + $classMetadata = new ClassMetadata('c'); + + $a1 = new AttributeMetadata('a1'); + $classMetadata->addAttributeMetadata($a1); + + $a2 = new AttributeMetadata('a2'); + $a2->addGroup('test'); + $classMetadata->addAttributeMetadata($a2); + + $a3 = new AttributeMetadata('a3'); + $a3->addGroup('other'); + $classMetadata->addAttributeMetadata($a3); + + $a4 = new AttributeMetadata('a4'); + $a4->addGroup('test'); + $a4->addGroup('other'); + $classMetadata->addAttributeMetadata($a4); + + $this->classMetadata->method('getMetadataFor')->willReturn($classMetadata); + + $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['test']], true); + $this->assertEquals(['a2', 'a4'], $result); + + $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['other']], true); + $this->assertEquals(['a3', 'a4'], $result); + } + + public function testGetAllowedAttributesAsObjects() + { + $classMetadata = new ClassMetadata('c'); + + $a1 = new AttributeMetadata('a1'); + $classMetadata->addAttributeMetadata($a1); + + $a2 = new AttributeMetadata('a2'); + $a2->addGroup('test'); + $classMetadata->addAttributeMetadata($a2); + + $a3 = new AttributeMetadata('a3'); + $a3->addGroup('other'); + $classMetadata->addAttributeMetadata($a3); + + $a4 = new AttributeMetadata('a4'); + $a4->addGroup('test'); + $a4->addGroup('other'); + $classMetadata->addAttributeMetadata($a4); + + $this->classMetadata->method('getMetadataFor')->willReturn($classMetadata); + + $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['test']], false); + $this->assertEquals([$a2, $a4], $result); + + $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['other']], false); + $this->assertEquals([$a3, $a4], $result); + } +} From 70afcc8023352a8e11e5071e30fba60165652d0f Mon Sep 17 00:00:00 2001 From: Evgeniy Sokolov Date: Wed, 9 Dec 2015 12:45:47 +0100 Subject: [PATCH 11/12] fix short array syntax for php 5.3 --- .../Normalizer/AbstractNormalizerTest.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index 84b9cb18c3..d27c8250aa 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -26,8 +26,8 @@ class AbstractNormalizerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $loader = $this->getMock('Symfony\Component\Serializer\Mapping\Loader\LoaderChain', [], [[]]); - $this->classMetadata = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', [], [$loader]); + $loader = $this->getMock('Symfony\Component\Serializer\Mapping\Loader\LoaderChain', array(), array(array())); + $this->classMetadata = $this->getMock('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', array(), array($loader)); $this->normalizer = new AbstractNormalizerDummy($this->classMetadata); } @@ -53,11 +53,11 @@ class AbstractNormalizerTest extends \PHPUnit_Framework_TestCase $this->classMetadata->method('getMetadataFor')->willReturn($classMetadata); - $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['test']], true); - $this->assertEquals(['a2', 'a4'], $result); + $result = $this->normalizer->getAllowedAttributes('c', array('groups' => array('test')), true); + $this->assertEquals(array('a2', 'a4'), $result); - $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['other']], true); - $this->assertEquals(['a3', 'a4'], $result); + $result = $this->normalizer->getAllowedAttributes('c', array('groups' => array('other')), true); + $this->assertEquals(array('a3', 'a4'), $result); } public function testGetAllowedAttributesAsObjects() @@ -82,10 +82,10 @@ class AbstractNormalizerTest extends \PHPUnit_Framework_TestCase $this->classMetadata->method('getMetadataFor')->willReturn($classMetadata); - $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['test']], false); - $this->assertEquals([$a2, $a4], $result); + $result = $this->normalizer->getAllowedAttributes('c', array('groups' => array('test')), false); + $this->assertEquals(array($a2, $a4), $result); - $result = $this->normalizer->getAllowedAttributes('c', ['groups' => ['other']], false); - $this->assertEquals([$a3, $a4], $result); + $result = $this->normalizer->getAllowedAttributes('c', array('groups' => array('other')), false); + $this->assertEquals(array($a3, $a4), $result); } } From e7cc4aa715175b37c3fb215580f3f392eef97f11 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Dec 2015 17:23:26 +0100 Subject: [PATCH 12/12] [Process] Enhance compatiblity with --enable-sigchild --- .travis.yml | 3 + src/Symfony/Component/Process/Process.php | 118 ++++----- .../Process/Tests/PhpProcessTest.php | 14 +- .../Tests/ProcessInSigchildEnvironment.php | 22 -- ...bstractProcessTest.php => ProcessTest.php} | 140 ++++++++--- .../Tests/SigchildDisabledProcessTest.php | 225 ------------------ .../Tests/SigchildEnabledProcessTest.php | 152 ------------ .../Process/Tests/SimpleProcessTest.php | 216 ----------------- 8 files changed, 184 insertions(+), 706 deletions(-) delete mode 100644 src/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php rename src/Symfony/Component/Process/Tests/{AbstractProcessTest.php => ProcessTest.php} (87%) delete mode 100644 src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php delete mode 100644 src/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php delete mode 100644 src/Symfony/Component/Process/Tests/SimpleProcessTest.php diff --git a/.travis.yml b/.travis.yml index c2933ed76e..00f8bf15ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ addons: cache: directories: - .phpunit + - php-5.3.9 matrix: include: @@ -32,6 +33,7 @@ env: before_install: - if [[ "$deps" = "no" ]] && [[ "$TRAVIS_PHP_VERSION" =~ 5.[45] ]] && [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then export deps=skip; fi; + - if [[ $deps = no && $TRAVIS_PHP_VERSION = 5.3 && ! -d php-5.3.9/sapi ]]; then wget http://museum.php.net/php5/php-5.3.9.tar.bz2; tar -xjf php-5.3.9.tar.bz2; (cd php-5.3.9; ./configure --enable-sigchild --enable-pcntl; make -j2); fi; - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi; - echo "memory_limit = -1" >> $INI_FILE - echo "session.gc_probability = 0" >> $INI_FILE @@ -54,6 +56,7 @@ install: script: - if [ "$deps" = "no" ]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi; - if [ "$deps" = "no" ]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi; + - if [[ $deps = no && $TRAVIS_PHP_VERSION = 5.3 ]]; then echo -e "1\\n0" | parallel --gnu 'echo -e "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-5.3.9/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi; - if [ "$deps" = "high" ]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer --prefer-source update; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi; - if [ "$deps" = "low" ]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi; - if [ "$deps" = "skip" ]; then echo 'This matrix line is skipped for pull requests.'; fi; diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 2b7da31d2f..d2af621d43 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -46,7 +46,7 @@ class Process private $timeout; private $options; private $exitcode; - private $fallbackExitcode; + private $fallbackStatus = array(); private $processInformation; private $stdout; private $stderr; @@ -65,6 +65,14 @@ class Process private $latestSignal; private static $sigchild; + private static $posixSignals = array( + 1 => 1, // SIGHUP + 2 => 2, // SIGINT + 3 => 3, // SIGQUIT + 6 => 6, // SIGABRT + 14 => 14, // SIGALRM + 15 => 15, // SIGTERM + ); /** * Exit codes translation table. @@ -339,17 +347,9 @@ class Process * Returns the Pid (process identifier), if applicable. * * @return int|null The process id if running, null otherwise - * - * @throws RuntimeException In case --enable-sigchild is activated */ public function getPid() { - if ($this->isSigchildEnabled()) { - throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.'); - } - - $this->updateStatus(false); - return $this->isRunning() ? $this->processInformation['pid'] : null; } @@ -361,7 +361,7 @@ class Process * @return Process * * @throws LogicException In case the process is not running - * @throws RuntimeException In case --enable-sigchild is activated + * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed * @throws RuntimeException In case of failure */ public function signal($signal) @@ -467,7 +467,9 @@ class Process */ public function getExitCode() { - if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) { + if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { + $this->stop(0); + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.'); } @@ -484,8 +486,6 @@ class Process * * @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 */ @@ -522,12 +522,12 @@ class Process { $this->requireProcessIsTerminated(__FUNCTION__); - if ($this->isSigchildEnabled()) { + if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { + $this->stop(0); + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.'); } - $this->updateStatus(false); - return $this->processInformation['signaled']; } @@ -545,12 +545,12 @@ class Process { $this->requireProcessIsTerminated(__FUNCTION__); - if ($this->isSigchildEnabled()) { + if ($this->isSigchildEnabled() && (!$this->enhanceSigchildCompatibility || -1 === $this->processInformation['termsig'])) { + $this->stop(0); + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.'); } - $this->updateStatus(false); - return $this->processInformation['termsig']; } @@ -567,8 +567,6 @@ class Process { $this->requireProcessIsTerminated(__FUNCTION__); - $this->updateStatus(false); - return $this->processInformation['stopped']; } @@ -585,8 +583,6 @@ class Process { $this->requireProcessIsTerminated(__FUNCTION__); - $this->updateStatus(false); - return $this->processInformation['stopsig']; } @@ -660,7 +656,7 @@ class Process usleep(1000); } while ($this->isRunning() && microtime(true) < $timeoutMicro); - if ($this->isRunning() && !$this->isSigchildEnabled()) { + if ($this->isRunning()) { // Avoid exception here: process is supposed to be running, but it might have stopped just // after this line. In any case, let's silently discard the error, we cannot do anything. $this->doSignal($signal ?: 9, false); @@ -998,9 +994,15 @@ class Process if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { // last exit code is output on the fourth pipe and caught to work around --enable-sigchild - $descriptors = array_merge($descriptors, array(array('pipe', 'w'))); + $descriptors[3] = array('pipe', 'w'); - $this->commandline = '('.$this->commandline.') 3>/dev/null; code=$?; echo $code >&3; exit $code'; + $trap = ''; + foreach (self::$posixSignals as $s) { + $trap .= "trap 'echo s$s >&3' $s;"; + } + + $this->commandline = $trap.'{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;'; + $this->commandline .= 'pid=$!; echo p$pid >&3; wait $pid; code=$?; echo x$code >&3; exit $code'; } return $descriptors; @@ -1047,10 +1049,13 @@ class Process } $this->processInformation = proc_get_status($this->process); - $this->captureExitCode(); $this->readPipes($blocking, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); + if ($this->fallbackStatus && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { + $this->processInformation = $this->fallbackStatus + $this->processInformation; + } + if (!$this->processInformation['running']) { $this->close(); } @@ -1067,7 +1072,7 @@ class Process return self::$sigchild; } - if (!function_exists('phpinfo')) { + if (!function_exists('phpinfo') || defined('HHVM_VERSION')) { return self::$sigchild = false; } @@ -1093,24 +1098,24 @@ class Process $callback = $this->callback; foreach ($result as $type => $data) { - if (3 == $type) { - $this->fallbackExitcode = (int) $data; + if (3 === $type) { + foreach (explode("\n", substr($data, 0, -1)) as $data) { + if ('p' === $data[0]) { + $this->fallbackStatus['pid'] = (int) substr($data, 1); + } elseif ('s' === $data[0]) { + $this->fallbackStatus['signaled'] = true; + $this->fallbackStatus['exitcode'] = -1; + $this->fallbackStatus['termsig'] = (int) substr($data, 1); + } elseif ('x' === $data[0] && !isset($this->fallbackStatus['signaled'])) { + $this->fallbackStatus['exitcode'] = (int) substr($data, 1); + } + } } else { $callback($type === self::STDOUT ? self::OUT : self::ERR, $data); } } } - /** - * Captures the exitcode if mentioned in the process information. - */ - private function captureExitCode() - { - if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) { - $this->exitcode = $this->processInformation['exitcode']; - } - } - /** * Closes process resource, closes file handles, sets the exitcode. * @@ -1120,19 +1125,19 @@ class Process { $this->processPipes->close(); if (is_resource($this->process)) { - $exitcode = proc_close($this->process); - } else { - $exitcode = -1; + proc_close($this->process); } - - $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1); + $this->exitcode = $this->processInformation['exitcode']; $this->status = self::STATUS_TERMINATED; - if (-1 === $this->exitcode && null !== $this->fallbackExitcode) { - $this->exitcode = $this->fallbackExitcode; - } elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) { - // if process has been signaled, no exitcode but a valid termsig, apply Unix convention - $this->exitcode = 128 + $this->processInformation['termsig']; + if (-1 === $this->exitcode) { + if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) { + // if process has been signaled, no exitcode but a valid termsig, apply Unix convention + $this->exitcode = 128 + $this->processInformation['termsig']; + } elseif ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { + $this->processInformation['signaled'] = true; + $this->processInformation['termsig'] = -1; + } } // Free memory from self-reference callback created by buildCallback @@ -1151,7 +1156,7 @@ class Process $this->starttime = null; $this->callback = null; $this->exitcode = null; - $this->fallbackExitcode = null; + $this->fallbackStatus = array(); $this->processInformation = null; $this->stdout = null; $this->stderr = null; @@ -1171,7 +1176,7 @@ class Process * @return bool True if the signal was sent successfully, false otherwise * * @throws LogicException In case the process is not running - * @throws RuntimeException In case --enable-sigchild is activated + * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed * @throws RuntimeException In case of failure */ private function doSignal($signal, $throwException) @@ -1184,9 +1189,9 @@ class Process return false; } - if ($this->isSigchildEnabled()) { + if ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled() && !isset(self::$posixSignals[$signal]) && !(function_exists('posix_kill') && @posix_kill($this->getPid(), $signal))) { if ($throwException) { - throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); + throw new RuntimeException('This PHP has been compiled with --enable-sigchild and posix_kill() is not available.'); } return false; @@ -1211,7 +1216,10 @@ class Process return false; } - $this->latestSignal = $signal; + $this->latestSignal = (int) $signal; + $this->fallbackStatus['signaled'] = true; + $this->fallbackStatus['exitcode'] = -1; + $this->fallbackStatus['termsig'] = $this->latestSignal; return true; } diff --git a/src/Symfony/Component/Process/Tests/PhpProcessTest.php b/src/Symfony/Component/Process/Tests/PhpProcessTest.php index 2cf79aa1a6..9c0f04d3d2 100644 --- a/src/Symfony/Component/Process/Tests/PhpProcessTest.php +++ b/src/Symfony/Component/Process/Tests/PhpProcessTest.php @@ -30,24 +30,20 @@ PHP public function testCommandLine() { - if ('phpdbg' === PHP_SAPI) { - $this->markTestSkipped('phpdbg SAPI is not supported by this test.'); - } - $process = new PhpProcess(<<find(); + $commandLine = $process->getCommandLine(); - $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP before start'); + $f = new PhpExecutableFinder(); + $this->assertContains($f->find(), $commandLine, '::getCommandLine() returns the command line of PHP before start'); $process->start(); - $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start'); + $this->assertContains($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start'); $process->wait(); - $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait'); + $this->assertContains($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait'); } } diff --git a/src/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php b/src/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php deleted file mode 100644 index 3977bcdcf1..0000000000 --- a/src/Symfony/Component/Process/Tests/ProcessInSigchildEnvironment.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Process\Tests; - -use Symfony\Component\Process\Process; - -class ProcessInSigchildEnvironment extends Process -{ - protected function isSigchildEnabled() - { - return true; - } -} diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php similarity index 87% rename from src/Symfony/Component/Process/Tests/AbstractProcessTest.php rename to src/Symfony/Component/Process/Tests/ProcessTest.php index ef1c28eef0..a49ededd7d 100644 --- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -20,9 +20,10 @@ use Symfony\Component\Process\ProcessPipes; /** * @author Robert Schönthal */ -abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase +class ProcessTest extends \PHPUnit_Framework_TestCase { - protected static $phpBin; + private static $phpBin; + private static $notEnhancedSigchild = false; public static function setUpBeforeClass() { @@ -71,12 +72,11 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $this->assertNull($p->getTimeout()); } + /** + * @requires extension pcntl + */ public function testStopWithTimeoutIsActuallyWorking() { - if (!extension_loaded('pcntl')) { - $this->markTestSkipped('Extension pcntl is required.'); - } - // exec is mandatory here since we send a signal to the process // see https://github.com/symfony/symfony/issues/5030 about prepending // command with exec @@ -124,7 +124,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase { $data = ''; - $process = $this->getProcess('echo foo && php -r "sleep(1);" && echo foo'); + $process = $this->getProcess('echo foo && '.self::$phpBin.' -r "sleep(1);" && echo foo'); $process->start(function ($type, $buffer) use (&$data) { $data .= $buffer; }); @@ -401,6 +401,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does not support POSIX exit code'); } + $this->skipIfNotEnhancedSigchild(); // such command run in bash return an exitcode 127 $process = $this->getProcess('nonexistingcommandIhopeneversomeonewouldnameacommandlikethis'); @@ -429,6 +430,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does have /dev/tty support'); } + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess('echo "foo" >> /dev/null'); $process->setTty(true); @@ -437,6 +439,10 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $this->assertTrue($process->isSuccessful()); } + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + * @expectedExceptionMessage TTY mode is not supported on Windows platform. + */ public function testTTYInWindowsEnvironment() { if ('\\' !== DIRECTORY_SEPARATOR) { @@ -445,18 +451,21 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $process = $this->getProcess('echo "foo" >> /dev/null'); $process->setTty(false); - $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'TTY mode is not supported on Windows platform.'); $process->setTty(true); } public function testExitCodeTextIsNullWhenExitCodeIsNull() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(''); $this->assertNull($process->getExitCodeText()); } public function testExitCodeText() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(''); $r = new \ReflectionObject($process); $p = $r->getProperty('exitcode'); @@ -485,6 +494,8 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testGetExitCodeIsNullOnStart() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(self::$phpBin.' -r "usleep(200000);"'); $this->assertNull($process->getExitCode()); $process->start(); @@ -495,6 +506,8 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testGetExitCodeIsNullOnWhenStartingAgain() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(self::$phpBin.' -r "usleep(200000);"'); $process->run(); $this->assertEquals(0, $process->getExitCode()); @@ -506,6 +519,8 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testGetExitCode() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(self::$phpBin.' -v'); $process->run(); $this->assertSame(0, $process->getExitCode()); @@ -541,6 +556,8 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testIsSuccessful() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(self::$phpBin.' -v'); $process->run(); $this->assertTrue($process->isSuccessful()); @@ -548,6 +565,8 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testIsSuccessfulOnlyAfterTerminated() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(self::$phpBin.' -r "sleep(1);"'); $process->start(); @@ -562,6 +581,8 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testIsNotSuccessful() { + $this->skipIfNotEnhancedSigchild(); + $process = $this->getProcess(self::$phpBin.' -r "usleep(500000);throw new \Exception(\'BOUM\');"'); $process->start(); $this->assertTrue($process->isRunning()); @@ -574,6 +595,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does not support POSIX signals'); } + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess(self::$phpBin.' -v'); $process->run(); @@ -585,6 +607,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does not support POSIX signals'); } + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess(self::$phpBin.' -v'); $process->run(); @@ -596,6 +619,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does not support POSIX signals'); } + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess(self::$phpBin.' -v'); $process->run(); @@ -607,6 +631,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does not support POSIX signals'); } + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess(self::$phpBin.' -r "sleep(4);"'); $process->start(); @@ -619,22 +644,25 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase if ('\\' === DIRECTORY_SEPARATOR) { $this->markTestSkipped('Windows does not support POSIX signals'); } - - // SIGTERM is only defined if pcntl extension is present - $termSignal = defined('SIGTERM') ? SIGTERM : 15; + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess(self::$phpBin.' -r "sleep(4);"'); $process->start(); $process->stop(); - $this->assertEquals($termSignal, $process->getTermSignal()); + $this->assertEquals(15, $process->getTermSignal()); // SIGTERM } + /** + * @expectedException \Symfony\Component\Process\Exception\RuntimeException + * @expectedExceptionMessage The process has been signaled + */ public function testProcessThrowsExceptionWhenExternallySignaled() { if (!function_exists('posix_kill')) { $this->markTestSkipped('Function posix_kill is required.'); } + $this->skipIfNotEnhancedSigchild(false); $termSignal = defined('SIGKILL') ? SIGKILL : 9; @@ -642,7 +670,6 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $process->start(); posix_kill($process->getPid(), $termSignal); - $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'The process has been signaled with signal "9".'); $process->wait(); } @@ -725,7 +752,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase } $duration = microtime(true) - $start; - $this->assertLessThan(1, $duration); + $this->assertLessThan(3, $duration); throw $e; } @@ -771,12 +798,11 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $this->assertNull($process->getPid()); } + /** + * @requires extension pcntl + */ public function testSignal() { - if (!extension_loaded('pcntl')) { - $this->markTestSkipped('Extension pcntl is required.'); - } - $process = $this->getProcess('exec '.self::$phpBin.' '.__DIR__.'/SignalListener.php'); $process->start(); @@ -789,11 +815,12 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $this->assertEquals('Caught SIGUSR1', $process->getOutput()); } + /** + * @requires extension pcntl + */ public function testExitCodeIsAvailableAfterSignal() { - if (!extension_loaded('pcntl')) { - $this->markTestSkipped('Extension pcntl is required.'); - } + $this->skipIfNotEnhancedSigchild(); $process = $this->getProcess('sleep 4'); $process->start(); @@ -811,15 +838,12 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Symfony\Component\Process\Exception\LogicException + * @expectedExceptionMessage Can not send signal on a non running process. */ public function testSignalProcessNotRunning() { - if (!extension_loaded('pcntl')) { - $this->markTestSkipped('Extension pcntl is required.'); - } - $process = $this->getProcess(self::$phpBin.' -v'); - $process->signal(SIGHUP); + $process->signal(1); // SIGHUP } /** @@ -901,6 +925,37 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $process->signal('Céphalopodes'); } + public function testStopTerminatesProcessCleanly() + { + $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); + $process->run(function () use ($process) { + $process->stop(); + }); + $this->assertTrue(true, 'A call to stop() is not expected to cause wait() to throw a RuntimeException'); + } + + public function testKillSignalTerminatesProcessCleanly() + { + $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); + $process->run(function () use ($process) { + if ($process->isRunning()) { + $process->signal(9); // SIGKILL + } + }); + $this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException'); + } + + public function testTermSignalTerminatesProcessCleanly() + { + $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); + $process->run(function () use ($process) { + if ($process->isRunning()) { + $process->signal(15); // SIGTERM + } + }); + $this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException'); + } + public function responsesCodeProvider() { return array( @@ -962,7 +1017,38 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase * * @return Process */ - abstract protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()); + private function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) + { + $process = new Process($commandline, $cwd, $env, $stdin, $timeout, $options); + + if (false !== $enhance = getenv('ENHANCE_SIGCHLD')) { + try { + $process->setEnhanceSigchildCompatibility(false); + $process->getExitCode(); + $this->fail('ENHANCE_SIGCHLD must be used together with a sigchild-enabled PHP.'); + } catch (RuntimeException $e) { + $this->assertSame('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.', $e->getMessage()); + if ($enhance) { + $process->setEnhanceSigChildCompatibility(true); + } else { + self::$notEnhancedSigchild = true; + } + } + } + + return $process; + } + + private function skipIfNotEnhancedSigchild($expectException = true) + { + if (self::$notEnhancedSigchild) { + if ($expectException) { + $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild.'); + } else { + $this->markTestSkipped('PHP is compiled with --enable-sigchild and enhanced mode is disabled.'); + } + } + } } class Stringifiable diff --git a/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php b/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php deleted file mode 100644 index 7e41b83529..0000000000 --- a/src/Symfony/Component/Process/Tests/SigchildDisabledProcessTest.php +++ /dev/null @@ -1,225 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Process\Tests; - -class SigchildDisabledProcessTest extends AbstractProcessTest -{ - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testGetExitCode() - { - parent::testGetExitCode(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testGetExitCodeIsNullOnStart() - { - parent::testGetExitCodeIsNullOnStart(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testGetExitCodeIsNullOnWhenStartingAgain() - { - parent::testGetExitCodeIsNullOnWhenStartingAgain(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testExitCodeCommandFailed() - { - parent::testExitCodeCommandFailed(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessIsSignaledIfStopped() - { - parent::testProcessIsSignaledIfStopped(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessWithTermSignal() - { - parent::testProcessWithTermSignal(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessIsNotSignaled() - { - parent::testProcessIsNotSignaled(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessWithoutTermSignal() - { - parent::testProcessWithoutTermSignal(); - } - - public function testCheckTimeoutOnStartedProcess() - { - $this->markTestSkipped('Stopping with signal is not supported in sigchild environment'); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved. - */ - public function testGetPid() - { - parent::testGetPid(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved. - */ - public function testGetPidIsNullBeforeStart() - { - parent::testGetPidIsNullBeforeStart(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved. - */ - public function testGetPidIsNullAfterRun() - { - parent::testGetPidIsNullAfterRun(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testExitCodeText() - { - $process = $this->getProcess('qdfsmfkqsdfmqmsd'); - $process->run(); - - $process->getExitCodeText(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testExitCodeTextIsNullWhenExitCodeIsNull() - { - parent::testExitCodeTextIsNullWhenExitCodeIsNull(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testIsSuccessful() - { - parent::testIsSuccessful(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testIsSuccessfulOnlyAfterTerminated() - { - parent::testIsSuccessfulOnlyAfterTerminated(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testIsNotSuccessful() - { - parent::testIsNotSuccessful(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method. - */ - public function testTTYCommandExitCode() - { - parent::testTTYCommandExitCode(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process can not be signaled. - */ - public function testSignal() - { - parent::testSignal(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessWithoutTermSignalIsNotSignaled() - { - parent::testProcessWithoutTermSignalIsNotSignaled(); - } - - public function testStopWithTimeoutIsActuallyWorking() - { - $this->markTestSkipped('Stopping with signal is not supported in sigchild environment'); - } - - public function testProcessThrowsExceptionWhenExternallySignaled() - { - $this->markTestSkipped('Retrieving Pid is not supported in sigchild environment'); - } - - public function testExitCodeIsAvailableAfterSignal() - { - $this->markTestSkipped('Signal is not supported in sigchild environment'); - } - - public function testRunProcessWithTimeout() - { - $this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment'); - } - - /** - * {@inheritdoc} - */ - protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) - { - $process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $stdin, $timeout, $options); - $process->setEnhanceSigchildCompatibility(false); - - return $process; - } -} diff --git a/src/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php b/src/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php deleted file mode 100644 index 300560e9b5..0000000000 --- a/src/Symfony/Component/Process/Tests/SigchildEnabledProcessTest.php +++ /dev/null @@ -1,152 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Process\Tests; - -class SigchildEnabledProcessTest extends AbstractProcessTest -{ - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessIsSignaledIfStopped() - { - parent::testProcessIsSignaledIfStopped(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessWithTermSignal() - { - parent::testProcessWithTermSignal(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessIsNotSignaled() - { - parent::testProcessIsNotSignaled(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessWithoutTermSignal() - { - parent::testProcessWithoutTermSignal(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved. - */ - public function testGetPid() - { - parent::testGetPid(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved. - */ - public function testGetPidIsNullBeforeStart() - { - parent::testGetPidIsNullBeforeStart(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved. - */ - public function testGetPidIsNullAfterRun() - { - parent::testGetPidIsNullAfterRun(); - } - - public function testExitCodeText() - { - $process = $this->getProcess('qdfsmfkqsdfmqmsd'); - $process->run(); - - $this->assertInternalType('string', $process->getExitCodeText()); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process can not be signaled. - */ - public function testSignal() - { - parent::testSignal(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved. - */ - public function testProcessWithoutTermSignalIsNotSignaled() - { - parent::testProcessWithoutTermSignalIsNotSignaled(); - } - - public function testProcessThrowsExceptionWhenExternallySignaled() - { - $this->markTestSkipped('Retrieving Pid is not supported in sigchild environment'); - } - - public function testExitCodeIsAvailableAfterSignal() - { - $this->markTestSkipped('Signal is not supported in sigchild environment'); - } - - /** - * @expectedException Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage The process timed-out. - */ - public function testStartAfterATimeout() - { - if ('\\' === DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Restarting a timed-out process on Windows is not supported in sigchild environment'); - } - parent::testStartAfterATimeout(); - } - - public function testStopWithTimeoutIsActuallyWorking() - { - $this->markTestSkipped('Stopping with signal is not supported in sigchild environment'); - } - - public function testRunProcessWithTimeout() - { - $this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment'); - } - - public function testCheckTimeoutOnStartedProcess() - { - $this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment'); - } - - /** - * {@inheritdoc} - */ - protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) - { - $process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $stdin, $timeout, $options); - $process->setEnhanceSigchildCompatibility(true); - - return $process; - } -} diff --git a/src/Symfony/Component/Process/Tests/SimpleProcessTest.php b/src/Symfony/Component/Process/Tests/SimpleProcessTest.php deleted file mode 100644 index 4419581167..0000000000 --- a/src/Symfony/Component/Process/Tests/SimpleProcessTest.php +++ /dev/null @@ -1,216 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Process\Tests; - -use Symfony\Component\Process\Process; - -class SimpleProcessTest extends AbstractProcessTest -{ - private $enabledSigchild = false; - - protected function setUp() - { - ob_start(); - phpinfo(INFO_GENERAL); - - $this->enabledSigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); - } - - public function testGetExitCode() - { - $this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case - parent::testGetExitCode(); - } - - public function testExitCodeCommandFailed() - { - $this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case - parent::testExitCodeCommandFailed(); - } - - public function testProcessIsSignaledIfStopped() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); - parent::testProcessIsSignaledIfStopped(); - } - - public function testProcessWithTermSignal() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); - parent::testProcessWithTermSignal(); - } - - public function testProcessIsNotSignaled() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); - parent::testProcessIsNotSignaled(); - } - - public function testProcessWithoutTermSignal() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); - parent::testProcessWithoutTermSignal(); - } - - public function testExitCodeText() - { - $this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case - parent::testExitCodeText(); - } - - public function testIsSuccessful() - { - $this->skipIfPHPSigchild(); // This test use PID that is not available in this case - parent::testIsSuccessful(); - } - - public function testIsNotSuccessful() - { - $this->skipIfPHPSigchild(); // This test use PID that is not available in this case - parent::testIsNotSuccessful(); - } - - public function testGetPid() - { - $this->skipIfPHPSigchild(); // This test use PID that is not available in this case - parent::testGetPid(); - } - - public function testGetPidIsNullBeforeStart() - { - $this->skipIfPHPSigchild(); // This test use PID that is not available in this case - parent::testGetPidIsNullBeforeStart(); - } - - public function testGetPidIsNullAfterRun() - { - $this->skipIfPHPSigchild(); // This test use PID that is not available in this case - parent::testGetPidIsNullAfterRun(); - } - - public function testSignal() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - parent::testSignal(); - } - - public function testProcessWithoutTermSignalIsNotSignaled() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved'); - parent::testProcessWithoutTermSignalIsNotSignaled(); - } - - public function testProcessThrowsExceptionWhenExternallySignaled() - { - $this->skipIfPHPSigchild(); // This test use PID that is not available in this case - parent::testProcessThrowsExceptionWhenExternallySignaled(); - } - - public function testExitCodeIsAvailableAfterSignal() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - parent::testExitCodeIsAvailableAfterSignal(); - } - - /** - * @expectedException \Symfony\Component\Process\Exception\LogicException - * @expectedExceptionMessage Can not send signal on a non running process. - */ - public function testSignalProcessNotRunning() - { - parent::testSignalProcessNotRunning(); - } - - public function testSignalWithWrongIntSignal() - { - if ($this->enabledSigchild) { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - } else { - $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Error while sending signal `-4`.'); - } - parent::testSignalWithWrongIntSignal(); - } - - public function testSignalWithWrongNonIntSignal() - { - if ($this->enabledSigchild) { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - } else { - $this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Error while sending signal `Céphalopodes`.'); - } - parent::testSignalWithWrongNonIntSignal(); - } - - public function testStopTerminatesProcessCleanly() - { - $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); - $process->run(function () use ($process) { - $process->stop(); - }); - $this->assertTrue(true, 'A call to stop() is not expected to cause wait() to throw a RuntimeException'); - } - - public function testKillSignalTerminatesProcessCleanly() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - - $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); - $process->run(function () use ($process) { - if ($process->isRunning()) { - $process->signal(defined('SIGKILL') ? SIGKILL : 9); - } - }); - $this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException'); - } - - public function testTermSignalTerminatesProcessCleanly() - { - $this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - - $process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"'); - $process->run(function () use ($process) { - if ($process->isRunning()) { - $process->signal(defined('SIGTERM') ? SIGTERM : 15); - } - }); - $this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException'); - } - - public function testStopWithTimeoutIsActuallyWorking() - { - $this->skipIfPHPSigchild(); - - parent::testStopWithTimeoutIsActuallyWorking(); - } - - /** - * {@inheritdoc} - */ - protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()) - { - return new Process($commandline, $cwd, $env, $stdin, $timeout, $options); - } - - private function skipIfPHPSigchild() - { - if ($this->enabledSigchild) { - $this->markTestSkipped('Your PHP has been compiled with --enable-sigchild, this test can not be executed'); - } - } - - private function expectExceptionIfPHPSigchild($classname, $message) - { - if ($this->enabledSigchild) { - $this->setExpectedException($classname, $message); - } - } -}