test-webkitpy: run tests in parallel
authordpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Jul 2012 19:37:18 +0000 (19:37 +0000)
committerdpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Jul 2012 19:37:18 +0000 (19:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=91294

Reviewed by Ojan Vafai.

This change adds support for running tests in parallel. This is
not yet on by default, since the logging isn't very pretty w/
parallel tests.

Also, there are some (multiprocessing-related) tests that can't be
run in parallel and so we skip them in that situation; I need to
come up with a mechanism for dealing with this, since you
apparently can't use multiprocessing as both a parent and a
child process.

* Scripts/webkitpy/test/finder.py:
(Finder.find_names):
(Finder._default_names):
* Scripts/webkitpy/test/main.py:
(Tester._parse_args):
(Tester.run):
* Scripts/webkitpy/test/main_unittest.py:
(TesterTest.test_no_tests_found):
* Scripts/webkitpy/test/runner.py:
(Runner.run):
* Scripts/webkitpy/test/runner_unittest.py:
(RunnerTest.test_regular):
(RunnerTest.test_verbose):
(RunnerTest.test_timing):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@122750 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/webkitpy/test/finder.py
Tools/Scripts/webkitpy/test/main.py
Tools/Scripts/webkitpy/test/main_unittest.py
Tools/Scripts/webkitpy/test/runner.py
Tools/Scripts/webkitpy/test/runner_unittest.py

index aeaae51..1d06a76 100644 (file)
@@ -1,5 +1,37 @@
 2012-07-16  Dirk Pranke  <dpranke@chromium.org>
 
+        test-webkitpy: run tests in parallel
+        https://bugs.webkit.org/show_bug.cgi?id=91294
+
+        Reviewed by Ojan Vafai.
+
+        This change adds support for running tests in parallel. This is
+        not yet on by default, since the logging isn't very pretty w/
+        parallel tests.
+
+        Also, there are some (multiprocessing-related) tests that can't be
+        run in parallel and so we skip them in that situation; I need to
+        come up with a mechanism for dealing with this, since you
+        apparently can't use multiprocessing as both a parent and a
+        child process.
+
+        * Scripts/webkitpy/test/finder.py:
+        (Finder.find_names):
+        (Finder._default_names):
+        * Scripts/webkitpy/test/main.py:
+        (Tester._parse_args):
+        (Tester.run):
+        * Scripts/webkitpy/test/main_unittest.py:
+        (TesterTest.test_no_tests_found):
+        * Scripts/webkitpy/test/runner.py:
+        (Runner.run):
+        * Scripts/webkitpy/test/runner_unittest.py:
+        (RunnerTest.test_regular):
+        (RunnerTest.test_verbose):
+        (RunnerTest.test_timing):
+
+2012-07-16  Dirk Pranke  <dpranke@chromium.org>
+
         test-webkitpy: use message pools
         https://bugs.webkit.org/show_bug.cgi?id=91292
 
index 132072d..0b14f04 100644 (file)
@@ -101,7 +101,7 @@ class Finder(object):
                 return tree.to_module(path)
         return None
 
-    def find_names(self, args, skip_integrationtests, find_all):
+    def find_names(self, args, skip_integrationtests, find_all, skip_if_parallel=True):
         suffixes = ['_unittest.py']
         if not skip_integrationtests:
             suffixes.append('_integrationtest.py')
@@ -112,7 +112,7 @@ class Finder(object):
                 names.extend(self._find_names_for_arg(arg, suffixes))
             return names
 
-        return self._default_names(suffixes, find_all)
+        return self._default_names(suffixes, find_all, skip_if_parallel)
 
     def _find_names_for_arg(self, arg, suffixes):
         realpath = self.filesystem.realpath(arg)
@@ -145,7 +145,7 @@ class Finder(object):
                 return tree.find_modules(suffixes, path)
         return []
 
-    def _default_names(self, suffixes, find_all):
+    def _default_names(self, suffixes, find_all, skip_if_parallel):
         modules = []
         for tree in self.trees:
             modules.extend(tree.find_modules(suffixes))
@@ -165,6 +165,11 @@ class Finder(object):
                                    'webkitpy.tool')
                 self._exclude(modules, win32_blacklist, 'fail horribly on win32', 54526)
 
+        if skip_if_parallel:
+            serial_tests = ('webkitpy.common.system.executive_unittest.ExecutiveTest.test_running_in_parallel',
+                            'webkitpy.test')
+            self._exclude(modules, serial_tests, 'tests fail when run in parallel with other tests', 12345)
+
         return modules
 
     def _exclude(self, modules, module_prefixes, reason, bugid):
index 2048d9e..abb297b 100644 (file)
@@ -63,6 +63,8 @@ class Tester(object):
                           help='do not run the integration tests')
         parser.add_option('-p', '--pass-through', action='store_true', default=False,
                           help='be debugger friendly by passing captured output through to the system')
+        parser.add_option('-j', '--child-processes', action='store', type='int', default=1,
+                          help='number of tests to run in parallel')
 
         parser.epilog = ('[args...] is an optional list of modules, test_classes, or individual tests. '
                          'If no args are given, all the tests will be run.')
@@ -75,7 +77,7 @@ class Tester(object):
 
         self.finder.clean_trees()
 
-        names = self.finder.find_names(args, self._options.skip_integrationtests, self._options.all)
+        names = self.finder.find_names(args, self._options.skip_integrationtests, self._options.all, self._options.child_processes != 1)
         if not names:
             _log.error('No tests to run')
             return False
index 2cf6df4..61e49a7 100644 (file)
@@ -41,7 +41,7 @@ class TesterTest(unittest.TestCase):
         root_logger.handlers = []
 
         tester.printer.stream = errors
-        tester.finder.find_names = lambda args, skip_integration, run_all: []
+        tester.finder.find_names = lambda args, skip_integration, run_all, skip_if_parallel: []
         oc = OutputCapture()
         try:
             oc.capture_output()
index 861f0b6..f8f19b2 100644 (file)
@@ -52,7 +52,7 @@ class Runner(object):
         run_start_time = time.time()
         all_test_names = self.all_test_names(suite)
 
-        with message_pool.get(self, self.worker_factory, 1) as pool:
+        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)
 
         self.printer.print_result(self.result, time.time() - run_start_time)
index a4030a6..9436b8c 100644 (file)
@@ -83,13 +83,13 @@ class RunnerTest(unittest.TestCase):
         # FIXME: check the output from the test
 
     def test_regular(self):
-        self.assert_run(MockOptions(verbose=0, timing=False))
+        self.assert_run(MockOptions(verbose=0, timing=False, child_processes=1))
 
     def test_verbose(self):
-        self.assert_run(MockOptions(verbose=1, timing=False))
+        self.assert_run(MockOptions(verbose=1, timing=False, child_processes=1))
 
     def test_timing(self):
-        self.assert_run(MockOptions(verbose=0, timing=True))
+        self.assert_run(MockOptions(verbose=0, timing=True, child_processes=1))
 
 
 if __name__ == '__main__':