diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-07-16 14:51:15 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-07-16 14:51:15 +0200 |
commit | 4e6b3a206fa4ad8bb0b664f7674c9a70376d6e26 (patch) | |
tree | 7bb9ad7e31c24d1cf1707e03e6f1a80f6d033951 /Tools/Scripts/webkitpy/test | |
parent | 3977e3d2f72f7fe2c887c1ec0e0c342e1d169f42 (diff) | |
download | qtwebkit-4e6b3a206fa4ad8bb0b664f7674c9a70376d6e26.tar.gz |
Imported WebKit commit 953baa67aa07087b6ecd4199351ec554c724e27d (http://svn.webkit.org/repository/webkit/trunk@122676)
Diffstat (limited to 'Tools/Scripts/webkitpy/test')
-rw-r--r-- | Tools/Scripts/webkitpy/test/finder.py (renamed from Tools/Scripts/webkitpy/test/test_finder.py) | 7 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/test/finder_unittest.py (renamed from Tools/Scripts/webkitpy/test/test_finder_unittest.py) | 8 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/test/main.py | 124 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/test/main_unittest.py | 2 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/test/printer.py | 182 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/test/runner.py | 71 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/test/runner_unittest.py | 9 |
7 files changed, 217 insertions, 186 deletions
diff --git a/Tools/Scripts/webkitpy/test/test_finder.py b/Tools/Scripts/webkitpy/test/finder.py index 3a90197e9..132072d82 100644 --- a/Tools/Scripts/webkitpy/test/test_finder.py +++ b/Tools/Scripts/webkitpy/test/finder.py @@ -31,7 +31,7 @@ import sys _log = logging.getLogger(__name__) -class TestDirectoryTree(object): +class _DirectoryTree(object): def __init__(self, filesystem, top_directory, starting_subdirectory): self.filesystem = filesystem self.top_directory = filesystem.realpath(top_directory) @@ -63,7 +63,6 @@ class TestDirectoryTree(object): return realpath.replace(self.top_directory + self.filesystem.sep, '') return None - def clean(self): """Delete all .pyc files in the tree that have no matching .py file.""" _log.debug("Cleaning orphaned *.pyc files from: %s" % self.search_directory) @@ -74,13 +73,13 @@ class TestDirectoryTree(object): self.filesystem.remove(filename) -class TestFinder(object): +class Finder(object): def __init__(self, filesystem): self.filesystem = filesystem self.trees = [] def add_tree(self, top_directory, starting_subdirectory=None): - self.trees.append(TestDirectoryTree(self.filesystem, top_directory, starting_subdirectory)) + self.trees.append(_DirectoryTree(self.filesystem, top_directory, starting_subdirectory)) def additional_paths(self, paths): return [tree.top_directory for tree in self.trees if tree.top_directory not in paths] diff --git a/Tools/Scripts/webkitpy/test/test_finder_unittest.py b/Tools/Scripts/webkitpy/test/finder_unittest.py index 5b6b3b030..09048b159 100644 --- a/Tools/Scripts/webkitpy/test/test_finder_unittest.py +++ b/Tools/Scripts/webkitpy/test/finder_unittest.py @@ -25,10 +25,10 @@ import unittest from webkitpy.common.system.filesystem_mock import MockFileSystem from webkitpy.common.system.outputcapture import OutputCapture -from webkitpy.test.test_finder import TestFinder +from webkitpy.test.finder import Finder -class TestFinderTest(unittest.TestCase): +class FinderTest(unittest.TestCase): def setUp(self): files = { '/foo/bar/baz.py': '', @@ -40,7 +40,7 @@ class TestFinderTest(unittest.TestCase): '/tmp/another_unittest.py': '', } self.fs = MockFileSystem(files) - self.finder = TestFinder(self.fs) + self.finder = Finder(self.fs) self.finder.add_tree('/foo', 'bar') self.finder.add_tree('/foo2') @@ -49,7 +49,7 @@ class TestFinderTest(unittest.TestCase): self.root_logger = logging.getLogger() self.log_handler = None for h in self.root_logger.handlers: - if getattr(h, 'name', None) == 'webkitpy.test.main': + if getattr(h, 'name', None) == 'webkitpy.test.printer': self.log_handler = h break if self.log_handler: diff --git a/Tools/Scripts/webkitpy/test/main.py b/Tools/Scripts/webkitpy/test/main.py index c5dc39433..2048d9e59 100644 --- a/Tools/Scripts/webkitpy/test/main.py +++ b/Tools/Scripts/webkitpy/test/main.py @@ -25,24 +25,24 @@ import logging import optparse -import os import StringIO import sys import traceback import unittest from webkitpy.common.system.filesystem import FileSystem -from webkitpy.common.system import outputcapture -from webkitpy.test.test_finder import TestFinder -from webkitpy.test.runner import TestRunner +from webkitpy.test.finder import Finder +from webkitpy.test.printer import Printer +from webkitpy.test.runner import Runner _log = logging.getLogger(__name__) class Tester(object): def __init__(self, filesystem=None): - self.finder = TestFinder(filesystem or FileSystem()) - self.stream = sys.stderr + self.finder = Finder(filesystem or FileSystem()) + self.printer = Printer(sys.stderr) + self._options = None def add_tree(self, top_directory, starting_subdirectory=None): self.finder.add_tree(top_directory, starting_subdirectory) @@ -50,13 +50,13 @@ class Tester(object): def _parse_args(self): parser = optparse.OptionParser(usage='usage: %prog [options] [args...]') parser.add_option('-a', '--all', action='store_true', default=False, - help='run all the tests'), + help='run all the tests') parser.add_option('-c', '--coverage', action='store_true', default=False, - help='generate code coverage info (requires http://pypi.python.org/pypi/coverage)'), + help='generate code coverage info (requires http://pypi.python.org/pypi/coverage)') parser.add_option('-q', '--quiet', action='store_true', default=False, - help='run quietly (errors, warnings, and progress only)'), + help='run quietly (errors, warnings, and progress only)') parser.add_option('-t', '--timing', action='store_true', default=False, - help='display per-test execution time (implies --verbose)'), + help='display per-test execution time (implies --verbose)') parser.add_option('-v', '--verbose', action='count', default=0, help='verbose output (specify once for individual test results, twice for debug messages)') parser.add_option('--skip-integrationtests', action='store_true', default=False, @@ -69,72 +69,9 @@ class Tester(object): return parser.parse_args() - def _configure(self, options): - self._options = options - - if options.timing: - # --timing implies --verbose - options.verbose = max(options.verbose, 1) - - log_level = logging.INFO - if options.quiet: - log_level = logging.WARNING - elif options.verbose == 2: - log_level = logging.DEBUG - self._configure_logging(log_level) - - def _configure_logging(self, log_level): - """Configure the root logger. - - Configure the root logger not to log any messages from webkitpy -- - except for messages from the autoinstall module. Also set the - logging level as described below. - """ - handler = logging.StreamHandler(self.stream) - # We constrain the level on the handler rather than on the root - # logger itself. This is probably better because the handler is - # configured and known only to this module, whereas the root logger - # is an object shared (and potentially modified) by many modules. - # Modifying the handler, then, is less intrusive and less likely to - # interfere with modifications made by other modules (e.g. in unit - # tests). - handler.name = __name__ - handler.setLevel(log_level) - formatter = logging.Formatter("%(message)s") - handler.setFormatter(formatter) - - logger = logging.getLogger() - logger.addHandler(handler) - logger.setLevel(logging.NOTSET) - - # Filter out most webkitpy messages. - # - # Messages can be selectively re-enabled for this script by updating - # this method accordingly. - def filter(record): - """Filter out autoinstall and non-third-party webkitpy messages.""" - # FIXME: Figure out a way not to use strings here, for example by - # using syntax like webkitpy.test.__name__. We want to be - # sure not to import any non-Python 2.4 code, though, until - # after the version-checking code has executed. - if (record.name.startswith("webkitpy.common.system.autoinstall") or - record.name.startswith("webkitpy.test")): - return True - if record.name.startswith("webkitpy"): - return False - return True - - testing_filter = logging.Filter() - testing_filter.filter = filter - - # Display a message so developers are not mystified as to why - # logging does not work in the unit tests. - _log.info("Suppressing most webkitpy logging while running unit tests.") - handler.addFilter(testing_filter) - def run(self): - options, args = self._parse_args() - self._configure(options) + self._options, args = self._parse_args() + self.printer.configure(self._options) self.finder.clean_trees() @@ -149,7 +86,7 @@ class Tester(object): if self._options.coverage: try: import webkitpy.thirdparty.autoinstalled.coverage as coverage - except ImportError, e: + except ImportError: _log.error("Failed to import 'coverage'; can't generate coverage numbers.") return False cov = coverage.coverage() @@ -169,7 +106,7 @@ class Tester(object): # produces lousy error messages for bad modules. try: __import__(name) - except ImportError, e: + except ImportError: _log.fatal('Failed to import %s:' % name) self._log_exception() return False @@ -177,11 +114,9 @@ class Tester(object): suites.append(loader.loadTestsFromName(name, None)) test_suite = unittest.TestSuite(suites) - test_runner = TestRunner(self.stream, self._options, loader) + test_runner = Runner(self.printer, self._options, loader) _log.debug("Running the tests.") - if self._options.pass_through: - outputcapture.OutputCapture.stream_wrapper = _CaptureAndPassThroughStream result = test_runner.run(test_suite) if self._options.coverage: cov.stop() @@ -194,32 +129,3 @@ class Tester(object): traceback.print_exc(file=s) for l in s.buflist: _log.error(' ' + l.rstrip()) - - -class _CaptureAndPassThroughStream(object): - def __init__(self, stream): - self._buffer = StringIO.StringIO() - self._stream = stream - - def write(self, msg): - self._stream.write(msg) - - # Note that we don't want to capture any output generated by the debugger - # because that could cause the results of capture_output() to be invalid. - if not self._message_is_from_pdb(): - self._buffer.write(msg) - - def _message_is_from_pdb(self): - # We will assume that if the pdb module is in the stack then the output - # is being generated by the python debugger (or the user calling something - # from inside the debugger). - import inspect - import pdb - stack = inspect.stack() - return any(frame[1] == pdb.__file__.replace('.pyc', '.py') for frame in stack) - - def flush(self): - self._stream.flush() - - def getvalue(self): - return self._buffer.getvalue() diff --git a/Tools/Scripts/webkitpy/test/main_unittest.py b/Tools/Scripts/webkitpy/test/main_unittest.py index 1a60beef3..2cf6df4a2 100644 --- a/Tools/Scripts/webkitpy/test/main_unittest.py +++ b/Tools/Scripts/webkitpy/test/main_unittest.py @@ -40,7 +40,7 @@ class TesterTest(unittest.TestCase): root_handlers = root_logger.handlers root_logger.handlers = [] - tester.stream = errors + tester.printer.stream = errors tester.finder.find_names = lambda args, skip_integration, run_all: [] oc = OutputCapture() try: diff --git a/Tools/Scripts/webkitpy/test/printer.py b/Tools/Scripts/webkitpy/test/printer.py new file mode 100644 index 000000000..77e28b8d1 --- /dev/null +++ b/Tools/Scripts/webkitpy/test/printer.py @@ -0,0 +1,182 @@ +# Copyright (C) 2012 Google, Inc. +# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import logging +import re +import StringIO + +from webkitpy.common.system import outputcapture + +_log = logging.getLogger(__name__) + + +class Printer(object): + def __init__(self, stream, options=None): + self.stream = stream + self.options = options + self.test_description = re.compile("(\w+) \(([\w.]+)\)") + + def test_name(self, test): + m = self.test_description.match(str(test)) + return "%s.%s" % (m.group(2), m.group(1)) + + def configure(self, options): + self.options = options + + if options.timing: + # --timing implies --verbose + options.verbose = max(options.verbose, 1) + + log_level = logging.INFO + if options.quiet: + log_level = logging.WARNING + elif options.verbose == 2: + log_level = logging.DEBUG + + handler = logging.StreamHandler(self.stream) + # We constrain the level on the handler rather than on the root + # logger itself. This is probably better because the handler is + # configured and known only to this module, whereas the root logger + # is an object shared (and potentially modified) by many modules. + # Modifying the handler, then, is less intrusive and less likely to + # interfere with modifications made by other modules (e.g. in unit + # tests). + handler.name = __name__ + handler.setLevel(log_level) + formatter = logging.Formatter("%(message)s") + handler.setFormatter(formatter) + + logger = logging.getLogger() + logger.addHandler(handler) + logger.setLevel(logging.NOTSET) + + # Filter out most webkitpy messages. + # + # Messages can be selectively re-enabled for this script by updating + # this method accordingly. + def filter_records(record): + """Filter out autoinstall and non-third-party webkitpy messages.""" + # FIXME: Figure out a way not to use strings here, for example by + # using syntax like webkitpy.test.__name__. We want to be + # sure not to import any non-Python 2.4 code, though, until + # after the version-checking code has executed. + if (record.name.startswith("webkitpy.common.system.autoinstall") or + record.name.startswith("webkitpy.test")): + return True + if record.name.startswith("webkitpy"): + return False + return True + + testing_filter = logging.Filter() + testing_filter.filter = filter_records + + # Display a message so developers are not mystified as to why + # logging does not work in the unit tests. + _log.info("Suppressing most webkitpy logging while running unit tests.") + handler.addFilter(testing_filter) + + if self.options.pass_through: + outputcapture.OutputCapture.stream_wrapper = _CaptureAndPassThroughStream + + def print_started_test(self, test_name): + if self.options.verbose: + self.stream.write(test_name) + + def print_finished_test(self, result, test_name, test_time, failure, err): + timing = '' + if self.options.timing: + timing = ' %.4fs' % test_time + if self.options.verbose: + if failure: + msg = ' failed' + elif err: + msg = ' erred' + else: + msg = ' passed' + self.stream.write(msg + timing + '\n') + else: + if failure: + msg = 'F' + elif err: + msg = 'E' + else: + msg = '.' + self.stream.write(msg) + + def print_result(self, result, run_time): + self.stream.write('\n') + + for (test, err) in result.errors: + self.stream.write("=" * 80 + '\n') + self.stream.write("ERROR: " + self.test_name(test) + '\n') + self.stream.write("-" * 80 + '\n') + for line in err.splitlines(): + self.stream.write(line + '\n') + self.stream.write('\n') + + for (test, failure) in result.failures: + self.stream.write("=" * 80 + '\n') + self.stream.write("FAILURE: " + self.test_name(test) + '\n') + self.stream.write("-" * 80 + '\n') + for line in failure.splitlines(): + self.stream.write(line + '\n') + self.stream.write('\n') + + self.stream.write('-' * 80 + '\n') + self.stream.write('Ran %d test%s in %.3fs\n' % + (result.testsRun, result.testsRun != 1 and "s" or "", run_time)) + + if result.wasSuccessful(): + self.stream.write('\nOK\n') + else: + self.stream.write('FAILED (failures=%d, errors=%d)\n' % + (len(result.failures), len(result.errors))) + + +class _CaptureAndPassThroughStream(object): + def __init__(self, stream): + self._buffer = StringIO.StringIO() + self._stream = stream + + def write(self, msg): + self._stream.write(msg) + + # Note that we don't want to capture any output generated by the debugger + # because that could cause the results of capture_output() to be invalid. + if not self._message_is_from_pdb(): + self._buffer.write(msg) + + def _message_is_from_pdb(self): + # We will assume that if the pdb module is in the stack then the output + # is being generated by the python debugger (or the user calling something + # from inside the debugger). + import inspect + import pdb + stack = inspect.stack() + return any(frame[1] == pdb.__file__.replace('.pyc', '.py') for frame in stack) + + def flush(self): + self._stream.flush() + + def getvalue(self): + return self._buffer.getvalue() diff --git a/Tools/Scripts/webkitpy/test/runner.py b/Tools/Scripts/webkitpy/test/runner.py index e190f2cd4..9c952075e 100644 --- a/Tools/Scripts/webkitpy/test/runner.py +++ b/Tools/Scripts/webkitpy/test/runner.py @@ -23,7 +23,6 @@ """code to actually run a list of python tests.""" import logging -import re import time import unittest @@ -31,16 +30,11 @@ import unittest _log = logging.getLogger(__name__) -class TestRunner(object): - def __init__(self, stream, options, loader): +class Runner(object): + def __init__(self, printer, options, loader): self.options = options - self.stream = stream + self.printer = printer self.loader = loader - self.test_description = re.compile("(\w+) \(([\w.]+)\)") - - def test_name(self, test): - m = self.test_description.match(str(test)) - return "%s.%s" % (m.group(2), m.group(1)) def all_test_names(self, suite): names = [] @@ -48,7 +42,7 @@ class TestRunner(object): for t in suite._tests: names.extend(self.all_test_names(t)) else: - names.append(self.test_name(suite)) + names.append(self.printer.test_name(suite)) return names def run(self, suite): @@ -57,8 +51,7 @@ class TestRunner(object): result = unittest.TestResult() stop = run_start_time for test_name in all_test_names: - if self.options.verbose: - self.stream.write(test_name) + self.printer.print_started_test(test_name) num_failures = len(result.failures) num_errors = len(result.errors) @@ -75,58 +68,8 @@ class TestRunner(object): failure = result.failures[num_failures][1] elif len(result.errors) > num_errors: err = result.errors[num_errors][1] - self.write_result(result, test_name, stop - start, failure, err) + self.printer.print_finished_test(result, test_name, stop - start, failure, err) - self.write_summary(result, stop - run_start_time) + self.printer.print_result(result, stop - run_start_time) return result - - def write_result(self, result, test_name, test_time, failure=None, err=None): - timing = '' - if self.options.timing: - timing = ' %.4fs' % test_time - if self.options.verbose: - if failure: - msg = ' failed' - elif err: - msg = ' erred' - else: - msg = ' passed' - self.stream.write(msg + timing + '\n') - else: - if failure: - msg = 'F' - elif err: - msg = 'E' - else: - msg = '.' - self.stream.write(msg) - - def write_summary(self, result, run_time): - self.stream.write('\n') - - for (test, err) in result.errors: - self.stream.write("=" * 80 + '\n') - self.stream.write("ERROR: " + self.test_name(test) + '\n') - self.stream.write("-" * 80 + '\n') - for line in err.splitlines(): - self.stream.write(line + '\n') - self.stream.write('\n') - - for (test, failure) in result.failures: - self.stream.write("=" * 80 + '\n') - self.stream.write("FAILURE: " + self.test_name(test) + '\n') - self.stream.write("-" * 80 + '\n') - for line in failure.splitlines(): - self.stream.write(line + '\n') - self.stream.write('\n') - - self.stream.write('-' * 80 + '\n') - self.stream.write('Ran %d test%s in %.3fs\n' % - (result.testsRun, result.testsRun != 1 and "s" or "", run_time)) - - if result.wasSuccessful(): - self.stream.write('\nOK\n') - else: - self.stream.write('FAILED (failures=%d, errors=%d)\n' % - (len(result.failures), len(result.errors))) diff --git a/Tools/Scripts/webkitpy/test/runner_unittest.py b/Tools/Scripts/webkitpy/test/runner_unittest.py index e2ea31aa1..1cf0146fb 100644 --- a/Tools/Scripts/webkitpy/test/runner_unittest.py +++ b/Tools/Scripts/webkitpy/test/runner_unittest.py @@ -25,7 +25,8 @@ import StringIO import unittest from webkitpy.tool.mocktool import MockOptions -from webkitpy.test.runner import TestRunner +from webkitpy.test.printer import Printer +from webkitpy.test.runner import Runner class FakeModuleSuite(object): @@ -74,7 +75,7 @@ class RunnerTest(unittest.TestCase): loader = FakeLoader(('test1 (Foo)', '.', ''), ('test2 (Foo)', 'F', 'test2\nfailed'), ('test3 (Foo)', 'E', 'test3\nerred')) - result = TestRunner(stream, options, loader).run(loader.top_suite()) + result = Runner(Printer(stream, options), options, loader).run(loader.top_suite()) self.assertFalse(result.wasSuccessful()) self.assertEquals(result.testsRun, 3) self.assertEquals(len(result.failures), 1) @@ -87,7 +88,7 @@ class RunnerTest(unittest.TestCase): loader = FakeLoader(('test1 (Foo)', '.', ''), ('test2 (Foo)', 'F', 'test2\nfailed'), ('test3 (Foo)', 'E', 'test3\nerred')) - result = TestRunner(stream, options, loader).run(loader.top_suite()) + result = Runner(Printer(stream, options), options, loader).run(loader.top_suite()) self.assertFalse(result.wasSuccessful()) self.assertEquals(result.testsRun, 3) self.assertEquals(len(result.failures), 1) @@ -100,7 +101,7 @@ class RunnerTest(unittest.TestCase): loader = FakeLoader(('test1 (Foo)', '.', ''), ('test2 (Foo)', 'F', 'test2\nfailed'), ('test3 (Foo)', 'E', 'test3\nerred')) - result = TestRunner(stream, options, loader).run(loader.top_suite()) + result = Runner(Printer(stream, options), options, loader).run(loader.top_suite()) self.assertFalse(result.wasSuccessful()) self.assertEquals(result.testsRun, 3) self.assertEquals(len(result.failures), 1) |