From 65a3ba5beca6b476ffc7f0d13dd5ae33580b7b7f Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sat, 16 Sep 2023 14:12:23 +0200 Subject: [PATCH 1/6] Remove skip condition as neither HHVM nor PHPDBG are supported --- tests/end-to-end/regression/1348.phpt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/end-to-end/regression/1348.phpt b/tests/end-to-end/regression/1348.phpt index a00913c768f..205dfe4364e 100644 --- a/tests/end-to-end/regression/1348.phpt +++ b/tests/end-to-end/regression/1348.phpt @@ -2,11 +2,6 @@ https://github.com/sebastianbergmann/phpunit/issues/1348 --XFAIL-- https://github.com/sebastianbergmann/phpunit/issues/5356 ---SKIPIF-- - Date: Sat, 16 Sep 2023 14:25:40 +0200 Subject: [PATCH 2/6] Fix CS/WS issue --- src/Util/PHP/Template/TestCaseClass.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Util/PHP/Template/TestCaseClass.tpl b/src/Util/PHP/Template/TestCaseClass.tpl index 5d2ea0252a5..d352646783d 100644 --- a/src/Util/PHP/Template/TestCaseClass.tpl +++ b/src/Util/PHP/Template/TestCaseClass.tpl @@ -49,7 +49,7 @@ function __phpunit_run_isolated_test() $test = new {className}('{name}', unserialize('{data}'), '{dataName}'); $test->setDependencyInput(unserialize('{dependencyInput}')); - $test->setInIsolation(TRUE); + $test->setInIsolation(true); ob_end_clean(); $test->run($result); From e64a9dd686dc12d7befc8bbc9bb7abeb9fe2ca48 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sat, 16 Sep 2023 14:25:57 +0200 Subject: [PATCH 3/6] Fix CS/WS issues --- src/Util/PHP/Template/TestCaseClass.tpl | 1 + src/Util/PHP/Template/TestCaseMethod.tpl | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Util/PHP/Template/TestCaseClass.tpl b/src/Util/PHP/Template/TestCaseClass.tpl index d352646783d..bfcaed7fdcf 100644 --- a/src/Util/PHP/Template/TestCaseClass.tpl +++ b/src/Util/PHP/Template/TestCaseClass.tpl @@ -59,6 +59,7 @@ function __phpunit_run_isolated_test() } ini_set('xdebug.scream', '0'); + @rewind(STDOUT); /* @ as not every STDOUT target stream is rewindable */ if ($stdout = @stream_get_contents(STDOUT)) { $output = $stdout . $output; diff --git a/src/Util/PHP/Template/TestCaseMethod.tpl b/src/Util/PHP/Template/TestCaseMethod.tpl index 9dd6c92034e..94545ff8705 100644 --- a/src/Util/PHP/Template/TestCaseMethod.tpl +++ b/src/Util/PHP/Template/TestCaseMethod.tpl @@ -62,6 +62,7 @@ function __phpunit_run_isolated_test() } ini_set('xdebug.scream', '0'); + @rewind(STDOUT); /* @ as not every STDOUT target stream is rewindable */ if ($stdout = @stream_get_contents(STDOUT)) { $output = $stdout . $output; From 2ce78bb5e848496bd34f530a0b4163cba150fa0a Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sat, 16 Sep 2023 14:26:24 +0200 Subject: [PATCH 4/6] Remove superfluous parent method calls --- .../2724/SeparateClassRunMethodInNewProcessTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php b/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php index ef219ecc6af..6627f2eab3e 100644 --- a/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php +++ b/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php @@ -23,8 +23,6 @@ class SeparateClassRunMethodInNewProcessTest extends PHPUnit\Framework\TestCase public static function setUpBeforeClass(): void { - parent::setUpBeforeClass(); - if (\file_exists(self::PROCESS_ID_FILE_PATH)) { static::$masterPid = (int) \file_get_contents(self::PROCESS_ID_FILE_PATH); } @@ -32,8 +30,6 @@ public static function setUpBeforeClass(): void public static function tearDownAfterClass(): void { - parent::tearDownAfterClass(); - if (\file_exists(self::PROCESS_ID_FILE_PATH)) { \unlink(self::PROCESS_ID_FILE_PATH); } From 33bbe51d4af5b4c09b23b49c411ddf5b22742e88 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sat, 16 Sep 2023 15:05:58 +0200 Subject: [PATCH 5/6] Skip test on PHP >= 8.3, see https://github.com/sebastianbergmann/phpunit/issues/5356#issuecomment-1722226459 --- tests/end-to-end/regression/1348.phpt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/end-to-end/regression/1348.phpt b/tests/end-to-end/regression/1348.phpt index 205dfe4364e..977dbb73995 100644 --- a/tests/end-to-end/regression/1348.phpt +++ b/tests/end-to-end/regression/1348.phpt @@ -1,7 +1,10 @@ --TEST-- https://github.com/sebastianbergmann/phpunit/issues/1348 ---XFAIL-- -https://github.com/sebastianbergmann/phpunit/issues/5356 +--SKIPIF-- + Date: Sat, 16 Sep 2023 15:14:09 +0200 Subject: [PATCH 6/6] The child processes used for process isolation now use temporary files to communicate their result to the parent process As of PHP 8.3, specifically as of https://github.com/php/php-src/pull/11169, it is no longer possible to capture direct writes to standard output. Such direct writes to standard output interfere with the previous approach where the child process would print its result to standard output from where the parent process would read it. Co-authored-by: Sebastian Bergmann Co-authored-by: Arne Blankerts --- ChangeLog-8.5.md | 7 +++++++ src/Framework/TestCase.php | 6 +++++- src/Util/PHP/AbstractPhpProcess.php | 16 +++++++++++++--- src/Util/PHP/Template/TestCaseClass.tpl | 17 ++++++++++------- src/Util/PHP/Template/TestCaseMethod.tpl | 17 ++++++++++------- 5 files changed, 45 insertions(+), 18 deletions(-) diff --git a/ChangeLog-8.5.md b/ChangeLog-8.5.md index a65e6a61928..754affa9620 100644 --- a/ChangeLog-8.5.md +++ b/ChangeLog-8.5.md @@ -2,6 +2,12 @@ All notable changes of the PHPUnit 8.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. +## [8.5.34] - 2023-MM-DD + +### Changed + +* The child processes used for process isolation now use temporary files to communicate their result to the parent process + ## [8.5.33] - 2023-02-27 ### Fixed @@ -268,6 +274,7 @@ All notable changes of the PHPUnit 8.5 release series are documented in this fil * [#3967](https://github.com/sebastianbergmann/phpunit/issues/3967): Cannot double interface that extends interface that extends `\Throwable` * [#3968](https://github.com/sebastianbergmann/phpunit/pull/3968): Test class run in a separate PHP process are passing when `exit` called inside +[8.5.34]: https://github.com/sebastianbergmann/phpunit/compare/8.5.33...8.5 [8.5.33]: https://github.com/sebastianbergmann/phpunit/compare/8.5.32...8.5.33 [8.5.32]: https://github.com/sebastianbergmann/phpunit/compare/8.5.31...8.5.32 [8.5.31]: https://github.com/sebastianbergmann/phpunit/compare/8.5.30...8.5.31 diff --git a/src/Framework/TestCase.php b/src/Framework/TestCase.php index 0973056679e..889d8db40fb 100644 --- a/src/Framework/TestCase.php +++ b/src/Framework/TestCase.php @@ -59,6 +59,8 @@ use function strlen; use function strpos; use function substr; +use function sys_get_temp_dir; +use function tempnam; use function trim; use function var_export; use DeepCopy\DeepCopy; @@ -801,6 +803,7 @@ public function run(TestResult $result = null): TestResult $codeCoverageFilter = "'." . $codeCoverageFilter . ".'"; $configurationFilePath = $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] ?? ''; + $processResultFile = tempnam(sys_get_temp_dir(), 'phpunit_'); $var = [ 'composerAutoload' => $composerAutoload, @@ -824,6 +827,7 @@ public function run(TestResult $result = null): TestResult 'codeCoverageFilter' => $codeCoverageFilter, 'configurationFilePath' => $configurationFilePath, 'name' => $this->getName(false), + 'processResultFile' => $processResultFile, ]; if (!$runEntireClass) { @@ -833,7 +837,7 @@ public function run(TestResult $result = null): TestResult $template->setVar($var); $php = AbstractPhpProcess::factory(); - $php->runTestJob($template->render(), $this, $result); + $php->runTestJob($template->render(), $this, $result, $processResultFile); } else { $result->run($this); } diff --git a/src/Util/PHP/AbstractPhpProcess.php b/src/Util/PHP/AbstractPhpProcess.php index 8706ae1a118..fc6bc6f14d2 100644 --- a/src/Util/PHP/AbstractPhpProcess.php +++ b/src/Util/PHP/AbstractPhpProcess.php @@ -15,6 +15,8 @@ use function array_merge; use function assert; use function escapeshellarg; +use function file_exists; +use function file_get_contents; use function ini_get_all; use function restore_error_handler; use function set_error_handler; @@ -24,6 +26,7 @@ use function strrpos; use function substr; use function trim; +use function unlink; use function unserialize; use __PHP_Incomplete_Class; use ErrorException; @@ -174,16 +177,23 @@ public function getTimeout(): int * * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException */ - public function runTestJob(string $job, Test $test, TestResult $result): void + public function runTestJob(string $job, Test $test, TestResult $result, string $processResultFile): void { $result->startTest($test); - $_result = $this->runJob($job); + $processResult = ''; + $_result = $this->runJob($job); + + if (file_exists($processResultFile)) { + $processResult = file_get_contents($processResultFile); + + @unlink($processResultFile); + } $this->processChildResult( $test, $result, - $_result['stdout'], + $processResult, $_result['stderr'] ); } diff --git a/src/Util/PHP/Template/TestCaseClass.tpl b/src/Util/PHP/Template/TestCaseClass.tpl index bfcaed7fdcf..2ec3b9c33cc 100644 --- a/src/Util/PHP/Template/TestCaseClass.tpl +++ b/src/Util/PHP/Template/TestCaseClass.tpl @@ -70,13 +70,16 @@ function __phpunit_run_isolated_test() } } - print serialize( - [ - 'testResult' => $test->getResult(), - 'numAssertions' => $test->getNumAssertions(), - 'result' => $result, - 'output' => $output - ] + file_put_contents( + '{processResultFile}', + serialize( + [ + 'testResult' => $test->getResult(), + 'numAssertions' => $test->getNumAssertions(), + 'result' => $result, + 'output' => $output + ] + ) ); } diff --git a/src/Util/PHP/Template/TestCaseMethod.tpl b/src/Util/PHP/Template/TestCaseMethod.tpl index 94545ff8705..b0a692d941e 100644 --- a/src/Util/PHP/Template/TestCaseMethod.tpl +++ b/src/Util/PHP/Template/TestCaseMethod.tpl @@ -73,13 +73,16 @@ function __phpunit_run_isolated_test() } } - print serialize( - [ - 'testResult' => $test->getResult(), - 'numAssertions' => $test->getNumAssertions(), - 'result' => $result, - 'output' => $output - ] + file_put_contents( + '{processResultFile}', + serialize( + [ + 'testResult' => $test->getResult(), + 'numAssertions' => $test->getNumAssertions(), + 'result' => $result, + 'output' => $output + ] + ) ); }