-
-
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=1
composer.json
:
"autoload-dev": { "files": [ "file_that_trigger_errors.php" ] }
Metadata
Metadata
Assignees
Labels
type/bugSomething is brokenSomething is broken