Changeset 122643 in webkit


Ignore:
Timestamp:
Jul 13, 2012 4:36:29 PM (12 years ago)
Author:
dpranke@chromium.org
Message:

webkitpy: split printing/logging code for test-webkitpy out into a new class
https://bugs.webkit.org/show_bug.cgi?id=91282

Reviewed by Ojan Vafai.

This patch is the first step at splitting all of the
printing/logging code out separately from the actual
test-running code.

This is just moving stuff around; no new functionality and no
new tests needed.

  • Scripts/webkitpy/test/finder_unittest.py:

(FinderTest.setUp):

  • Scripts/webkitpy/test/main.py:

(Tester.init):
(Tester._parse_args):
(Tester.run):
(Tester._run_tests):
(Tester._log_exception):

  • Scripts/webkitpy/test/main_unittest.py:

(TesterTest.test_no_tests_found):

  • Scripts/webkitpy/test/printer.py: Added.

(Printer):
(Printer.init):
(Printer.configure):
(Printer.configure.filter):
(_CaptureAndPassThroughStream):
(_CaptureAndPassThroughStream.init):
(_CaptureAndPassThroughStream.write):
(_CaptureAndPassThroughStream._message_is_from_pdb):
(_CaptureAndPassThroughStream.flush):
(_CaptureAndPassThroughStream.getvalue):

Location:
trunk/Tools
Files:
4 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r122632 r122643  
     12012-07-13  Dirk Pranke  <dpranke@chromium.org>
     2
     3        webkitpy: split printing/logging code for test-webkitpy out into a new class
     4        https://bugs.webkit.org/show_bug.cgi?id=91282
     5
     6        Reviewed by Ojan Vafai.
     7
     8        This patch is the first step at splitting all of the
     9        printing/logging code out separately from the actual
     10        test-running code.
     11
     12        This is just moving stuff around; no new functionality and no
     13        new tests needed.
     14
     15        * Scripts/webkitpy/test/finder_unittest.py:
     16        (FinderTest.setUp):
     17        * Scripts/webkitpy/test/main.py:
     18        (Tester.__init__):
     19        (Tester._parse_args):
     20        (Tester.run):
     21        (Tester._run_tests):
     22        (Tester._log_exception):
     23        * Scripts/webkitpy/test/main_unittest.py:
     24        (TesterTest.test_no_tests_found):
     25        * Scripts/webkitpy/test/printer.py: Added.
     26        (Printer):
     27        (Printer.__init__):
     28        (Printer.configure):
     29        (Printer.configure.filter):
     30        (_CaptureAndPassThroughStream):
     31        (_CaptureAndPassThroughStream.__init__):
     32        (_CaptureAndPassThroughStream.write):
     33        (_CaptureAndPassThroughStream._message_is_from_pdb):
     34        (_CaptureAndPassThroughStream.flush):
     35        (_CaptureAndPassThroughStream.getvalue):
     36
    1372012-07-13  James Simonsen  <simonjam@chromium.org>
    238
  • trunk/Tools/Scripts/webkitpy/test/finder_unittest.py

    r122536 r122643  
    5050        self.log_handler = None
    5151        for h in self.root_logger.handlers:
    52             if getattr(h, 'name', None) == 'webkitpy.test.main':
     52            if getattr(h, 'name', None) == 'webkitpy.test.printer':
    5353                self.log_handler = h
    5454                break
  • trunk/Tools/Scripts/webkitpy/test/main.py

    r122548 r122643  
    2626import logging
    2727import optparse
    28 import os
    2928import StringIO
    3029import sys
     
    3332
    3433from webkitpy.common.system.filesystem import FileSystem
    35 from webkitpy.common.system import outputcapture
    3634from webkitpy.test.finder import Finder
     35from webkitpy.test.printer import Printer
    3736from webkitpy.test.runner import Runner
    3837
     
    4342    def __init__(self, filesystem=None):
    4443        self.finder = Finder(filesystem or FileSystem())
    45         self.stream = sys.stderr
     44        self.printer = Printer(sys.stderr)
     45        self._options = None
    4646
    4747    def add_tree(self, top_directory, starting_subdirectory=None):
     
    5151        parser = optparse.OptionParser(usage='usage: %prog [options] [args...]')
    5252        parser.add_option('-a', '--all', action='store_true', default=False,
    53                           help='run all the tests'),
     53                          help='run all the tests')
    5454        parser.add_option('-c', '--coverage', action='store_true', default=False,
    55                           help='generate code coverage info (requires http://pypi.python.org/pypi/coverage)'),
     55                          help='generate code coverage info (requires http://pypi.python.org/pypi/coverage)')
    5656        parser.add_option('-q', '--quiet', action='store_true', default=False,
    57                           help='run quietly (errors, warnings, and progress only)'),
     57                          help='run quietly (errors, warnings, and progress only)')
    5858        parser.add_option('-t', '--timing', action='store_true', default=False,
    59                           help='display per-test execution time (implies --verbose)'),
     59                          help='display per-test execution time (implies --verbose)')
    6060        parser.add_option('-v', '--verbose', action='count', default=0,
    6161                          help='verbose output (specify once for individual test results, twice for debug messages)')
     
    7070        return parser.parse_args()
    7171
    72     def _configure(self, options):
    73         self._options = options
    74 
    75         if options.timing:
    76             # --timing implies --verbose
    77             options.verbose = max(options.verbose, 1)
    78 
    79         log_level = logging.INFO
    80         if options.quiet:
    81             log_level = logging.WARNING
    82         elif options.verbose == 2:
    83             log_level = logging.DEBUG
    84         self._configure_logging(log_level)
    85 
    86     def _configure_logging(self, log_level):
    87         """Configure the root logger.
    88 
    89         Configure the root logger not to log any messages from webkitpy --
    90         except for messages from the autoinstall module.  Also set the
    91         logging level as described below.
    92         """
    93         handler = logging.StreamHandler(self.stream)
    94         # We constrain the level on the handler rather than on the root
    95         # logger itself.  This is probably better because the handler is
    96         # configured and known only to this module, whereas the root logger
    97         # is an object shared (and potentially modified) by many modules.
    98         # Modifying the handler, then, is less intrusive and less likely to
    99         # interfere with modifications made by other modules (e.g. in unit
    100         # tests).
    101         handler.name = __name__
    102         handler.setLevel(log_level)
    103         formatter = logging.Formatter("%(message)s")
    104         handler.setFormatter(formatter)
    105 
    106         logger = logging.getLogger()
    107         logger.addHandler(handler)
    108         logger.setLevel(logging.NOTSET)
    109 
    110         # Filter out most webkitpy messages.
    111         #
    112         # Messages can be selectively re-enabled for this script by updating
    113         # this method accordingly.
    114         def filter(record):
    115             """Filter out autoinstall and non-third-party webkitpy messages."""
    116             # FIXME: Figure out a way not to use strings here, for example by
    117             #        using syntax like webkitpy.test.__name__.  We want to be
    118             #        sure not to import any non-Python 2.4 code, though, until
    119             #        after the version-checking code has executed.
    120             if (record.name.startswith("webkitpy.common.system.autoinstall") or
    121                 record.name.startswith("webkitpy.test")):
    122                 return True
    123             if record.name.startswith("webkitpy"):
    124                 return False
    125             return True
    126 
    127         testing_filter = logging.Filter()
    128         testing_filter.filter = filter
    129 
    130         # Display a message so developers are not mystified as to why
    131         # logging does not work in the unit tests.
    132         _log.info("Suppressing most webkitpy logging while running unit tests.")
    133         handler.addFilter(testing_filter)
    134 
    13572    def run(self):
    136         options, args = self._parse_args()
    137         self._configure(options)
     73        self._options, args = self._parse_args()
     74        self.printer.configure(self._options)
    13875
    13976        self.finder.clean_trees()
     
    15087            try:
    15188                import webkitpy.thirdparty.autoinstalled.coverage as coverage
    152             except ImportError, e:
     89            except ImportError:
    15390                _log.error("Failed to import 'coverage'; can't generate coverage numbers.")
    15491                return False
     
    170107                try:
    171108                    __import__(name)
    172                 except ImportError, e:
     109                except ImportError:
    173110                    _log.fatal('Failed to import %s:' % name)
    174111                    self._log_exception()
     
    178115
    179116        test_suite = unittest.TestSuite(suites)
    180         test_runner = Runner(self.stream, self._options, loader)
     117        test_runner = Runner(self.printer.stream, self._options, loader)
    181118
    182119        _log.debug("Running the tests.")
    183         if self._options.pass_through:
    184             outputcapture.OutputCapture.stream_wrapper = _CaptureAndPassThroughStream
    185120        result = test_runner.run(test_suite)
    186121        if self._options.coverage:
     
    195130        for l in s.buflist:
    196131            _log.error('  ' + l.rstrip())
    197 
    198 
    199 class _CaptureAndPassThroughStream(object):
    200     def __init__(self, stream):
    201         self._buffer = StringIO.StringIO()
    202         self._stream = stream
    203 
    204     def write(self, msg):
    205         self._stream.write(msg)
    206 
    207         # Note that we don't want to capture any output generated by the debugger
    208         # because that could cause the results of capture_output() to be invalid.
    209         if not self._message_is_from_pdb():
    210             self._buffer.write(msg)
    211 
    212     def _message_is_from_pdb(self):
    213         # We will assume that if the pdb module is in the stack then the output
    214         # is being generated by the python debugger (or the user calling something
    215         # from inside the debugger).
    216         import inspect
    217         import pdb
    218         stack = inspect.stack()
    219         return any(frame[1] == pdb.__file__.replace('.pyc', '.py') for frame in stack)
    220 
    221     def flush(self):
    222         self._stream.flush()
    223 
    224     def getvalue(self):
    225         return self._buffer.getvalue()
  • trunk/Tools/Scripts/webkitpy/test/main_unittest.py

    r119443 r122643  
    4141        root_logger.handlers = []
    4242
    43         tester.stream = errors
     43        tester.printer.stream = errors
    4444        tester.finder.find_names = lambda args, skip_integration, run_all: []
    4545        oc = OutputCapture()
  • trunk/Tools/Scripts/webkitpy/test/printer.py

    r122641 r122643  
    2222# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2323
    24 """unit testing code for webkitpy."""
     24import logging
     25import StringIO
    2526
    26 import logging
    27 import optparse
    28 import os
    29 import StringIO
    30 import sys
    31 import traceback
    32 import unittest
    33 
    34 from webkitpy.common.system.filesystem import FileSystem
    3527from webkitpy.common.system import outputcapture
    36 from webkitpy.test.finder import Finder
    37 from webkitpy.test.runner import Runner
    3828
    3929_log = logging.getLogger(__name__)
    4030
    4131
    42 class Tester(object):
    43     def __init__(self, filesystem=None):
    44         self.finder = Finder(filesystem or FileSystem())
    45         self.stream = sys.stderr
     32class Printer(object):
     33    def __init__(self, stream, options=None):
     34        self.stream = stream
     35        self.options = options
    4636
    47     def add_tree(self, top_directory, starting_subdirectory=None):
    48         self.finder.add_tree(top_directory, starting_subdirectory)
    49 
    50     def _parse_args(self):
    51         parser = optparse.OptionParser(usage='usage: %prog [options] [args...]')
    52         parser.add_option('-a', '--all', action='store_true', default=False,
    53                           help='run all the tests'),
    54         parser.add_option('-c', '--coverage', action='store_true', default=False,
    55                           help='generate code coverage info (requires http://pypi.python.org/pypi/coverage)'),
    56         parser.add_option('-q', '--quiet', action='store_true', default=False,
    57                           help='run quietly (errors, warnings, and progress only)'),
    58         parser.add_option('-t', '--timing', action='store_true', default=False,
    59                           help='display per-test execution time (implies --verbose)'),
    60         parser.add_option('-v', '--verbose', action='count', default=0,
    61                           help='verbose output (specify once for individual test results, twice for debug messages)')
    62         parser.add_option('--skip-integrationtests', action='store_true', default=False,
    63                           help='do not run the integration tests')
    64         parser.add_option('-p', '--pass-through', action='store_true', default=False,
    65                           help='be debugger friendly by passing captured output through to the system')
    66 
    67         parser.epilog = ('[args...] is an optional list of modules, test_classes, or individual tests. '
    68                          'If no args are given, all the tests will be run.')
    69 
    70         return parser.parse_args()
    71 
    72     def _configure(self, options):
    73         self._options = options
     37    def configure(self, options):
     38        self.options = options
    7439
    7540        if options.timing:
     
    8247        elif options.verbose == 2:
    8348            log_level = logging.DEBUG
    84         self._configure_logging(log_level)
    8549
    86     def _configure_logging(self, log_level):
    87         """Configure the root logger.
    88 
    89         Configure the root logger not to log any messages from webkitpy --
    90         except for messages from the autoinstall module.  Also set the
    91         logging level as described below.
    92         """
    9350        handler = logging.StreamHandler(self.stream)
    9451        # We constrain the level on the handler rather than on the root
     
    11269        # Messages can be selectively re-enabled for this script by updating
    11370        # this method accordingly.
    114         def filter(record):
     71        def filter_records(record):
    11572            """Filter out autoinstall and non-third-party webkitpy messages."""
    11673            # FIXME: Figure out a way not to use strings here, for example by
     
    12683
    12784        testing_filter = logging.Filter()
    128         testing_filter.filter = filter
     85        testing_filter.filter = filter_records
    12986
    13087        # Display a message so developers are not mystified as to why
     
    13390        handler.addFilter(testing_filter)
    13491
    135     def run(self):
    136         options, args = self._parse_args()
    137         self._configure(options)
    138 
    139         self.finder.clean_trees()
    140 
    141         names = self.finder.find_names(args, self._options.skip_integrationtests, self._options.all)
    142         if not names:
    143             _log.error('No tests to run')
    144             return False
    145 
    146         return self._run_tests(names)
    147 
    148     def _run_tests(self, names):
    149         if self._options.coverage:
    150             try:
    151                 import webkitpy.thirdparty.autoinstalled.coverage as coverage
    152             except ImportError, e:
    153                 _log.error("Failed to import 'coverage'; can't generate coverage numbers.")
    154                 return False
    155             cov = coverage.coverage()
    156             cov.start()
    157 
    158         # Make sure PYTHONPATH is set up properly.
    159         sys.path = self.finder.additional_paths(sys.path) + sys.path
    160 
    161         _log.debug("Loading the tests...")
    162 
    163         loader = unittest.defaultTestLoader
    164         suites = []
    165         for name in names:
    166             if self.finder.is_module(name):
    167                 # if we failed to load a name and it looks like a module,
    168                 # try importing it directly, because loadTestsFromName()
    169                 # produces lousy error messages for bad modules.
    170                 try:
    171                     __import__(name)
    172                 except ImportError, e:
    173                     _log.fatal('Failed to import %s:' % name)
    174                     self._log_exception()
    175                     return False
    176 
    177             suites.append(loader.loadTestsFromName(name, None))
    178 
    179         test_suite = unittest.TestSuite(suites)
    180         test_runner = Runner(self.stream, self._options, loader)
    181 
    182         _log.debug("Running the tests.")
    183         if self._options.pass_through:
     92        if self.options.pass_through:
    18493            outputcapture.OutputCapture.stream_wrapper = _CaptureAndPassThroughStream
    185         result = test_runner.run(test_suite)
    186         if self._options.coverage:
    187             cov.stop()
    188             cov.save()
    189             cov.report(show_missing=False)
    190         return result.wasSuccessful()
    191 
    192     def _log_exception(self):
    193         s = StringIO.StringIO()
    194         traceback.print_exc(file=s)
    195         for l in s.buflist:
    196             _log.error('  ' + l.rstrip())
    19794
    19895
Note: See TracChangeset for help on using the changeset viewer.