Skip to content

run-tests: refactor worker globals into global WorkerContext value-object #16678

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

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 66 additions & 39 deletions run-tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,10 @@ function main(): void
$test_files, $test_idx, $test_results, $testfile,
$valgrind, $sum_results, $shuffle, $file_cache, $num_repeats,
$show_progress;
// Parallel testing
global $workers, $workerID;

global $workerContext;
$workerContext = new WorkerContext();

global $context_line_count;

// Temporary for the duration of refactoring
Expand All @@ -166,9 +168,9 @@ function main(): void

define('IS_WINDOWS', substr(PHP_OS, 0, 3) == "WIN");

$workerID = 0;
$workerContext->workerID = 0;
if (getenv("TEST_PHP_WORKER")) {
$workerID = intval(getenv("TEST_PHP_WORKER"));
$workerContext->workerID = intval(getenv("TEST_PHP_WORKER"));
run_worker();
return;
}
Expand Down Expand Up @@ -251,7 +253,7 @@ function main(): void
$DETAILED = 0;
}

$junit = new JUnit($environment, $workerID);
$junit = new JUnit($environment, $workerContext->workerID);

if (getenv('SHOW_ONLY_GROUPS')) {
$SHOW_ONLY_GROUPS = explode(",", getenv('SHOW_ONLY_GROUPS'));
Expand Down Expand Up @@ -350,7 +352,7 @@ function main(): void
$file_cache = null;
$shuffle = false;
$bless = false;
$workers = null;
$workerContext->workers = null;
$context_line_count = 3;
$num_repeats = 1;
$show_progress = true;
Expand Down Expand Up @@ -421,6 +423,7 @@ function main(): void
if ($workers === 1) {
$workers = null;
}
$workerContext->workers = $workers;
break;
case 'r':
case 'l':
Expand Down Expand Up @@ -1229,13 +1232,14 @@ function system_with_timeout(
proc_close($proc);
return $data;
}

function run_all_tests(array $test_files, array $env, ?string $redir_tested = null): void
{
global $test_results, $failed_tests_file, $result_tests_file, $php, $test_idx, $file_cache;
global $preload;
// Parallel testing
global $PHP_FAILED_TESTS, $workers, $workerID, $workerSock;
global $PHP_FAILED_TESTS;

/** @var WorkerContext $workerContext */
global $workerContext;

if ($file_cache !== null || $preload) {
/* Automatically skip opcache tests in --file-cache and --preload mode,
Expand All @@ -1255,7 +1259,7 @@ function run_all_tests(array $test_files, array $env, ?string $redir_tested = nu
}

/* Ignore -jN if there is only one file to analyze. */
if ($workers !== null && count($test_files) > 1 && !$workerID) {
if ($workerContext->workers !== null && count($test_files) > 1 && !$workerContext->workerID) {
run_all_tests_parallel($test_files, $env, $redir_tested);
return;
}
Expand All @@ -1274,19 +1278,19 @@ function run_all_tests(array $test_files, array $env, ?string $redir_tested = nu
}
$test_idx++;

if ($workerID) {
if ($workerContext->workerID) {
$PHP_FAILED_TESTS = ['BORKED' => [], 'FAILED' => [], 'WARNED' => [], 'LEAKED' => [], 'XFAILED' => [], 'XLEAKED' => [], 'SLOW' => []];
ob_start();
}

$result = run_test($php, $name, $env);
if ($workerID) {
if ($workerContext->workerID) {
$resultText = ob_get_clean();
}

if (!is_array($name) && $result != 'REDIR') {
if ($workerID) {
send_message($workerSock, [
if ($workerContext->workerID) {
send_message($workerContext->workerSock, [
"type" => "test_result",
"name" => $name,
"index" => $index,
Expand All @@ -1310,10 +1314,13 @@ function run_all_tests(array $test_files, array $env, ?string $redir_tested = nu

function run_all_tests_parallel(array $test_files, array $env, ?string $redir_tested): void
{
global $workers, $test_idx, $test_results, $failed_tests_file, $result_tests_file, $PHP_FAILED_TESTS, $shuffle, $valgrind, $show_progress;
global $test_idx, $test_results, $failed_tests_file, $result_tests_file, $PHP_FAILED_TESTS, $shuffle, $valgrind, $show_progress;

global $junit;

/** @var WorkerContext $workerContext */
global $workerContext;

// The PHP binary running run-tests.php, and run-tests.php itself
// This PHP executable is *not* necessarily the same as the tested version
$thisPHP = PHP_BINARY;
Expand Down Expand Up @@ -1367,9 +1374,9 @@ function run_all_tests_parallel(array $test_files, array $env, ?string $redir_te
}

// Don't start more workers than test files.
$workers = max(1, min($workers, count($test_files)));
$workerContext->workers = max(1, min($workerContext->workers, count($test_files)));

echo "Spawning $workers workers... ";
echo "Spawning ". $workerContext->workers ." workers... ";

// We use sockets rather than STDIN/STDOUT for comms because on Windows,
// those can't be non-blocking for some reason.
Expand All @@ -1386,7 +1393,7 @@ function run_all_tests_parallel(array $test_files, array $env, ?string $redir_te
$totalFileCount = count($test_files);

$startTime = microtime(true);
for ($i = 1; $i <= $workers; $i++) {
for ($i = 1; $i <= $workerContext->workers; $i++) {
$proc = proc_open(
[$thisPHP, $thisScript],
[], // Inherit our stdin, stdout and stderr
Expand All @@ -1408,7 +1415,7 @@ function run_all_tests_parallel(array $test_files, array $env, ?string $redir_te
$workerProcs[$i] = $proc;
}

for ($i = 1; $i <= $workers; $i++) {
for ($i = 1; $i <= $workerContext->workers; $i++) {
$workerSock = stream_socket_accept($listenSock, 5);
if ($workerSock === false) {
kill_children($workerProcs);
Expand Down Expand Up @@ -1567,7 +1574,7 @@ function run_all_tests_parallel(array $test_files, array $env, ?string $redir_te
echo $resultText;

if ($show_progress) {
show_test($test_idx, count($workerProcs) . "/$workers concurrent test workers running");
show_test($test_idx, count($workerProcs) . "/".$workerContext->workers ." concurrent test workers running");
}

if (!is_array($name) && $result != 'REDIR') {
Expand Down Expand Up @@ -1662,6 +1669,9 @@ function safe_fwrite($stream, string $data)
return $bytes_written;
}

/**
* @param resource $stream
*/
function send_message($stream, array $message): void
{
$blocking = stream_get_meta_data($stream)["blocked"];
Expand All @@ -1681,23 +1691,24 @@ function kill_children(array $children): void

function run_worker(): void
{
global $workerID, $workerSock;
/** @var WorkerContext $workerContext */
global $workerContext;

global $junit;

$sockUri = getenv("TEST_PHP_URI");

$workerSock = stream_socket_client($sockUri, $_, $_, 5) or error("Couldn't connect to $sockUri");
$workerContext->workerSock = stream_socket_client($sockUri, $_, $_, 5) or error("Couldn't connect to $sockUri");

$greeting = fgets($workerSock);
$greeting = fgets($workerContext->workerSock);
$greeting = unserialize(base64_decode($greeting)) or die("Could not decode greeting\n");
if ($greeting["type"] !== "hello") {
error("Unexpected greeting of type $greeting[type]");
}

set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) use ($workerSock): bool {
set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) use ($workerContext): bool {
if (error_reporting() & $errno) {
send_message($workerSock, compact('errno', 'errstr', 'errfile', 'errline') + [
send_message($workerContext->workerSock, compact('errno', 'errstr', 'errfile', 'errline') + [
'type' => 'php_error'
]);
}
Expand All @@ -1706,37 +1717,37 @@ function run_worker(): void
});

foreach ($greeting["GLOBALS"] as $var => $value) {
if ($var !== "workerID" && $var !== "workerSock" && $var !== "GLOBALS") {
if ($var !== "workerContext" && $var !== "GLOBALS") {
$GLOBALS[$var] = $value;
}
}
foreach ($greeting["constants"] as $const => $value) {
define($const, $value);
}

send_message($workerSock, [
send_message($workerContext->workerSock, [
"type" => "hello_reply",
"workerID" => $workerID
"workerID" => $workerContext->workerID
]);

send_message($workerSock, [
send_message($workerContext->workerSock, [
"type" => "ready"
]);

while (($command = fgets($workerSock))) {
while (($command = fgets($workerContext->workerSock))) {
$command = unserialize(base64_decode($command));

switch ($command["type"]) {
case "run_tests":
run_all_tests($command["test_files"], $command["env"], $command["redir_tested"]);
send_message($workerSock, [
send_message($workerContext->workerSock, [
"type" => "tests_finished",
"junit" => $junit->isEnabled() ? $junit : null,
]);
$junit->clear();
break;
default:
send_message($workerSock, [
send_message($workerContext->workerSock, [
"type" => "error",
"msg" => "Unrecognised message type: $command[type]"
]);
Expand Down Expand Up @@ -1796,10 +1807,11 @@ function run_test(string $php, $file, array $env): string
global $slow_min_ms;
global $preload, $file_cache;
global $num_repeats;
// Parallel testing
global $workerID;
global $show_progress;

/** @var WorkerContext $workerContext */
global $workerContext;

// Temporary
/** @var JUnit $junit */
global $junit;
Expand Down Expand Up @@ -1913,7 +1925,7 @@ function run_test(string $php, $file, array $env): string
}
}

if ($show_progress && !$workerID) {
if ($show_progress && !$workerContext->workerID) {
show_test($test_idx, $shortname);
}

Expand Down Expand Up @@ -2004,7 +2016,7 @@ function run_test(string $php, $file, array $env): string
}

// Default ini settings
$ini_settings = $workerID ? ['opcache.cache_id' => "worker$workerID"] : [];
$ini_settings = $workerContext->workerID ? ['opcache.cache_id' => "worker".$workerContext->workers] : [];

// Additional required extensions
$extensions = [];
Expand Down Expand Up @@ -3217,10 +3229,10 @@ function show_test(int $test_idx, string $shortname): void
function clear_show_test(): void
{
global $line_length;
// Parallel testing
global $workerID;
/** @var WorkerContext $workerContext */
global $workerContext;

if (!$workerID && isset($line_length)) {
if (!$workerContext->workerID && isset($line_length)) {
// Write over the last line to avoid random trailing chars on next echo
echo str_repeat(" ", $line_length), "\r";
}
Expand Down Expand Up @@ -4171,4 +4183,19 @@ public function getDiff(array $diffs): string
}
}

class WorkerContext {
/**
* @var int|null number of workers to use, null for non-parallel testing.
*/
public $workers;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use native property types.

/**
* @var int
*/
public $workerID;
/**
* @var resource
*/
public $workerSock;
}

main();
Loading