cpython: 8bd9422ef41e (original) (raw)
--- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -1,7 +1,7 @@ import json import os -import re import sys +import time import traceback import unittest from queue import Queue @@ -15,7 +15,12 @@ except ImportError: from test.libregrtest.runtest import runtest, INTERRUPTED, CHILD_ERROR -def run_tests_in_subprocess(testname, ns): +# Minimum duration of a test to display its duration or to mention that +# the test is running in background +PROGRESS_MIN_TIME = 30.0 # seconds + + +def run_test_in_subprocess(testname, ns): """Run the given test in a subprocess with --slaveargs. ns is the option Namespace parsed from command-line arguments. regrtest @@ -24,26 +29,33 @@ def run_tests_in_subprocess(testname, ns 3-tuple. """ from subprocess import Popen, PIPE
- base_cmd = ([sys.executable] + support.args_from_interpreter_flags() +
['-X', 'faulthandler', '-m', 'test.regrtest'])[](#l1.31)
- slaveargs = (
(testname, ns.verbose, ns.quiet),[](#l1.34)
dict(huntrleaks=ns.huntrleaks,[](#l1.35)
use_resources=ns.use_resources,[](#l1.36)
output_on_failure=ns.verbose3,[](#l1.37)
timeout=ns.timeout, failfast=ns.failfast,[](#l1.38)
match_tests=ns.match_tests))[](#l1.39)
- args = (testname, ns.verbose, ns.quiet)
- kwargs = dict(huntrleaks=ns.huntrleaks,
use_resources=ns.use_resources,[](#l1.42)
output_on_failure=ns.verbose3,[](#l1.43)
timeout=ns.timeout,[](#l1.44)
failfast=ns.failfast,[](#l1.45)
match_tests=ns.match_tests)[](#l1.46)
- slaveargs = (args, kwargs)
- slaveargs = json.dumps(slaveargs)
- cmd = [sys.executable, *support.args_from_interpreter_flags(),
'-X', 'faulthandler',[](#l1.51)
'-m', 'test.regrtest',[](#l1.52)
'--slaveargs', slaveargs][](#l1.53)
+ # Running the child from the same working directory as regrtest's original # invocation ensures that TEMPDIR for the child is the same when # sysconfig.is_python_build() is true. See issue 15300.
- popen = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True, close_fds=(os.name != 'nt'), cwd=support.SAVEDCWD)
- with popen:
stdout, stderr = popen.communicate()[](#l1.67)
return retcode, stdout, stderr @@ -90,30 +102,45 @@ class MultiprocessThread(threading.Threa self.pending = pending self.output = output self.ns = nsretcode = popen.wait()[](#l1.68)
self.current_test = None[](#l1.76)
self.start_time = None[](#l1.77)
- def _runtest(self):
try:[](#l1.80)
test = next(self.pending)[](#l1.81)
except StopIteration:[](#l1.82)
self.output.put((None, None, None, None))[](#l1.83)
return True[](#l1.84)
try:[](#l1.86)
self.start_time = time.monotonic()[](#l1.87)
self.current_test = test[](#l1.88)
retcode, stdout, stderr = run_test_in_subprocess(test, self.ns)[](#l1.90)
finally:[](#l1.91)
self.current_test = None[](#l1.92)
stdout, _, result = stdout.strip().rpartition("\n")[](#l1.94)
if retcode != 0:[](#l1.95)
result = (CHILD_ERROR, "Exit code %s" % retcode)[](#l1.96)
self.output.put((test, stdout.rstrip(), stderr.rstrip(),[](#l1.97)
result))[](#l1.98)
return True[](#l1.99)
if not result:[](#l1.101)
self.output.put((None, None, None, None))[](#l1.102)
return True[](#l1.103)
result = json.loads(result)[](#l1.105)
self.output.put((test, stdout.rstrip(), stderr.rstrip(),[](#l1.106)
result))[](#l1.107)
return False[](#l1.108)
# A worker thread.[](#l1.111) try:[](#l1.112)
while True:[](#l1.113)
try:[](#l1.114)
test = next(self.pending)[](#l1.115)
except StopIteration:[](#l1.116)
self.output.put((None, None, None, None))[](#l1.117)
return[](#l1.118)
retcode, stdout, stderr = run_tests_in_subprocess(test,[](#l1.119)
self.ns)[](#l1.120)
stdout, _, result = stdout.strip().rpartition("\n")[](#l1.121)
if retcode != 0:[](#l1.122)
result = (CHILD_ERROR, "Exit code %s" % retcode)[](#l1.123)
self.output.put((test, stdout.rstrip(), stderr.rstrip(),[](#l1.124)
result))[](#l1.125)
return[](#l1.126)
if not result:[](#l1.127)
self.output.put((None, None, None, None))[](#l1.128)
return[](#l1.129)
result = json.loads(result)[](#l1.130)
self.output.put((test, stdout.rstrip(), stderr.rstrip(),[](#l1.131)
result))[](#l1.132)
stop = False[](#l1.133)
while not stop:[](#l1.134)
stop = self._runtest()[](#l1.135) except BaseException:[](#l1.136) self.output.put((None, None, None, None))[](#l1.137) raise[](#l1.138)
@@ -136,13 +163,33 @@ def run_tests_multiprocess(regrtest): finished += 1 continue regrtest.accumulate_result(test, result)
regrtest.display_progress(test_index, test)[](#l1.143)
# Display progress[](#l1.145)
text = test[](#l1.146)
ok, test_time = result[](#l1.147)
if (ok not in (CHILD_ERROR, INTERRUPTED)[](#l1.148)
and test_time >= PROGRESS_MIN_TIME):[](#l1.149)
text += ' (%.0f sec)' % test_time[](#l1.150)
running = [][](#l1.151)
for worker in workers:[](#l1.152)
current_test = worker.current_test[](#l1.153)
if not current_test:[](#l1.154)
continue[](#l1.155)
dt = time.monotonic() - worker.start_time[](#l1.156)
if dt >= PROGRESS_MIN_TIME:[](#l1.157)
running.append('%s (%.0f sec)' % (current_test, dt))[](#l1.158)
if running:[](#l1.159)
text += ' -- running: %s' % ', '.join(running)[](#l1.160)
regrtest.display_progress(test_index, text)[](#l1.161)
# Copy stdout and stderr from the child process[](#l1.163) if stdout:[](#l1.164) print(stdout)[](#l1.165) if stderr:[](#l1.166) print(stderr, file=sys.stderr)[](#l1.167) sys.stdout.flush()[](#l1.168) sys.stderr.flush()[](#l1.169)
+ if result[0] == INTERRUPTED: raise KeyboardInterrupt if result[0] == CHILD_ERROR: @@ -152,5 +199,11 @@ def run_tests_multiprocess(regrtest): except KeyboardInterrupt: regrtest.interrupted = True pending.interrupted = True
print()[](#l1.178)