-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Open
Labels
type/bugSomething is brokenSomething is broken
Description
| Q | A |
|---|---|
| PHPUnit version | 10.5.36 |
| PHP version | 8.3.12 |
| Installation Method | Composer |
| OS | Debian testing with deb.sury.org repository |
Summary
When there's a lot of errors triggered before running PHPUnit, for example when a installed package triggers a lot of deprecation messages when being auto loaded, and there's a test that runs in a separate process, PHPUnit will hang indefinitely.
Current behavior
The process blocks here when reading stdout:
$stdout = stream_get_contents($pipes[1]);phpunit/src/Util/PHP/DefaultPhpProcess.php
Lines 115 to 125 in 0c843b0
| if (isset($pipes[1])) { | |
| $stdout = stream_get_contents($pipes[1]); | |
| fclose($pipes[1]); | |
| } | |
| if (isset($pipes[2])) { | |
| $stderr = stream_get_contents($pipes[2]); | |
| fclose($pipes[2]); | |
| } |
Replacing both stream_get_contents calls (stdout and stderr) with this old code (without the timeout check) fixed the issue (removed by ccb3b24):
phpunit/src/Util/PHP/DefaultPhpProcess.php
Lines 125 to 182 in dc7281e
| unset($pipes[0]); | |
| while (true) { | |
| $r = $pipes; | |
| $w = null; | |
| $e = null; | |
| $n = @stream_select($r, $w, $e, $this->timeout); | |
| if ($n === false) { | |
| break; | |
| } | |
| if ($n === 0) { | |
| proc_terminate($process, 9); | |
| throw new PhpProcessException( | |
| sprintf( | |
| 'Job execution aborted after %d seconds', | |
| $this->timeout, | |
| ), | |
| ); | |
| } | |
| if ($n > 0) { | |
| foreach ($r as $pipe) { | |
| $pipeOffset = 0; | |
| foreach ($pipes as $i => $origPipe) { | |
| if ($pipe === $origPipe) { | |
| $pipeOffset = $i; | |
| break; | |
| } | |
| } | |
| if (!$pipeOffset) { | |
| break; | |
| } | |
| $line = fread($pipe, 8192); | |
| if ($line === '' || $line === false) { | |
| fclose($pipes[$pipeOffset]); | |
| unset($pipes[$pipeOffset]); | |
| } elseif ($pipeOffset === 1) { | |
| $stdout .= $line; | |
| } else { | |
| $stderr .= $line; | |
| } | |
| } | |
| if (empty($pipes)) { | |
| break; | |
| } | |
| } | |
| } |
How to reproduce
IssueTest.php:
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use PHPUnit\Framework\TestCase;
final class IssueTest extends TestCase
{
#[RunInSeparateProcess]
public function testOne(): void
{
$this->assertTrue(true);
}
}file_that_trigger_errors.php:
<?php
trigger_error("error 1");
trigger_error("error 2");
trigger_error("error 3");
// ...
trigger_error("error 9997");
trigger_error("error 9998");
trigger_error("error 9999");php.ini:
error_reporting=-1
display_errors=1
display_startup_errors=1
memory_limit=-1
zend.assertions=1
assert.exception=1composer.json:
"autoload-dev": { "files": [ "file_that_trigger_errors.php" ] }Metadata
Metadata
Assignees
Labels
type/bugSomething is brokenSomething is broken