Commit 7785159f7ee for php.net

commit 7785159f7ee21f64bcd3b68ffaac58f8fdbe244e
Author: NickSdot <32384907+NickSdot@users.noreply.github.com>
Date:   Mon Aug 3 23:22:06 2026 +0700

    Fix redirected-test progress accounting in parallel runs (#22952)

diff --git a/run-tests.php b/run-tests.php
index 703dd643ca7..89bd8ffb797 100755
--- a/run-tests.php
+++ b/run-tests.php
@@ -1351,7 +1351,8 @@ 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 ($workers !== null && count($test_files) > 1 && !$workerID
+            && $redir_tested === null) {
         run_all_tests_parallel($test_files, $env, $redir_tested);
         return;
     }
@@ -1406,7 +1407,7 @@ 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 $workers, $test_cnt, $test_idx, $test_results, $failed_tests_file, $result_tests_file, $PHP_FAILED_TESTS, $shuffle, $valgrind, $show_progress;

     global $junit;

@@ -1588,6 +1589,9 @@ function run_all_tests_parallel(array $test_files, array $env, ?string $redir_te
                     }

                     switch ($message["type"]) {
+                        case "test_count_delta":
+                            $test_cnt += $message["delta"];
+                            break;
                         case "tests_finished":
                             $testsInProgress--;
                             foreach ($activeConflicts as $key => $workerId) {
@@ -1890,7 +1894,7 @@ function run_test(string $php, $file, array $env): string
     global $preload, $file_cache;
     global $num_repeats;
     // Parallel testing
-    global $workerID;
+    global $workerID, $workerSock;
     global $show_progress;

     // Temporary
@@ -2326,7 +2330,14 @@ function run_test(string $php, $file, array $env): string
                     $test_files[] = [$f, $file];
                 }
             }
-            $test_cnt += count($test_files) - 1;
+            $test_count_delta = count($test_files) - 1;
+            $test_cnt += $test_count_delta;
+            if ($workerID && $test_count_delta !== 0) {
+                send_message($workerSock, [
+                    "type" => "test_count_delta",
+                    "delta" => $test_count_delta,
+                ]);
+            }
             $test_idx--;

             show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file);
diff --git a/tests/run-test/redirected_parallel.phpt b/tests/run-test/redirected_parallel.phpt
new file mode 100644
index 00000000000..47830f34125
--- /dev/null
+++ b/tests/run-test/redirected_parallel.phpt
@@ -0,0 +1,111 @@
+--TEST--
+Redirected tests work in parallel runs and update the progress total
+--ENV--
+TEST_PHP_FORK_SERVER=0
+--FILE--
+<?php
+function writeRedirectedTest(string $file, string $name): void
+{
+    file_put_contents($file, <<<PHPT
+        --TEST--
+        $name
+        --FILE--
+        <?php echo "ok\\n"; ?>
+        --EXPECT--
+        ok
+        PHPT);
+}
+
+function runRedirectedTests(array $testFiles): array
+{
+    $command = [
+        getenv('TEST_PHP_EXECUTABLE'),
+        '-n',
+        dirname(__DIR__, 2) . '/run-tests.php',
+        '-n',
+        '-q',
+        '-j2',
+        '--progress',
+        ...$testFiles,
+    ];
+    $environment = [
+        'PATH' => getenv('PATH'),
+        'TEST_PHP_EXECUTABLE' => getenv('TEST_PHP_EXECUTABLE'),
+        'TEST_PHP_FORK_SERVER' => '0',
+    ];
+    foreach (['SystemRoot', 'TEMP', 'TMPDIR'] as $name) {
+        if (($value = getenv($name)) !== false) {
+            $environment[$name] = $value;
+        }
+    }
+
+    $process = proc_open(
+        $command,
+        [
+            0 => ['pipe', 'r'],
+            1 => ['pipe', 'w'],
+            2 => ['redirect', 1],
+        ],
+        $pipes,
+        null,
+        $environment,
+    );
+    fclose($pipes[0]);
+    $output = stream_get_contents($pipes[1]);
+    fclose($pipes[1]);
+    return [proc_close($process), str_replace("\r", "\n", $output)];
+}
+
+$root = __DIR__ . '/redirected_parallel_' . getmypid();
+$targets = $root . '/targets';
+mkdir($targets, recursive: true);
+
+writeRedirectedTest($targets . '/one.phpt', 'redirected one');
+writeRedirectedTest($targets . '/two.phpt', 'redirected two');
+
+$targetExpression = var_export($targets, true);
+$redirect = $root . '/redirect.phpt';
+file_put_contents($redirect, <<<PHPT
+    --TEST--
+    redirect wrapper
+    --REDIRECTTEST--
+    return ['ENV' => [], 'TESTS' => $targetExpression];
+    PHPT);
+writeRedirectedTest($root . '/companion.phpt', 'companion');
+
+[$singleExitCode, $singleOutput] = runRedirectedTests([$redirect]);
+if ($singleExitCode !== 0) {
+    echo $singleOutput;
+}
+var_dump($singleExitCode);
+var_dump(str_contains($singleOutput, 'Fatal error'));
+
+[$parallelExitCode, $parallelOutput] = runRedirectedTests([
+    $redirect,
+    $root . '/companion.phpt',
+]);
+if ($parallelExitCode !== 0) {
+    echo $parallelOutput;
+}
+var_dump($parallelExitCode);
+var_dump(str_contains($parallelOutput, 'TEST 3/3'));
+var_dump(str_contains($parallelOutput, 'TEST 3/2'));
+?>
+--CLEAN--
+<?php
+foreach (glob(__DIR__ . '/redirected_parallel_*') ?: [] as $root) {
+    foreach (glob($root . '/targets/*') ?: [] as $file) {
+        unlink($file);
+    }
+    @rmdir($root . '/targets');
+    @unlink($root . '/redirect.phpt');
+    @unlink($root . '/companion.phpt');
+    @rmdir($root);
+}
+?>
+--EXPECT--
+int(0)
+bool(false)
+int(0)
+bool(true)
+bool(false)