webkitpy: Notify parent process when a worker is spawned
[WebKit-https.git] / Tools / Scripts / webkitpy / test / runner.py
index 8c415de..3c25a16 100644 (file)
 
 """code to actually run a list of python tests."""
 
-import logging
 import re
 import time
 import unittest
 
 from webkitpy.common import message_pool
 
-_log = logging.getLogger(__name__)
-
-
 _test_description = re.compile("(\w+) \(([\w.]+)\)")
 
 
-def _test_name(test):
+def unit_test_name(test):
     m = _test_description.match(str(test))
     return "%s.%s" % (m.group(2), m.group(1))
 
 
 class Runner(object):
-    def __init__(self, printer, options, loader):
-        self.options = options
+    def __init__(self, printer, loader):
         self.printer = printer
         self.loader = loader
-        self.result = unittest.TestResult()
+        self.tests_run = 0
+        self.errors = []
+        self.failures = []
         self.worker_factory = lambda caller: _Worker(caller, self.loader)
 
-    def all_test_names(self, suite):
-        names = []
-        if hasattr(suite, '_tests'):
-            for t in suite._tests:
-                names.extend(self.all_test_names(t))
-        else:
-            names.append(_test_name(suite))
-        return names
-
-    def run(self, suite):
-        run_start_time = time.time()
-        all_test_names = self.all_test_names(suite)
-
-        with message_pool.get(self, self.worker_factory, int(self.options.child_processes)) as pool:
-            pool.run(('test', test_name) for test_name in all_test_names)
+    def run(self, test_names, num_workers):
+        if not test_names:
+            return
+        num_workers = min(num_workers, len(test_names))
+        with message_pool.get(self, self.worker_factory, num_workers) as pool:
+            pool.run(('test', test_name) for test_name in test_names)
 
-        self.printer.print_result(self.result, time.time() - run_start_time)
-        return self.result
+    def handle(self, message_name, source, test_name=None, delay=None, failures=None, errors=None):
+        if message_name == 'did_spawn_worker':
+            return
 
-    def handle(self, message_name, source, test_name, delay=None, result=None):
         if message_name == 'started_test':
             self.printer.print_started_test(source, test_name)
             return
 
-        self.result.testsRun += 1
-        self.result.errors.extend(result.errors)
-        self.result.failures.extend(result.failures)
-        self.printer.print_finished_test(source, test_name, delay, result.failures, result.errors)
+        self.tests_run += 1
+        if failures:
+            self.failures.append((test_name, failures))
+        if errors:
+            self.errors.append((test_name, errors))
+        self.printer.print_finished_test(source, test_name, delay, failures, errors)
 
 
 class _Worker(object):
@@ -88,13 +78,8 @@ class _Worker(object):
         result = unittest.TestResult()
         start = time.time()
         self._caller.post('started_test', test_name)
-        self._loader.loadTestsFromName(test_name, None).run(result)
 
-        # The tests in the TestResult contain file objects and other unpicklable things; we only
-        # care about the test name, so we rewrite the result to replace the test with the test name.
-        # FIXME: We need an automated test for this, but I don't know how to write an automated
-        # test that will fail in this case that doesn't get picked up by test-webkitpy normally :(.
-        result.failures = [(_test_name(failure[0]), failure[1]) for failure in result.failures]
-        result.errors = [(_test_name(error[0]), error[1]) for error in result.errors]
-
-        self._caller.post('finished_test', test_name, time.time() - start, result)
+        # We will need to rework this if a test_name results in multiple tests.
+        self._loader.loadTestsFromName(test_name, None).run(result)
+        self._caller.post('finished_test', test_name, time.time() - start,
+            [failure[1] for failure in result.failures], [error[1] for error in result.errors])