Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHPUnit process is blocked when there's a lot of output and a test with RunInSeparateProcess #5993

Open
MauricioFauth opened this issue Oct 16, 2024 · 3 comments
Labels
type/bug Something is broken

Comments

@MauricioFauth
Copy link
Contributor

MauricioFauth commented Oct 16, 2024

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" ] }
@MauricioFauth MauricioFauth added the type/bug Something is broken label Oct 16, 2024
@staabm
Copy link
Contributor

staabm commented Oct 17, 2024

great report.

adding back async streams would also help in not blocking the phpunit main process while workers do their thing

@staabm
Copy link
Contributor

staabm commented Oct 19, 2024

I can reproduce in PHPUnit 11.5.x using

IssueTest5993.php

--TEST--
PHPUnit process is blocked when there's a lot of output and a test with separate process
--INI--
error_reporting=-1
display_errors=1
display_startup_errors=1
memory_limit=-1
zend.assertions=1
assert.exception=1
--SKIPIF--
<?php
for ($i = 0; $i < 390; $i++) {
    trigger_error("error $i");
}
?>
--FILE--
<?php

use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use PHPUnit\Framework\TestCase;

final class IssueTest5993 extends TestCase
{
    #[RunInSeparateProcess]
    public function testOne(): void
    {
        $this->assertTrue(true);
    }
}

using one less trigger_error it does not reproduce for me

for ($i = 0; $i < 389; $i++) {
    trigger_error("error $i");
}

when dropping the #[RunInSeparateProcess] attribute it also no longer reproduces

@staabm
Copy link
Contributor

staabm commented Nov 5, 2024

Note to self: maybe our problem is similar to https://github.com/php/php-src/pull/16456/files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/bug Something is broken
Projects
None yet
Development

No branches or pull requests

3 participants
@staabm @MauricioFauth and others