Skip to content

Commit

Permalink
cs
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm committed Mar 17, 2024
1 parent 3cc5b46 commit f353d0b
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 56 deletions.
12 changes: 3 additions & 9 deletions src/Framework/TestRunner.php
Expand Up @@ -9,8 +9,6 @@
*/
namespace PHPUnit\Framework;

use PHPUnit\TestRunner\TestResult\PassedTests;
use PHPUnit\Util\PHP\PcntlFork;
use const PHP_EOL;
use function assert;
use function class_exists;
Expand All @@ -35,6 +33,7 @@
use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry;
use PHPUnit\Util\GlobalState;
use PHPUnit\Util\PHP\AbstractPhpProcess;
use PHPUnit\Util\PHP\PcntlFork;
use ReflectionClass;
use SebastianBergmann\CodeCoverage\Exception as OriginalCodeCoverageException;
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
Expand Down Expand Up @@ -255,17 +254,12 @@ public function runInSeparateProcess(TestCase $test, bool $runEntireClass, bool
if (PcntlFork::isPcntlForkAvailable()) {
// forking the parent process is a more lightweight way to run a test in isolation.
// it requires the pcntl extension though.
$fork = new PcntlFork();
$fork = new PcntlFork;
$fork->runTest($test);

Check warning on line 258 in src/Framework/TestRunner.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestRunner.php#L257-L258

Added lines #L257 - L258 were not covered by tests

return;

Check warning on line 260 in src/Framework/TestRunner.php

View check run for this annotation

Codecov / codecov/patch

src/Framework/TestRunner.php#L260

Added line #L260 was not covered by tests
}

// running in a separate process is slow, but works in most situations.
$this->runInWorkerProcess($test, $runEntireClass, $preserveGlobalState);
}

private function runInWorkerProcess(TestCase $test, bool $runEntireClass, bool $preserveGlobalState): void
{
$class = new ReflectionClass($test);

if ($runEntireClass) {
Expand Down
123 changes: 76 additions & 47 deletions src/Util/PHP/PcntlFork.php
Expand Up @@ -9,35 +9,62 @@
*/
namespace PHPUnit\Util\PHP;

use function array_key_exists;
use function array_values;
use function function_exists;
use function hrtime;
use function ini_get;
use function is_array;
use function pack;
use function pcntl_fork;
use function serialize;
use function socket_close;
use function socket_create_pair;
use function socket_last_error;
use function socket_read;
use function socket_strerror;
use function socket_write;
use function str_contains;
use function strlen;
use function strtoupper;
use function substr;
use function unpack;
use function unserialize;
use Exception;
use PHPUnit\Event\Facade;
use PHPUnit\Event\Telemetry\HRTime;
use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\CodeCoverage;
use PHPUnit\TestRunner\TestResult\PassedTests;
use RuntimeException;

final class PcntlFork {
final class PcntlFork
{
// IPC inspired from https://github.com/barracudanetworks/forkdaemon-php
private const SOCKET_HEADER_SIZE = 4;

static public function isPcntlForkAvailable(): bool {
public static function isPcntlForkAvailable(): bool
{
$disabledFunctions = ini_get('disable_functions');

return
function_exists('pcntl_fork')
&& !str_contains($disabledFunctions, 'pcntl')
&& function_exists('socket_create_pair')
&& !str_contains($disabledFunctions, 'socket')
;
function_exists('pcntl_fork') &&
!str_contains($disabledFunctions, 'pcntl') &&
function_exists('socket_create_pair') &&
!str_contains($disabledFunctions, 'socket');
}

public function runTest(TestCase $test): void

Check warning on line 57 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L57

Added line #L57 was not covered by tests
{
list($socket_child, $socket_parent) = $this->ipcInit();
[$socket_child, $socket_parent] = $this->ipcInit();

Check warning on line 59 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L59

Added line #L59 was not covered by tests

$pid = pcntl_fork();

Check warning on line 61 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L61

Added line #L61 was not covered by tests

if ($pid === -1 ) {
throw new \Exception('could not fork');
} else if ($pid) {
if ($pid === -1) {
throw new Exception('could not fork');

Check failure on line 64 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:64:13: MissingThrowsDocblock: Exception is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)

Check warning on line 64 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L63-L64

Added lines #L63 - L64 were not covered by tests
}

if ($pid) {

Check warning on line 67 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L67

Added line #L67 was not covered by tests
// we are the parent

socket_close($socket_parent);

Check warning on line 70 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L70

Added line #L70 was not covered by tests
Expand All @@ -47,6 +74,7 @@ public function runTest(TestCase $test): void

$stderr = '';
$stdout = '';

Check warning on line 76 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L75-L76

Added lines #L75 - L76 were not covered by tests

if (is_array($result) && array_key_exists('error', $result)) {
$stderr = $result['error'];

Check warning on line 79 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L78-L79

Added lines #L78 - L79 were not covered by tests
} else {
Expand All @@ -61,19 +89,21 @@ public function runTest(TestCase $test): void

socket_close($socket_child);

Check warning on line 90 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L90

Added line #L90 was not covered by tests

$offset = hrtime();
$offset = hrtime();
$dispatcher = Facade::instance()->initForIsolation(
\PHPUnit\Event\Telemetry\HRTime::fromSecondsAndNanoseconds(
HRTime::fromSecondsAndNanoseconds(

Check failure on line 94 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:94:17: MissingThrowsDocblock: PHPUnit\Event\InvalidArgumentException is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)
$offset[0],
$offset[1]
)
$offset[1],
),

Check warning on line 97 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L92-L97

Added lines #L92 - L97 were not covered by tests
);

$test->setInIsolation(true);

Check warning on line 100 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L100

Added line #L100 was not covered by tests

try {
$test->run();

Check failure on line 103 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:103:24: MissingThrowsDocblock: PHPUnit\Runner\Exception is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)

Check failure on line 103 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:103:24: MissingThrowsDocblock: PHPUnit\Framework\Exception is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)

Check failure on line 103 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:103:24: MissingThrowsDocblock: PHPUnit\Event\NoPreviousThrowableException is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)

Check failure on line 103 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:103:24: MissingThrowsDocblock: PHPUnit\Util\Exception is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)

Check failure on line 103 in src/Util/PHP/PcntlFork.php

View workflow job for this annotation

GitHub Actions / Type Checker

MissingThrowsDocblock

src/Util/PHP/PcntlFork.php:103:24: MissingThrowsDocblock: SebastianBergmann\CodeCoverage\InvalidArgumentException is thrown but not caught - please either catch or add a @throws annotation (see https://psalm.dev/169)
} catch (Throwable $e) {
$this->socketSend($socket_parent, ['error' => $e->getMessage()]);

Check warning on line 105 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L103-L105

Added lines #L103 - L105 were not covered by tests

exit();

Check warning on line 107 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L107

Added line #L107 was not covered by tests
}

Expand All @@ -84,12 +114,13 @@ public function runTest(TestCase $test): void
'numAssertions' => $test->numberOfAssertionsPerformed(),
'output' => !$test->expectsOutput() ? $test->output() : '',
'events' => $dispatcher->flush(),
'passedTests' => PassedTests::instance()
]
'passedTests' => PassedTests::instance(),
],

Check warning on line 118 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L112-L118

Added lines #L112 - L118 were not covered by tests
);

// send result into parent
$this->socketSend($socket_parent, $result);

Check warning on line 122 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L122

Added line #L122 was not covered by tests

exit();

Check warning on line 124 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L124

Added line #L124 was not covered by tests
}
}
Expand All @@ -100,10 +131,10 @@ private function ipcInit(): array
$domain = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' ? AF_INET : AF_UNIX;

Check warning on line 131 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L131

Added line #L131 was not covered by tests

// create a socket pair for IPC
$sockets = array();
if (socket_create_pair($domain, SOCK_STREAM, 0, $sockets) === false)
{
throw new \RuntimeException('socket_create_pair failed: ' . socket_strerror(socket_last_error()));
$sockets = [];

Check warning on line 134 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L134

Added line #L134 was not covered by tests

if (socket_create_pair($domain, SOCK_STREAM, 0, $sockets) === false) {
throw new RuntimeException('socket_create_pair failed: ' . socket_strerror(socket_last_error()));

Check warning on line 137 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L136-L137

Added lines #L136 - L137 were not covered by tests
}

return $sockets;

Check warning on line 140 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L140

Added line #L140 was not covered by tests
Expand All @@ -116,32 +147,30 @@ private function socketReceive($socket): mixed
{
// initially read to the length of the header size, then
// expand to read more
$bytes_total = self::SOCKET_HEADER_SIZE;
$bytes_read = 0;
$have_header = false;
$bytes_total = self::SOCKET_HEADER_SIZE;
$bytes_read = 0;
$have_header = false;
$socket_message = '';

Check warning on line 153 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L150-L153

Added lines #L150 - L153 were not covered by tests
while ($bytes_read < $bytes_total)
{

while ($bytes_read < $bytes_total) {
$read = @socket_read($socket, $bytes_total - $bytes_read);

Check warning on line 156 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L155-L156

Added lines #L155 - L156 were not covered by tests
if ($read === false)
{
throw new \RuntimeException('socket_receive error: ' . socket_strerror(socket_last_error()));

if ($read === false) {
throw new RuntimeException('socket_receive error: ' . socket_strerror(socket_last_error()));

Check warning on line 159 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L158-L159

Added lines #L158 - L159 were not covered by tests
}

// blank socket_read means done
if ($read == '')
{
if ($read == '') {
break;

Check warning on line 164 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L163-L164

Added lines #L163 - L164 were not covered by tests
}

$bytes_read += strlen($read);
$socket_message .= $read;

Check warning on line 168 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L167-L168

Added lines #L167 - L168 were not covered by tests

if (!$have_header && $bytes_read >= self::SOCKET_HEADER_SIZE)
{
$have_header = true;
list($bytes_total) = array_values(unpack('N', $socket_message));
$bytes_read = 0;
if (!$have_header && $bytes_read >= self::SOCKET_HEADER_SIZE) {
$have_header = true;
[$bytes_total] = array_values(unpack('N', $socket_message));
$bytes_read = 0;
$socket_message = '';

Check warning on line 174 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L170-L174

Added lines #L170 - L174 were not covered by tests
}
}
Expand All @@ -151,25 +180,25 @@ private function socketReceive($socket): mixed

/**
* @param resource $socket
* @param mixed $message
* @param mixed $message
*/
private function socketSend($socket, $message): void

Check warning on line 185 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L185

Added line #L185 was not covered by tests
{
$serialized_message = @serialize($message);

Check warning on line 187 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L187

Added line #L187 was not covered by tests
if ($serialized_message == false)
{
throw new \RuntimeException('socket_send failed to serialize message');

if ($serialized_message == false) {
throw new RuntimeException('socket_send failed to serialize message');

Check warning on line 190 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L189-L190

Added lines #L189 - L190 were not covered by tests
}

$header = pack('N', strlen($serialized_message));
$data = $header . $serialized_message;
$header = pack('N', strlen($serialized_message));
$data = $header . $serialized_message;
$bytes_left = strlen($data);

Check warning on line 195 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L193-L195

Added lines #L193 - L195 were not covered by tests
while ($bytes_left > 0)
{

while ($bytes_left > 0) {
$bytes_sent = @socket_write($socket, $data);

Check warning on line 198 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L197-L198

Added lines #L197 - L198 were not covered by tests
if ($bytes_sent === false)
{
throw new \RuntimeException('socket_send failed to write to socket');

if ($bytes_sent === false) {
throw new RuntimeException('socket_send failed to write to socket');

Check warning on line 201 in src/Util/PHP/PcntlFork.php

View check run for this annotation

Codecov / codecov/patch

src/Util/PHP/PcntlFork.php#L200-L201

Added lines #L200 - L201 were not covered by tests
}

$bytes_left -= $bytes_sent;
Expand Down

0 comments on commit f353d0b

Please sign in to comment.