]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
regrtest: don't fail immediately if a child does crash
authorVictor Stinner <victor.stinner@gmail.com>
Mon, 6 Feb 2017 11:42:00 +0000 (12:42 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Mon, 6 Feb 2017 11:42:00 +0000 (12:42 +0100)
Issue #29362: Catch a crash of a worker process as a normal failure and
continue to run next tests. It allows to get the usual test summary: single
line result (OK/FAIL), total duration, etc.

Lib/test/libregrtest/main.py
Lib/test/libregrtest/runtest_mp.py
Lib/test/test_regrtest.py

index 61a98763701d9680419e06f422f1975d2d625609..de1f4f9505ca9d829c44b394e66b7fe73495c962 100644 (file)
@@ -107,7 +107,7 @@ class Regrtest:
             self.test_times.append((test_time, test))
         if ok == PASSED:
             self.good.append(test)
-        elif ok == FAILED:
+        elif ok in (FAILED, CHILD_ERROR):
             self.bad.append(test)
         elif ok == ENV_CHANGED:
             self.environment_changed.append(test)
index 74ac4fa8951a5fd7f633ae65d64a19c6b4f0cc6b..34b3ae6a976c5c302ada76e710515ef22849c4b6 100644 (file)
@@ -129,7 +129,7 @@ class MultiprocessThread(threading.Thread):
             result = (CHILD_ERROR, "Exit code %s" % retcode)
             self.output.put((test, stdout.rstrip(), stderr.rstrip(),
                              result))
-            return True
+            return False
 
         if not result:
             self.output.put((None, None, None, None))
@@ -203,6 +203,8 @@ def run_tests_multiprocess(regrtest):
                 and test_time >= PROGRESS_MIN_TIME
                 and not regrtest.ns.pgo):
                 text += ' (%.0f sec)' % test_time
+            elif ok == CHILD_ERROR:
+                text = '%s (%s)' % (text, test_time)
             running = get_running(workers)
             if running and not regrtest.ns.pgo:
                 text += ' -- running: %s' % ', '.join(running)
@@ -216,9 +218,6 @@ def run_tests_multiprocess(regrtest):
 
             if result[0] == INTERRUPTED:
                 raise KeyboardInterrupt
-            if result[0] == CHILD_ERROR:
-                msg = "Child error on {}: {}".format(test, result[1])
-                raise Exception(msg)
             test_index += 1
     except KeyboardInterrupt:
         regrtest.interrupted = True
index 6d70e4d8f036d999b3bca336608854223dc3b34c..0bd62985d9c21ddfb0791c7ed3bd965504ef87f6 100644 (file)
@@ -354,7 +354,7 @@ class BaseTestCase(unittest.TestCase):
         self.assertRegex(output, regex)
 
     def parse_executed_tests(self, output):
-        regex = (r'^[0-9]+:[0-9]+:[0-9]+ \[ *[0-9]+(?:/ *[0-9]+)?\] (%s)'
+        regex = (r'^[0-9]+:[0-9]+:[0-9]+ \[ *[0-9]+(?:/ *[0-9]+)*\] (%s)'
                  % self.TESTNAME_REGEX)
         parser = re.finditer(regex, output, re.MULTILINE)
         return list(match.group(1) for match in parser)
@@ -809,6 +809,17 @@ class ArgsTestCase(BaseTestCase):
         self.assertEqual(output.rstrip().splitlines(),
                          tests)
 
+    def test_crashed(self):
+        # Any code which causes a crash
+        code = 'import faulthandler; faulthandler._sigsegv()'
+        crash_test = self.create_test(name="crash", code=code)
+        ok_test = self.create_test(name="ok")
+
+        tests = [crash_test, ok_test]
+        output = self.run_tests("-j2", *tests, exitcode=1)
+        self.check_executed_tests(output, tests, failed=crash_test,
+                                  randomize=True)
+
 
 if __name__ == '__main__':
     unittest.main()