Merged revisions 76260 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r76260 | r.david.murray | 2009-11-14 10:18:22 -0500 (Sat, 14 Nov 2009) | 5 lines

  Issue #7312 (new feature): Add a -F flag to run the selected tests in
  a loop until a test fails.  Can be combined with -j.  Patch by Antoine
  Pitrou.
........
This commit is contained in:
R. David Murray 2009-11-14 16:13:02 +00:00
parent 864b3f08d8
commit 7dc72cc1c4
2 changed files with 56 additions and 29 deletions

View File

@ -45,6 +45,7 @@ Special runs
-t/--threshold THRESHOLD -t/--threshold THRESHOLD
-- call gc.set_threshold(THRESHOLD) -- call gc.set_threshold(THRESHOLD)
-n/--nowindows -- suppress error message boxes on Windows -n/--nowindows -- suppress error message boxes on Windows
-F/--forever -- run the selected tests in a loop, until an error happens
If non-option arguments are present, they are names for tests to run, If non-option arguments are present, they are names for tests to run,
unless -x is given, in which case they are names for tests not to run. unless -x is given, in which case they are names for tests not to run.
@ -147,6 +148,7 @@ option '-uall,-gui'.
""" """
import getopt import getopt
import itertools
import json import json
import os import os
import random import random
@ -217,7 +219,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
exclude=False, single=False, randomize=False, fromfile=None, exclude=False, single=False, randomize=False, fromfile=None,
findleaks=False, use_resources=None, trace=False, coverdir='coverage', findleaks=False, use_resources=None, trace=False, coverdir='coverage',
runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, runleaks=False, huntrleaks=False, verbose2=False, print_slow=False,
random_seed=None, use_mp=None, verbose3=False): random_seed=None, use_mp=None, verbose3=False, forever=False):
"""Execute a test suite. """Execute a test suite.
This also parses command-line options and modifies its behavior This also parses command-line options and modifies its behavior
@ -243,12 +245,13 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
support.record_original_stdout(sys.stdout) support.record_original_stdout(sys.stdout)
try: try:
opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:wWM:nj:', opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:FwWM:nj:',
['help', 'verbose', 'verbose2', 'verbose3', 'quiet', ['help', 'verbose', 'verbose2', 'verbose3', 'quiet',
'exclude', 'single', 'slow', 'random', 'fromfile', 'findleaks', 'exclude', 'single', 'slow', 'random', 'fromfile', 'findleaks',
'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir',
'runleaks', 'huntrleaks=', 'memlimit=', 'debug', 'start=', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=',
'nowindows', 'randseed=', 'multiprocess=', 'slaveargs=']) 'multiprocess=', 'slaveargs=', 'forever', 'debug', 'start=',
'nowindows'])
except getopt.error as msg: except getopt.error as msg:
usage(msg) usage(msg)
@ -353,6 +356,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
elif o in ('-F', '--forever'):
forever = True
elif o in ('-j', '--multiprocess'): elif o in ('-j', '--multiprocess'):
use_mp = int(a) use_mp = int(a)
elif o == '--slaveargs': elif o == '--slaveargs':
@ -396,8 +401,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
filename = os.path.join(gettempdir(), 'pynexttest') filename = os.path.join(gettempdir(), 'pynexttest')
try: try:
fp = open(filename, 'r') fp = open(filename, 'r')
next = fp.read().strip() next_test = fp.read().strip()
tests = [next] tests = [next_test]
fp.close() fp.close()
except IOError: except IOError:
pass pass
@ -443,6 +448,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix, tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix,
tempfile.gettempdir()], tempfile.gettempdir()],
trace=False, count=True) trace=False, count=True)
test_times = [] test_times = []
support.verbose = verbose # Tell tests to be moderately quiet support.verbose = verbose # Tell tests to be moderately quiet
support.use_resources = use_resources support.use_resources = use_resources
@ -464,6 +470,17 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
skipped.append(test) skipped.append(test)
resource_denieds.append(test) resource_denieds.append(test)
if forever:
def test_forever(tests=list(tests)):
while True:
for test in tests:
yield test
if bad:
return
tests = test_forever()
else:
tests = iter(tests)
if use_mp: if use_mp:
from threading import Thread from threading import Thread
from queue import Queue, Empty from queue import Queue, Empty
@ -472,20 +489,22 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
debug_output_pat = re.compile(r"\[\d+ refs\]$") debug_output_pat = re.compile(r"\[\d+ refs\]$")
pending = deque() pending = deque()
output = Queue() output = Queue()
for test in tests: def tests_and_args():
args_tuple = ( for test in tests:
(test, verbose, quiet, testdir), args_tuple = (
dict(huntrleaks=huntrleaks, use_resources=use_resources, (test, verbose, quiet, testdir),
debug=debug) dict(huntrleaks=huntrleaks, use_resources=use_resources,
) debug=debug)
pending.append((test, args_tuple)) )
yield (test, args_tuple)
pending = tests_and_args()
def work(): def work():
# A worker thread. # A worker thread.
try: try:
while True: while True:
try: try:
test, args_tuple = pending.popleft() test, args_tuple = next(pending)
except IndexError: except StopIteration:
output.put((None, None, None, None)) output.put((None, None, None, None))
return return
# -E is needed by some tests, e.g. test_import # -E is needed by some tests, e.g. test_import
@ -498,6 +517,9 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
# comes from the shutdown of the interpreter in the subcommand. # comes from the shutdown of the interpreter in the subcommand.
stderr = debug_output_pat.sub("", stderr) stderr = debug_output_pat.sub("", stderr)
stdout, _, result = stdout.strip().rpartition("\n") stdout, _, result = stdout.strip().rpartition("\n")
if not result:
output.put((None, None, None, None))
return
result = json.loads(result) result = json.loads(result)
if not quiet: if not quiet:
stdout = test+'\n'+stdout stdout = test+'\n'+stdout
@ -509,20 +531,22 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
for worker in workers: for worker in workers:
worker.start() worker.start()
finished = 0 finished = 0
while finished < use_mp: try:
test, stdout, stderr, result = output.get() while finished < use_mp:
if test is None: test, stdout, stderr, result = output.get()
finished += 1 if test is None:
continue finished += 1
if stdout: continue
print(stdout) if stdout:
if stderr: print(stdout)
print(stderr, file=sys.stderr) if stderr:
if result[0] == INTERRUPTED: print(stderr, file=sys.stderr)
assert result[1] == 'KeyboardInterrupt' if result[0] == INTERRUPTED:
pending.clear() assert result[1] == 'KeyboardInterrupt'
raise KeyboardInterrupt # What else? raise KeyboardInterrupt # What else?
accumulate_result(test, result) accumulate_result(test, result)
except KeyboardInterrupt:
pending.close()
for worker in workers: for worker in workers:
worker.join() worker.join()
else: else:

View File

@ -378,6 +378,9 @@ Documentation
Tests Tests
----- -----
- Issue #7312: Add a -F flag to run the selected tests in a loop until
a test fails. Can be combined with -j.
- Issue #6551: test_zipimport could import and then destroy some modules of - Issue #6551: test_zipimport could import and then destroy some modules of
the encodings package, which would make other tests fail further down the encodings package, which would make other tests fail further down
the road because the internally cached encoders and decoders would point the road because the internally cached encoders and decoders would point