[pypy-svn] r58322 - in pypy/build/testrunner: . test

pedronis at codespeak.net pedronis at codespeak.net
Mon Sep 22 17:51:06 CEST 2008


Author: pedronis
Date: Mon Sep 22 17:51:04 2008
New Revision: 58322

Modified:
   pypy/build/testrunner/runner.py
   pypy/build/testrunner/test/test_runner.py
Log:
(iko, pedronis)

- support parallel runs
- configurability hack through python code overriding the run parameters instance



Modified: pypy/build/testrunner/runner.py
==============================================================================
--- pypy/build/testrunner/runner.py	(original)
+++ pypy/build/testrunner/runner.py	Mon Sep 22 17:51:04 2008
@@ -1,4 +1,4 @@
-import sys, os, signal
+import sys, os, signal, thread, Queue
 import py
 from py.compat import subprocess, optparse
 
@@ -17,12 +17,7 @@
             return name
     return 'signal %d' % (n,)
 
-def execute_test(cwd, test, out, logfname, interp=None, test_driver=None):
-    if interp is None:
-        interp = [os.path.abspath(sys.executable)]
-    if test_driver is None:
-        test_driver = [os.path.abspath(os.path.join('py', 'bin', 'py.test'))]
-
+def execute_test(cwd, test, out, logfname, interp, test_driver):
     args = interp+test_driver
     args += ['--resultlog=%s' % logfname, test]
 
@@ -32,59 +27,124 @@
     return exitcode
 
 
+def worker(num, n, run_param, testdirs, result_queue):
+    sessdir = run_param.sessdir
+    root = run_param.root
+    test_driver = run_param.test_driver
+    interp = run_param.interp
+    # xxx cfg thread start
+    while 1:
+        try:
+            test = testdirs.pop(0)
+        except IndexError:
+            result_queue.put(None) # done
+            return
+        basename = py.path.local(test).purebasename        
+        logfname = sessdir.join("%d-%s-pytest-log" % (num, basename))
+        one_output = sessdir.join("%d-%s-output" % (num, basename))
+        num += n
 
-def execute_tests(cwd, testdirs, logfile, out, test_driver=None):
-    sessdir = py.path.local.make_numbered_dir(prefix='usession-testrunner-', keep=4)
-    c = 0
-    failure = False
-    
-    for test in testdirs:
-        basename = py.path.local(test).purebasename
-        logfname = sessdir.join("%d-%s-pytest-log" % (c, basename))
-        one_output = sessdir.join("%d-%s-output" % (c, basename))
-        c += 1
-        exitcode = execute_test(cwd, test, one_output, logfname,
-                                test_driver=test_driver)
-        if c > 1:
-            out.write(79*'_'+'\n')
+        exitcode = execute_test(root, test, one_output, logfname,
+                                interp, test_driver)
+
+        # xxx cfg cleanup after testdir
+        
         output = one_output.read()
-        out.write(output)
         if logfname.check(file=1):
             logdata = logfname.read()
-            logfile.write(logdata)
+        else:
+            logdata = ""
+
         if exitcode:
             failure = True
             if exitcode != 1:
                 pass # xxx unexpected exit cases
+        else:
+            failure = False
 
-    return failure
+        result_queue.put((failure, logdata, output))
+
+        
+
+def start_workers(n, run_param, testdirs):
+    result_queue = Queue.Queue()
+    for i in range(n):
+        thread.start_new_thread(worker, (i, n, run_param, testdirs,
+                                         result_queue))
+    return result_queue
+
+
+def execute_tests(run_param, testdirs, logfile, out):
+    sessdir = py.path.local.make_numbered_dir(prefix='usession-testrunner-',
+                                              keep=4)
+    run_param.sessdir = sessdir
+
+    N = run_param.parallel_runs
+    failure = False
+    
+    result_queue =start_workers(N, run_param, testdirs)
+
+    done = 0
+    first_ever = True
+    while True:
+        res = result_queue.get()
+        if res is None:
+            done += 1
+            if done == N:
+                break
+            continue
+                
+        somefailed, logdata, output = res
+        failure = failure or somefailed
+
+        if first_ever:
+            first_ever = False
+        else:
+            out.write(79*'_'+'\n')
+
+        out.write(output)
+        if logdata:
+            logfile.write(logdata)
 
+    return failure
 
-def is_test_py_file(p):
-    name = p.basename
-    return name.startswith('test_') and name.endswith('.py')
-
-def collect_one_testdir(testdirs, root, reldir, tests):
-    testdirs.append(reldir)
-    return
-
-def collect_testdirs(testdirs, p, root=None):
-    if root is None:
-        root = p
 
-    reldir = p.relto(root)
-    entries = [p1 for p1 in p.listdir() if p1.check(dotfile=0)]
+class RunParam(object):
+    interp = [os.path.abspath(sys.executable)]
+    test_driver = [os.path.abspath(os.path.join('py', 'bin', 'py.test'))]
+    parallel_runs = 1
+    
+    def __init__(self, root):
+        self.root = root
+        self.self = self
+
+    def is_test_py_file(self, p):
+        name = p.basename
+        return name.startswith('test_') and name.endswith('.py')
+
+    def collect_one_testdir(self, testdirs, reldir, tests):
+        testdirs.append(reldir)
+        return
+
+    def collect_testdirs(self, testdirs, p=None):
+        if p is None:
+            p = self.root
+            
+        reldir = p.relto(self.root)
+        entries = [p1 for p1 in p.listdir() if p1.check(dotfile=0)]
+
+        if p != self.root:
+            for p1 in entries:
+                if self.is_test_py_file(p1):
+                    self.collect_one_testdir(testdirs, reldir,
+                                   [t for t in entries
+                                    if self.is_test_py_file(t)])
+                    return
 
-    if p != root:
         for p1 in entries:
-            if is_test_py_file(p1):
-                collect_one_testdir(testdirs, root, reldir,
-                                   [t for t in entries if is_test_py_file(t)])
-                return
-
-    for p1 in entries:
-        if p1.check(dir=1, link=0):
-            collect_testdirs(testdirs, p1, root=root)
+            if p1.check(dir=1, link=0):
+                self.collect_testdirs(testdirs, p1)
+
 
 
 if __name__ == '__main__':
@@ -93,10 +153,15 @@
                       help="accumulated machine-readable logfile")
     parser.add_option("--output", dest="output", default='-',
                       help="plain test output (default: stdout)")
-    parser.add_option("--config", dest="config", default=None,
+    parser.add_option("--config", dest="config", default=[],
+                      action="append",
                       help="configuration python file (optional)")
     parser.add_option("--root", dest="root", default=".",
                       help="root directory for the run")
+    parser.add_option("--parallel-runs", dest="parallel_runs", default=0,
+                      type="int",
+                      help="number of parallel test runs")    
+    
     opts, args = parser.parse_args()
 
     if opts.logfile is None:
@@ -112,10 +177,22 @@
     root = py.path.local(opts.root)
 
     testdirs = []
+
+
+    run_param = RunParam(root)
+    # the config files are python files whose run overrides the content
+    # of the run_param instance namespace
+    # in that code function overriding method should not take self
+    # though a self and self.__class__ are available if needed
+    for config_py_file in opts.config:
+        execfile(config_py_file, run_param.__dict__)
     
-    collect_testdirs(testdirs, root)
+    run_param.collect_testdirs(testdirs)
 
-    res = execute_tests(root, testdirs, logfile, out)
+    if opts.parallel_runs:
+        run_param.parallel_runs = opts.parallel_runs
+    
+    res = execute_tests(run_param, testdirs, logfile, out)
 
     if res:
         sys.exit(1)

Modified: pypy/build/testrunner/test/test_runner.py
==============================================================================
--- pypy/build/testrunner/test/test_runner.py	(original)
+++ pypy/build/testrunner/test/test_runner.py	Mon Sep 22 17:51:04 2008
@@ -18,18 +18,6 @@
     def teardown_class(cls):
         runner.run = cls.real_run[0]
 
-    def test_basic(self):
-        res = runner.execute_test('/wd', 'test_one', 'out', 'LOGFILE')
-
-        expected = [os.path.abspath(sys.executable),
-                    os.path.abspath(os.path.join('py', 'bin', 'py.test')),
-                    '--resultlog=LOGFILE',
-                    'test_one']
-
-        assert self.called == (expected, '/wd', 'out')
-        assert res == 0
-
-
     def test_explicit(self):
         res = runner.execute_test('/wd', 'test_one', 'out', 'LOGFILE',
                                   interp=['INTERP', 'IARG'],
@@ -46,12 +34,16 @@
 
     def test_error(self):
         self.exitcode[:] = [1]
-        res = runner.execute_test('/wd', 'test_one', 'out', 'LOGFILE')
+        res = runner.execute_test('/wd', 'test_one', 'out', 'LOGFILE',
+                                  interp=['INTERP', 'IARG'],
+                                  test_driver=['driver', 'darg'])
         assert res == 1
 
 
         self.exitcode[:] = [-signal.SIGSEGV]
-        res = runner.execute_test('/wd', 'test_one', 'out', 'LOGFILE')
+        res = runner.execute_test('/wd', 'test_one', 'out', 'LOGFILE',
+                                  interp=['INTERP', 'IARG'],
+                                  test_driver=['driver', 'darg'])
         assert res == -signal.SIGSEGV
 
 
@@ -71,7 +63,9 @@
 
     def test_collect_testdirs_simple(self):
         res = []
-        runner.collect_testdirs(res, self.udir)
+        run_param = runner.RunParam(self.udir)
+        
+        run_param.collect_testdirs(res)
 
         assert res == ['test_normal']
         
@@ -81,9 +75,12 @@
 
         log = cStringIO.StringIO()
         out = cStringIO.StringIO()
+
+        param = runner.RunParam(self.udir)
+        param.test_driver = test_driver
+        param.parallel_runs = 3
         
-        res = runner.execute_tests(self.udir, ['test_normal'], log, out,
-                                   test_driver=test_driver)
+        res = runner.execute_tests(param, ['test_normal'], log, out)
 
         assert res
 
@@ -102,3 +99,7 @@
 
         assert noutcomes == 107
         assert nfailures == 6
+
+    # xxx test with more than one dir
+
+    # xxx test for main logic



More information about the Pypy-commit mailing list