Close #25373: Fix regrtest --slow with interrupted test
* Fix accumulate_result(): don't use time on interrupted and failed test
* Add unit test for interrupted test
* Add unit test on --slow with interrupted test, with and without
multiprocessing
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index aa95b21..82788ad 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -7,10 +7,11 @@
import sysconfig
import tempfile
import textwrap
+from test.libregrtest.cmdline import _parse_args
from test.libregrtest.runtest import (
findtests, runtest,
- STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED)
-from test.libregrtest.cmdline import _parse_args
+ STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
+ INTERRUPTED, CHILD_ERROR)
from test.libregrtest.setup import setup_tests
from test import support
try:
@@ -87,7 +88,8 @@
def accumulate_result(self, test, result):
ok, test_time = result
- self.test_times.append((test_time, test))
+ if ok not in (CHILD_ERROR, INTERRUPTED):
+ self.test_times.append((test_time, test))
if ok == PASSED:
self.good.append(test)
elif ok == FAILED:
@@ -291,10 +293,12 @@
else:
try:
result = runtest(self.ns, test)
- self.accumulate_result(test, result)
except KeyboardInterrupt:
+ self.accumulate_result(test, (INTERRUPTED, None))
self.interrupted = True
break
+ else:
+ self.accumulate_result(test, result)
if self.ns.findleaks:
gc.collect()
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index 16a29b1..ab7741f 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -24,6 +24,16 @@
ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..')
ROOT_DIR = os.path.abspath(os.path.normpath(ROOT_DIR))
+TEST_INTERRUPTED = textwrap.dedent("""
+ from signal import SIGINT
+ try:
+ from _testcapi import raise_signal
+ raise_signal(SIGINT)
+ except ImportError:
+ import os
+ os.kill(os.getpid(), SIGINT)
+ """)
+
class ParseArgsTestCase(unittest.TestCase):
"""
@@ -340,16 +350,19 @@
return list(match.group(1) for match in parser)
def check_executed_tests(self, output, tests, skipped=(), failed=(),
- randomize=False):
+ omitted=(), randomize=False):
if isinstance(tests, str):
tests = [tests]
if isinstance(skipped, str):
skipped = [skipped]
if isinstance(failed, str):
failed = [failed]
+ if isinstance(omitted, str):
+ omitted = [omitted]
ntest = len(tests)
nskipped = len(skipped)
nfailed = len(failed)
+ nomitted = len(omitted)
executed = self.parse_executed_tests(output)
if randomize:
@@ -375,7 +388,11 @@
regex = list_regex('%s test%s failed', failed)
self.check_line(output, regex)
- good = ntest - nskipped - nfailed
+ if omitted:
+ regex = list_regex('%s test%s omitted', omitted)
+ self.check_line(output, regex)
+
+ good = ntest - nskipped - nfailed - nomitted
if good:
regex = r'%s test%s OK\.$' % (good, plural(good))
if not skipped and not failed and good > 1:
@@ -607,6 +624,12 @@
output = self.run_tests('--fromfile', filename)
self.check_executed_tests(output, tests)
+ def test_interrupted(self):
+ code = TEST_INTERRUPTED
+ test = self.create_test("sigint", code=code)
+ output = self.run_tests(test, exitcode=1)
+ self.check_executed_tests(output, test, omitted=test)
+
def test_slow(self):
# test --slow
tests = [self.create_test() for index in range(3)]
@@ -617,6 +640,22 @@
% (self.TESTNAME_REGEX, len(tests)))
self.check_line(output, regex)
+ def test_slow_interrupted(self):
+ # Issue #25373: test --slow with an interrupted test
+ code = TEST_INTERRUPTED
+ test = self.create_test("sigint", code=code)
+
+ for multiprocessing in (False, True):
+ if multiprocessing:
+ args = ("--slow", "-j2", test)
+ else:
+ args = ("--slow", test)
+ output = self.run_tests(*args, exitcode=1)
+ self.check_executed_tests(output, test, omitted=test)
+ regex = ('10 slowest tests:\n')
+ self.check_line(output, regex)
+ self.check_line(output, 'Test suite interrupted by signal SIGINT.')
+
def test_coverage(self):
# test --coverage
test = self.create_test()