phpunit
phpunit copied to clipboard
`@runInSeparateProcess` and `@preserveGlobalState disabled` fails with `unserialize()` exception when writing to `php://stdout`
Q | A |
---|---|
PHPUnit version | 8.5.32 |
PHP version | 7.2.34-37+ubuntu22.04.1+deb.sury.org+1 |
Installation Method | Composer |
Summary
When running a test with the annotations @runInSeparateProcess
and @preserveGlobalState disabled
that includes (directly or indirectly) some writing to php://stdout
the test fails with
ErrorException: unserialize(): Error at offset 0 of 5 bytes in /vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php:289
Current behavior
The test fails with the following output:
Runtime: PHP 7.2.34-37+ubuntu22.04.1+deb.sury.org+1
E 1 / 1 (100%)
Time: 8.65 seconds, Memory: 8.00 MB
There was 1 error:
1) cloudbackup\RateLimitTest::testActualError
PHPUnit\Framework\Exception: TEST
Caused by
ErrorException: unserialize(): Error at offset 0 of 5 bytes in /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php:289
Stack trace:
#0 [internal function]: PHPUnit\Util\PHP\AbstractPhpProcess::PHPUnit\Util\PHP\{closure}(8, 'unserialize(): ...', '/mnt/c/dev/clou...', 289, Array)
#1 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php(289): unserialize('TEST\n')
#2 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php(187): PHPUnit\Util\PHP\AbstractPhpProcess->processChildResult(Object(cloudbackup\RateLimitTest), Object(PHPUnit\Framework\TestResult), 'TEST\n', '')
#3 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/Framework/TestCase.php(836): PHPUnit\Util\PHP\AbstractPhpProcess->runTestJob('<?php\nuse PHPUn...', Object(cloudbackup\RateLimitTest), Object(PHPUnit\Framework\TestResult))
#4 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/Framework/TestSuite.php(622): PHPUnit\Framework\TestCase->run(Object(PHPUnit\Framework\TestResult))
#5 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(647): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#6 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/TextUI/Command.php(235): PHPUnit\TextUI\TestRunner->doRun(Object(PHPUnit\Framework\TestSuite), Array, Array, true)
#7 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/src/TextUI/Command.php(194): PHPUnit\TextUI\Command->run(Array, true)
#8 /mnt/c/dev/cloud-backup-for-podio/vendor/phpunit/phpunit/phpunit(98): PHPUnit\TextUI\Command::main()
#9 {main}
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
How to reproduce
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testActualError()
{
if ($fd = fopen('php://stdout', "a")) {
fwrite($fd, "TEST\n");
fclose($fd);
}
$this->assertTrue(true);
}
Expected behavior
The test should not error.
composer info
datadog/php-datadogstatsd 1.3.0 This is an extremely simple PHP datadogstatsd client
doctrine/annotations 1.14.2 Docblock Annotations Parser
doctrine/cache 1.13.0 PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, ...
doctrine/deprecations v1.0.0 A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selec...
doctrine/instantiator 1.5.0 A small, lightweight utility to instantiate objects in PHP without invoking their constructors
doctrine/lexer 2.1.0 PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.
firebase/php-jwt v6.3.2 A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.
flowjs/flow-php-server v1.2.0 PHP library for handling chunk uploads. Works with flow.js html5 file uploads.
goaop/framework 2.3.4 Framework for aspect-oriented programming in PHP.
goaop/parser-reflection 2.1.3 Provides reflection information, based on raw source
google/apiclient v2.13.0 Client library for Google APIs
google/apiclient-services v0.284.0 Client library for Google APIs
google/auth v1.24.0 Google Auth Library for PHP
google/cloud-core v1.48.1 Google Cloud PHP shared dependency, providing functionality useful to all components.
google/cloud-logging v1.24.10 Stackdriver Logging Client for PHP
google/cloud-storage v1.30.1 Cloud Storage Client for PHP
google/common-protos v3.2.0 Google API Common Protos for PHP
google/crc32 v0.1.0 Various CRC32 implementations
google/gax v1.18.2 Google API Core for PHP
google/grpc-gcp v0.2.1 gRPC GCP library for channel management
google/longrunning v0.2.2 Google LongRunning Client for PHP
google/protobuf v3.21.12 proto library for PHP
grpc/grpc 1.42.0 gRPC library for PHP
guzzlehttp/guzzle 6.5.8 Guzzle is a PHP HTTP client library
guzzlehttp/promises 1.5.2 Guzzle promises library
guzzlehttp/psr7 1.9.0 PSR-7 message implementation that also provides common utility methods
jakubledl/dissect v1.0.1 Lexing and parsing in pure PHP
jean85/pretty-package-versions 2.0.5 A library to get pretty versions strings of installed dependencies
mikecao/flight v1.3.9 Flight is a fast, simple, extensible framework for PHP. Flight enables you to quickly and easily build RESTful web applicat...
mongodb/mongodb 1.9.0 MongoDB driver library
monolog/monolog 2.8.0 Sends your logs to files, sockets, inboxes, databases and various web services
myclabs/deep-copy 1.11.0 Create deep copies (clones) of your objects
nikic/php-parser v4.6.0 A PHP parser written in PHP
paragonie/constant_time_encoding v2.6.3 Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)
paragonie/random_compat v9.99.100 PHP 5.x polyfill for random_bytes() and random_int() from PHP 7
phar-io/manifest 2.0.3 Component for reading phar.io manifest information from a PHP Archive (PHAR)
phar-io/version 3.2.1 Library for handling version information and constraints
phpmailer/phpmailer v5.2.28 PHPMailer is a full-featured email creation and transfer class for PHP
phpseclib/phpseclib 3.0.18 PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.
phpstan/phpstan 1.9.14 PHPStan - PHP Static Analysis Tool
phpunit/php-code-coverage 7.0.15 Library that provides collection, processing, and rendering functionality for PHP code coverage information.
phpunit/php-file-iterator 2.0.5 FilterIterator implementation that filters files based on a list of suffixes.
phpunit/php-text-template 1.2.1 Simple template engine.
phpunit/php-timer 2.1.3 Utility class for timing
phpunit/php-token-stream 3.1.3 Wrapper around PHP's tokenizer extension.
phpunit/phpunit 8.5.32 The PHP Unit Testing framework.
sebastian/type 1.1.4 Collection of value objects that represent the types of the PHP type system
sebastian/version 2.0.1 Library that helps with managing the version number of Git-hosted PHP projects
stripe/stripe-php v7.0.2 Stripe PHP Library
symfony/deprecation-contracts v2.5.2 A generic function and convention to trigger deprecation notices
symfony/finder v5.4.19 Finds files and directories via an intuitive fluent interface
symfony/polyfill-intl-idn v1.27.0 Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions
symfony/polyfill-intl-normalizer v1.27.0 Symfony polyfill for intl's Normalizer class and related functions
symfony/polyfill-php72 v1.27.0 Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions
symfony/polyfill-php80 v1.27.0 Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
theseer/tokenizer 1.2.1 A small library for converting tokenized PHP source code into XML and potentially other formats
twig/twig v1.32.0 Twig, the flexible, fast, and secure template language for PHP
php://stdout
does not obey output buffering. Output made in the child process breaks unserialization of child process results in the parent process. We work around this limitation (https://github.com/sebastianbergmann/phpunit/blob/8.5/src/Util/PHP/Template/TestCaseMethod.tpl#L5, https://github.com/sebastianbergmann/phpunit/blob/8.5/src/Util/PHP/Template/TestCaseMethod.tpl#L19, https://github.com/sebastianbergmann/phpunit/blob/8.5/src/Util/PHP/Template/TestCaseMethod.tpl#L65), but this seems to be not enough for your case.
@sebastianbergmann thanks for lookin into this. I probably do not fully understand the technical background.
If this is not feasible to solve, maybe some documentation on https://phpunit.readthedocs.io/en/8.5/annotations.html#runinseparateprocess would help?
During my research I found some issue reports that were inconclusive, but might well be caused by the same problem: #3141, #4443, #1149. My guess is, that this often surfaces only depending on logging configuration and/or error output.
Also fixed by 3291172e198f044a922af8036378719f71267a51, which will soon be released as part of PHPUnit 8.5.34, PHPUnit 9.6.13, and PHPUnit 10.3.5.
Issue5151Test.php
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class Issue5151Test extends TestCase
{
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testActualError()
{
if ($fd = fopen('php://stdout', 'a')) {
fwrite($fd, "test\n");
fclose($fd);
}
$this->assertTrue(true);
}
}
PHPUnit 10.3.4
PHPUnit 10.3.4 by Sebastian Bergmann and contributors.
Runtime: PHP 8.2.10
E 1 / 1 (100%)
Time: 00:00.065, Memory: 8.00 MB
There was 1 error:
1) Issue5151Test::testActualError
PHPUnit\Framework\Exception: test
Caused by
ErrorException: unserialize(): Error at offset 0 of 5 bytes
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
PHPUnit 10.3.5-dev
PHPUnit 10.3.4-14-g6d0cb2dbb2 by Sebastian Bergmann and contributors.
Runtime: PHP 8.2.10
. 1 / 1 (100%)
Time: 00:00.060, Memory: 8.00 MB
OK (1 test, 1 assertion)