| 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]);
|
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):
|
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=1
composer.json:
"autoload-dev": { "files": [ "file_that_trigger_errors.php" ] }
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:
phpunit/src/Util/PHP/DefaultPhpProcess.php
Lines 115 to 125 in 0c843b0
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
How to reproduce
IssueTest.php:file_that_trigger_errors.php:php.ini:composer.json: