[Zope3-checkins] SVN: zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/ checkpoint

Benji York benji at zope.com
Fri Jul 4 09:45:41 EDT 2008


Log message for revision 87998:
  checkpoint
  

Changed:
  U   zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/layer.py
  U   zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/options.py
  U   zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/runner.py

-=-
Modified: zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/layer.py
===================================================================
--- zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/layer.py	2008-07-04 08:40:27 UTC (rev 87997)
+++ zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/layer.py	2008-07-04 13:45:39 UTC (rev 87998)
@@ -19,7 +19,3 @@
 
 class UnitTests(object):
     """A layer for gathering all unit tests."""
-
-    @staticmethod
-    def tearDown():
-        raise NotImplementedError

Modified: zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/options.py
===================================================================
--- zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/options.py	2008-07-04 08:40:27 UTC (rev 87997)
+++ zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/options.py	2008-07-04 13:45:39 UTC (rev 87998)
@@ -407,6 +407,20 @@
 other = optparse.OptionGroup(parser, "Other", "Other options")
 
 other.add_option(
+    '--exit-with-status', action="store_true", dest='exitwithstatus',
+    help="""\
+Return an error exit status if the tests failed.  This can be useful for
+an invoking process that wants to monitor the result of a test run.
+""")
+
+other.add_option(
+    '-j', action="store", type="int", dest='processes', default=1,
+    help="""\
+Use up to given number of parallel processes to execute tests.  May decrease
+test run time substantially.  Defaults to %default.
+""")
+
+other.add_option(
     '--keepbytecode', '-k', action="store_true", dest='keepbytecode',
     help="""\
 Normally, the test runner scans the test paths and the test
@@ -431,13 +445,6 @@
 compilation to .pyc/.pyo.  Use of this option implies --keepbytecode.
 """)
 
-other.add_option(
-    '--exit-with-status', action="store_true", dest='exitwithstatus',
-    help="""\
-Return an error exit status if the tests failed.  This can be useful for
-an invoking process that wants to monitor the result of a test run.
-""")
-
 parser.add_option_group(other)
 
 ######################################################################

Modified: zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/runner.py
===================================================================
--- zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/runner.py	2008-07-04 08:40:27 UTC (rev 87997)
+++ zope.testing/branches/benji-parallelize-subprocesses/src/zope/testing/testrunner/runner.py	2008-07-04 13:45:39 UTC (rev 87998)
@@ -206,8 +206,10 @@
         """
         setup_layers = {}
         layers_to_run = list(self.ordered_layers())
+        should_resume = False
 
-        for layer_name, layer, tests in layers_to_run:
+        while layers_to_run:
+            layer_name, layer, tests = layers_to_run.pop(0)
             for feature in self.features:
                 feature.layer_setup(layer)
             try:
@@ -217,12 +219,19 @@
                 self.failed = True
                 return
             except CanNotTearDown:
-                setup_layers = None
                 if not self.options.resume_layer:
-                    self.ran += resume_tests(self.options, layer_name, layers_to_run,
-                                             self.failures, self.errors)
+                    should_resume = True
                     break
 
+            if self.options.processes > 1:
+                should_resume = True
+                break
+
+        if should_resume:
+            setup_layers = None
+            self.ran += resume_tests(self.options, self.features,
+                layers_to_run, self.failures, self.errors)
+
         if setup_layers:
             if self.options.resume_layer == None:
                 self.options.output.info("Tearing down left over layers:")
@@ -359,8 +368,8 @@
     def runTest(self):
         "Layer set up failure."
 
-def resume_a_layer(queue, options, layer_name, failures, errors,
-        resume_number):
+def spawn_layer_in_subprocess(queue, options, features, layer_name, layer,
+        failures, errors, resume_number):
     args = [sys.executable,
             sys.argv[0],
             '--resume-layer', layer_name, str(resume_number),
@@ -381,6 +390,9 @@
             for a in args[1:]
             ])
 
+    for feature in features:
+        feature.layer_setup(layer)
+
     subin, subout, suberr = os.popen3(args)
     while True:
         try:
@@ -416,24 +428,21 @@
     queue.put(ran)
 
 
-def resume_tests(options, layer_name, layers, failures, errors):
-    output = options.output
+def resume_tests(options, features, layers, failures, errors):
     queue = Queue.Queue()
-    layers = [l for (l, _, _) in layers]
-    layers = layers[layers.index(layer_name):]
     resume_number = 0
     ready_threads = []
-    for layer_name in layers:
+    for layer_name, layer, tests in layers:
         ready_threads.append(threading.Thread(
-            target=resume_a_layer,
-            args=(queue, options, layer_name, failures, errors, resume_number)))
+            target=spawn_layer_in_subprocess,
+            args=(queue, options, features, layer_name, layer, failures,
+                errors, resume_number)))
         resume_number += 1
 
     # Now start a few threads at a time.
-    num_threads = 3
     running_threads = []
     while ready_threads or running_threads:
-        while len(running_threads) < num_threads and ready_threads:
+        while len(running_threads) < options.processes and ready_threads:
             thread = ready_threads.pop(0)
             thread.start()
             running_threads.append(thread)
@@ -441,7 +450,7 @@
         for index, thread in list(enumerate(running_threads)):
             if not thread.isAlive():
                 del running_threads[index]
-        time.sleep(0.1)
+        time.sleep(0.01) # keep the loop from being too tight
 
     # Gather up all the results.
     rantotal = 0



More information about the Zope3-Checkins mailing list