@@ -1851,11 +1851,16 @@ function run_test(string $php, $file, array $env): string
18511851 $ skipCache = new SkipCache ($ enableSkipCache , $ cfg ['keep ' ]['skip ' ]);
18521852 }
18531853
1854+ $ orig_php = $ php ;
1855+ $ php = escapeshellarg ($ php );
1856+
1857+ $ retriable = true ;
1858+ $ retried = false ;
1859+ retry:
1860+
18541861 $ temp_filenames = null ;
18551862 $ org_file = $ file ;
1856- $ orig_php = $ php ;
18571863
1858- $ php = escapeshellarg ($ php );
18591864 $ php_cgi = $ env ['TEST_PHP_CGI_EXECUTABLE ' ] ?? null ;
18601865 $ phpdbg = $ env ['TEST_PHPDBG_EXECUTABLE ' ] ?? null ;
18611866
@@ -1891,8 +1896,11 @@ function run_test(string $php, $file, array $env): string
18911896
18921897 $ tested = $ test ->getName ();
18931898
1894- if ($ num_repeats > 1 && $ test ->hasSection ('FILE_EXTERNAL ' )) {
1895- return skip_test ($ tested , $ tested_file , $ shortname , 'Test with FILE_EXTERNAL might not be repeatable ' );
1899+ if ($ test ->hasSection ('FILE_EXTERNAL ' )) {
1900+ $ retriable = false ;
1901+ if ($ num_repeats > 1 ) {
1902+ return skip_test ($ tested , $ tested_file , $ shortname , 'Test with FILE_EXTERNAL might not be repeatable ' );
1903+ }
18961904 }
18971905
18981906 if ($ test ->hasSection ('CAPTURE_STDIO ' )) {
@@ -1918,6 +1926,7 @@ function run_test(string $php, $file, array $env): string
19181926 }
19191927 $ php = escapeshellarg ($ php_cgi ) . ' -C ' ;
19201928 $ uses_cgi = true ;
1929+ $ retriable = false ;
19211930 if ($ num_repeats > 1 ) {
19221931 return skip_test ($ tested , $ tested_file , $ shortname , 'CGI does not support --repeat ' );
19231932 }
@@ -1935,20 +1944,18 @@ function run_test(string $php, $file, array $env): string
19351944 } else {
19361945 return skip_test ($ tested , $ tested_file , $ shortname , 'phpdbg not available ' );
19371946 }
1947+ $ retriable = false ;
19381948 if ($ num_repeats > 1 ) {
19391949 return skip_test ($ tested , $ tested_file , $ shortname , 'phpdbg does not support --repeat ' );
19401950 }
19411951 }
19421952
1943- if ($ num_repeats > 1 ) {
1944- if ($ test ->hasSection ('CLEAN ' )) {
1945- return skip_test ($ tested , $ tested_file , $ shortname , 'Test with CLEAN might not be repeatable ' );
1946- }
1947- if ($ test ->hasSection ('STDIN ' )) {
1948- return skip_test ($ tested , $ tested_file , $ shortname , 'Test with STDIN might not be repeatable ' );
1949- }
1950- if ($ test ->hasSection ('CAPTURE_STDIO ' )) {
1951- return skip_test ($ tested , $ tested_file , $ shortname , 'Test with CAPTURE_STDIO might not be repeatable ' );
1953+ foreach (['CLEAN ' , 'STDIN ' , 'CAPTURE_STDIO ' ] as $ section ) {
1954+ if ($ test ->hasSection ($ section )) {
1955+ $ retriable = false ;
1956+ if ($ num_repeats > 1 ) {
1957+ return skip_test ($ tested , $ tested_file , $ shortname , "Test with $ section might not be repeatable " );
1958+ }
19521959 }
19531960 }
19541961
@@ -2140,8 +2147,11 @@ function run_test(string $php, $file, array $env): string
21402147 }
21412148 settings2array (preg_split ("/[ \n\r]+/ " , $ ini ), $ ini_settings );
21422149
2143- if ($ num_repeats > 1 && isset ($ ini_settings ['opcache.opt_debug_level ' ])) {
2144- return skip_test ($ tested , $ tested_file , $ shortname , 'opt_debug_level tests are not repeatable ' );
2150+ if (isset ($ ini_settings ['opcache.opt_debug_level ' ])) {
2151+ $ retriable = false ;
2152+ if ($ num_repeats > 1 ) {
2153+ return skip_test ($ tested , $ tested_file , $ shortname , 'opt_debug_level tests are not repeatable ' );
2154+ }
21452155 }
21462156 }
21472157
@@ -2640,6 +2650,10 @@ function run_test(string $php, $file, array $env): string
26402650
26412651 $ wanted_re = null ;
26422652 }
2653+ if (!$ passed && !$ retried && $ retriable && error_may_be_retried ($ output )) {
2654+ $ retried = true ;
2655+ goto retry;
2656+ }
26432657
26442658 if ($ passed ) {
26452659 if (!$ cfg ['keep ' ]['php ' ] && !$ leaked ) {
@@ -2671,6 +2685,9 @@ function run_test(string $php, $file, array $env): string
26712685 // XLEAK with ASAN completely disables LSAN so the test is expected to pass
26722686 $ warn = true ;
26732687 $ info = " (warn: XLEAK section but test passes) " ;
2688+ } elseif ($ retried ) {
2689+ $ warn = true ;
2690+ $ info = " (warn: Test passed on retry attempt) " ;
26742691 } else {
26752692 show_result ("PASS " , $ tested , $ tested_file , '' , $ temp_filenames );
26762693 $ junit ->markTestAs ('PASS ' , $ shortname , $ tested );
@@ -2815,6 +2832,11 @@ function run_test(string $php, $file, array $env): string
28152832 return $ restype [0 ] . 'ED ' ;
28162833}
28172834
2835+ function error_may_be_retried (string $ output ): bool
2836+ {
2837+ return preg_match ('((timed out)|(connection refused))i ' , $ output ) === 1 ;
2838+ }
2839+
28182840function expectf_to_regex (?string $ wanted ): string
28192841{
28202842 $ wanted_re = $ wanted ?? '' ;
0 commit comments