[Checkins] SVN: z3c.recipe.compattest/trunk/ Allow parallel execution of the individual test runners by stating

Christian Theune ct at gocept.com
Thu Jan 29 03:35:16 EST 2009


Log message for revision 95383:
  Allow parallel execution of the individual test runners by stating
  'max_jobs=X' in the recipe's options.
  
  

Changed:
  U   z3c.recipe.compattest/trunk/CHANGES.txt
  U   z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/recipe.py
  U   z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.py
  A   z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.txt
  U   z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/tests/test_doctests.py

-=-
Modified: z3c.recipe.compattest/trunk/CHANGES.txt
===================================================================
--- z3c.recipe.compattest/trunk/CHANGES.txt	2009-01-29 08:33:45 UTC (rev 95382)
+++ z3c.recipe.compattest/trunk/CHANGES.txt	2009-01-29 08:35:16 UTC (rev 95383)
@@ -2,6 +2,12 @@
 CHANGES
 =======
 
+0.4 (unreleased)
+================
+
+- Allow parallel execution of the individual test runners by stating
+  'max_jobs=X' in the recipe's options.
+
 0.3 (2009-01-28)
 ================
 

Modified: z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/recipe.py
===================================================================
--- z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/recipe.py	2009-01-29 08:33:45 UTC (rev 95382)
+++ z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/recipe.py	2009-01-29 08:35:16 UTC (rev 95383)
@@ -46,11 +46,15 @@
 
 
 class Recipe(object):
+
     def __init__(self, buildout, name, options):
         self.buildout = buildout
         self.name = name
         self.options = options
 
+        if not 'max_jobs' in options:
+            options['max_jobs'] = '1'
+
         self.svn_url = self.options.get('svn_url',
                                         'svn://svn.zope.org/repos/main/')
         if self.svn_url[-1] != '/':
@@ -110,7 +114,8 @@
             [(self.script, 'z3c.recipe.compattest.runner', 'main')],
             self._working_set('z3c.recipe.compattest'),
             self.buildout['buildout']['executable'],
-            bindir, arguments = '%s' % ', '.join(runners))
+            bindir, arguments='%s, %s' % (self.options['max_jobs'],
+                                          ', '.join(runners)))
 
     def _wanted_packages(self):
         projects = []

Modified: z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.py
===================================================================
--- z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.py	2009-01-29 08:33:45 UTC (rev 95382)
+++ z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.py	2009-01-29 08:35:16 UTC (rev 95383)
@@ -1,7 +1,10 @@
+import StringIO
+import os.path
+import select
 import subprocess
 import sys
-import os.path
 
+
 def usage():
     print """
 usage: %s [OPTIONS]
@@ -10,32 +13,58 @@
 options you can use, refer to the test runner documentation.
 """ % sys.argv[0]
 
-def main(*scripts):
-    failed = dict()
+class Job(object):
+
+    def __init__(self, script, args):
+        self.script = script
+        self.args = args
+        self.name = os.path.basename(script)
+        self.output = StringIO.StringIO()
+        self.exitcode = None
+
+    def start(self):
+        self.process = subprocess.Popen(
+            [self.script, '--exit-with-status'] + self.args,
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            close_fds=True)
+
+    def poll(self):
+        self.exitcode = self.process.poll()
+        read, _, _ = select.select([self.process.stdout], [], [], 0.01)
+        if read:
+            self.output.write(read[0].read())
+
+
+def main(max_jobs, *scripts):
     argv = sys.argv[1:]
     if '-h' in argv or '--help' in argv:
         usage()
         return
 
-    for script in scripts:
-        print "Running %s" % os.path.basename(script)
-        p = subprocess.Popen(
-            [script, '--exit-with-status'] + sys.argv[1:],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            close_fds=True)
-        output = u''
-        data = p.stdout.read()
-        while data:
-            output += data
-            data = p.stdout.read()
-        if p.wait():
-            failed[script] = output
-            print "Failed with:"
-            print failed[script]
+    running = []
+    completed = []
+    scripts = list(scripts)
 
-    failures = len(failed)
-    print "%d failures." % failures
-    if failures:
-        print "- %s" % u"\n- ".join(failed.keys())
+    while scripts or running:
+        for job in running:
+            job.poll()
+            if job.exitcode is None:
+                continue
+            completed.append(job)
+            running.remove(job)
+            if job.exitcode:
+                print "%s failed with:" % job.name
+                print job.output.getvalue()
 
+        while (len(running) < max_jobs) and scripts:
+            script = scripts.pop(0)
+            job = Job(script, sys.argv[1:])
+            print "Running %s" % job.name
+            job.start()
+            running.append(job)
+
+    failures = [job for job in completed if job.exitcode]
+    print "%d failure(s)." % len(failures)
+    for job in failures:
+        print "-", job.name

Added: z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.txt
===================================================================
--- z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.txt	                        (rev 0)
+++ z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.txt	2009-01-29 08:35:16 UTC (rev 95383)
@@ -0,0 +1,45 @@
+=====================================
+Combined runner for multiple packages
+=====================================
+
+To run the compatibility tests for the huge amount of individual
+packages in isolation we provide a wrapper script which runs all
+individual test runners together, but each in a separate process.
+
+It monitors the stdout of those processes and reports back packages with
+failures.
+
+>>> import os
+>>> ok_script = os.path.join(sample_buildout, 'test-ok')
+>>> write(ok_script, '#!/bin/bash\n sleep 1; exit')
+>>> os.chmod(ok_script, 0755)
+
+>>> failure_script = os.path.join(sample_buildout, 'test-failure')
+>>> write(failure_script, '#!/bin/bash\n sleep 1; echo ouch; exit 1')
+>>> os.chmod(failure_script, 0755)
+
+>>> import os.path
+>>> from z3c.recipe.compattest.runner import main
+>>> main(1, ok_script, failure_script)
+Running test-ok
+Running test-failure
+test-failure failed with:
+ouch
+<BLANKLINE>
+1 failure(s).
+- test-failure
+
+>>> main(2, failure_script, ok_script, failure_script, ok_script)
+Running test-failure
+Running test-ok
+test-failure failed with:
+ouch
+<BLANKLINE>
+Running test-failure
+Running test-ok
+test-failure failed with:
+ouch
+<BLANKLINE>
+2 failure(s).
+- test-failure
+- test-failure


Property changes on: z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/runner.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/tests/test_doctests.py
===================================================================
--- z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/tests/test_doctests.py	2009-01-29 08:33:45 UTC (rev 95382)
+++ z3c.recipe.compattest/trunk/src/z3c/recipe/compattest/tests/test_doctests.py	2009-01-29 08:35:16 UTC (rev 95383)
@@ -2,4 +2,5 @@
 
 
 def test_suite():
-    return z3c.recipe.compattest.testing.DocFileSuite('README.txt')
+    return z3c.recipe.compattest.testing.DocFileSuite(
+        'README.txt', 'runner.txt')



More information about the Checkins mailing list