]> granicus.if.org Git - python/commitdiff
bpo-30258: regrtest handles child process crash (#1431)
authorVictor Stinner <victor.stinner@gmail.com>
Wed, 3 May 2017 15:28:28 +0000 (17:28 +0200)
committerGitHub <noreply@github.com>
Wed, 3 May 2017 15:28:28 +0000 (17:28 +0200)
Backport the CHILD_ERROR status from master: a test is considered as
failed if a worker process running a test exited with a code
different than zero.

Change also the output: write stdout and stderr of the child process
after the test name, instead of writing it before.

accumulate_result(): don't use time of CHILD_ERROR or INTERRUPTED
results.

Lib/test/regrtest.py

index bc3fa713b50f52a9662f1f0c804373da7bf663bc..e49bcb962fb8de2851a6af5e50dd25c2bdf35499 100755 (executable)
@@ -220,6 +220,7 @@ ENV_CHANGED = -1
 SKIPPED = -2
 RESOURCE_DENIED = -3
 INTERRUPTED = -4
+CHILD_ERROR = -5   # error in a child process
 
 from test import test_support
 
@@ -466,7 +467,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
 
     def accumulate_result(test, result):
         ok, test_time = result
-        test_times.append((test_time, test))
+        if ok not in (CHILD_ERROR, INTERRUPTED):
+            test_times.append((test_time, test))
         if ok == PASSED:
             good.append(test)
         elif ok == FAILED:
@@ -478,6 +480,9 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
         elif ok == RESOURCE_DENIED:
             skipped.append(test)
             resource_denieds.append(test)
+        else:
+            # CHILD_ERROR
+            bad.append(test)
 
     if forever:
         def test_forever(tests=list(selected)):
@@ -533,9 +538,17 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
                                    universal_newlines=True,
                                    close_fds=(os.name != 'nt'))
                     stdout, stderr = popen.communicate()
+                    retcode = popen.wait()
+
                     # Strip last refcount output line if it exists, since it
                     # comes from the shutdown of the interpreter in the subcommand.
                     stderr = debug_output_pat.sub("", stderr)
+
+                    if retcode != 0:
+                        result = (CHILD_ERROR, "Exit code %s" % retcode)
+                        output.put((test, stdout.rstrip(), stderr.rstrip(),
+                                    result))
+
                     stdout, _, result = stdout.strip().rpartition("\n")
                     if not result:
                         output.put((None, None, None, None))
@@ -545,9 +558,11 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
             except BaseException:
                 output.put((None, None, None, None))
                 raise
+
         workers = [Thread(target=work) for i in range(use_mp)]
         for worker in workers:
             worker.start()
+
         finished = 0
         test_index = 1
         try:
@@ -556,21 +571,24 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
                 if test is None:
                     finished += 1
                     continue
+                accumulate_result(test, result)
+                if not quiet:
+                    fmt = "[{1:{0}}{2}/{3}] {4}" if bad else "[{1:{0}}{2}] {4}"
+                    print(fmt.format(
+                        test_count_width, test_index, test_count,
+                        len(bad), test))
+
                 if stdout:
                     print stdout
+                sys.stdout.flush()
                 if stderr and not pgo:
                     print >>sys.stderr, stderr
-                sys.stdout.flush()
                 sys.stderr.flush()
+
                 if result[0] == INTERRUPTED:
                     assert result[1] == 'KeyboardInterrupt'
                     raise KeyboardInterrupt   # What else?
-                accumulate_result(test, result)
-                if not quiet:
-                    fmt = "[{1:{0}}{2}/{3}] {4}" if bad else "[{1:{0}}{2}] {4}"
-                    print(fmt.format(
-                        test_count_width, test_index, test_count,
-                        len(bad), test))
+
                 test_index += 1
         except KeyboardInterrupt:
             interrupted = True
@@ -738,6 +756,7 @@ def runtest(test, verbose, quiet,
            for Profile Guided Optimization build
 
     Returns one of the test result constants:
+        CHILD_ERROR      Child process crashed
         INTERRUPTED      KeyboardInterrupt when run under -j
         RESOURCE_DENIED  test skipped because resource denied
         SKIPPED          test skipped for some other reason