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