~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Tools/Scripts/webkitpy/test/printer.py

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2012 Google, Inc.
 
2
# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
 
3
#
 
4
# Redistribution and use in source and binary forms, with or without
 
5
# modification, are permitted provided that the following conditions
 
6
# are met:
 
7
# 1.  Redistributions of source code must retain the above copyright
 
8
#     notice, this list of conditions and the following disclaimer.
 
9
# 2.  Redistributions in binary form must reproduce the above copyright
 
10
#     notice, this list of conditions and the following disclaimer in the
 
11
#     documentation and/or other materials provided with the distribution.
 
12
#
 
13
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
 
14
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
15
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
16
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
 
17
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
18
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
19
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
20
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
21
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
22
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
23
 
 
24
import logging
 
25
import StringIO
 
26
 
 
27
from webkitpy.common.system import outputcapture
 
28
from webkitpy.layout_tests.views.metered_stream import MeteredStream
 
29
 
 
30
_log = logging.getLogger(__name__)
 
31
 
 
32
 
 
33
class Printer(object):
 
34
    def __init__(self, stream, options=None):
 
35
        self.stream = stream
 
36
        self.meter = None
 
37
        self.options = options
 
38
        self.num_tests = 0
 
39
        self.num_completed = 0
 
40
        self.num_errors = 0
 
41
        self.num_failures = 0
 
42
        self.running_tests = []
 
43
        self.completed_tests = []
 
44
        if options:
 
45
            self.configure(options)
 
46
 
 
47
    def configure(self, options):
 
48
        self.options = options
 
49
 
 
50
        if options.timing:
 
51
            # --timing implies --verbose
 
52
            options.verbose = max(options.verbose, 1)
 
53
 
 
54
        log_level = logging.INFO
 
55
        if options.quiet:
 
56
            log_level = logging.WARNING
 
57
        elif options.verbose == 2:
 
58
            log_level = logging.DEBUG
 
59
 
 
60
        self.meter = MeteredStream(self.stream, (options.verbose == 2))
 
61
 
 
62
        handler = logging.StreamHandler(self.stream)
 
63
        # We constrain the level on the handler rather than on the root
 
64
        # logger itself.  This is probably better because the handler is
 
65
        # configured and known only to this module, whereas the root logger
 
66
        # is an object shared (and potentially modified) by many modules.
 
67
        # Modifying the handler, then, is less intrusive and less likely to
 
68
        # interfere with modifications made by other modules (e.g. in unit
 
69
        # tests).
 
70
        handler.name = __name__
 
71
        handler.setLevel(log_level)
 
72
        formatter = logging.Formatter("%(message)s")
 
73
        handler.setFormatter(formatter)
 
74
 
 
75
        logger = logging.getLogger()
 
76
        logger.addHandler(handler)
 
77
        logger.setLevel(logging.NOTSET)
 
78
 
 
79
        # Filter out most webkitpy messages.
 
80
        #
 
81
        # Messages can be selectively re-enabled for this script by updating
 
82
        # this method accordingly.
 
83
        def filter_records(record):
 
84
            """Filter out autoinstall and non-third-party webkitpy messages."""
 
85
            # FIXME: Figure out a way not to use strings here, for example by
 
86
            #        using syntax like webkitpy.test.__name__.  We want to be
 
87
            #        sure not to import any non-Python 2.4 code, though, until
 
88
            #        after the version-checking code has executed.
 
89
            if (record.name.startswith("webkitpy.common.system.autoinstall") or
 
90
                record.name.startswith("webkitpy.test")):
 
91
                return True
 
92
            if record.name.startswith("webkitpy"):
 
93
                return False
 
94
            return True
 
95
 
 
96
        testing_filter = logging.Filter()
 
97
        testing_filter.filter = filter_records
 
98
 
 
99
        # Display a message so developers are not mystified as to why
 
100
        # logging does not work in the unit tests.
 
101
        _log.info("Suppressing most webkitpy logging while running unit tests.")
 
102
        handler.addFilter(testing_filter)
 
103
 
 
104
        if self.options.pass_through:
 
105
            outputcapture.OutputCapture.stream_wrapper = _CaptureAndPassThroughStream
 
106
 
 
107
    def write_update(self, msg):
 
108
        self.meter.write_update(msg)
 
109
 
 
110
    def print_started_test(self, source, test_name):
 
111
        self.running_tests.append(test_name)
 
112
        if len(self.running_tests) > 1:
 
113
            suffix = ' (+%d)' % (len(self.running_tests) - 1)
 
114
        else:
 
115
            suffix = ''
 
116
 
 
117
        if self.options.verbose:
 
118
            write = self.meter.write_update
 
119
        else:
 
120
            write = self.meter.write_throttled_update
 
121
 
 
122
        write(self._test_line(self.running_tests[0], suffix))
 
123
 
 
124
    def print_finished_test(self, source, test_name, test_time, failures, errors):
 
125
        write = self.meter.writeln
 
126
        if failures:
 
127
            lines = failures[0].splitlines() + ['']
 
128
            suffix = ' failed:'
 
129
            self.num_failures += 1
 
130
        elif errors:
 
131
            lines = errors[0].splitlines() + ['']
 
132
            suffix = ' erred:'
 
133
            self.num_errors += 1
 
134
        else:
 
135
            suffix = ' passed'
 
136
            lines = []
 
137
            if self.options.verbose:
 
138
                write = self.meter.writeln
 
139
            else:
 
140
                write = self.meter.write_throttled_update
 
141
        if self.options.timing:
 
142
            suffix += ' %.4fs' % test_time
 
143
 
 
144
        self.num_completed += 1
 
145
 
 
146
        if test_name == self.running_tests[0]:
 
147
            self.completed_tests.insert(0, [test_name, suffix, lines])
 
148
        else:
 
149
            self.completed_tests.append([test_name, suffix, lines])
 
150
        self.running_tests.remove(test_name)
 
151
 
 
152
        for test_name, msg, lines in self.completed_tests:
 
153
            if lines:
 
154
                self.meter.writeln(self._test_line(test_name, msg))
 
155
                for line in lines:
 
156
                    self.meter.writeln('  ' + line)
 
157
            else:
 
158
                write(self._test_line(test_name, msg))
 
159
        self.completed_tests = []
 
160
 
 
161
    def _test_line(self, test_name, suffix):
 
162
        return '[%d/%d] %s%s' % (self.num_completed, self.num_tests, test_name, suffix)
 
163
 
 
164
    def print_result(self, run_time):
 
165
        write = self.meter.writeln
 
166
        write('Ran %d test%s in %.3fs' % (self.num_completed, self.num_completed != 1 and "s" or "", run_time))
 
167
        if self.num_failures or self.num_errors:
 
168
            write('FAILED (failures=%d, errors=%d)\n' % (self.num_failures, self.num_errors))
 
169
        else:
 
170
            write('\nOK\n')
 
171
 
 
172
 
 
173
class _CaptureAndPassThroughStream(object):
 
174
    def __init__(self, stream):
 
175
        self._buffer = StringIO.StringIO()
 
176
        self._stream = stream
 
177
 
 
178
    def write(self, msg):
 
179
        self._stream.write(msg)
 
180
 
 
181
        # Note that we don't want to capture any output generated by the debugger
 
182
        # because that could cause the results of capture_output() to be invalid.
 
183
        if not self._message_is_from_pdb():
 
184
            self._buffer.write(msg)
 
185
 
 
186
    def _message_is_from_pdb(self):
 
187
        # We will assume that if the pdb module is in the stack then the output
 
188
        # is being generated by the python debugger (or the user calling something
 
189
        # from inside the debugger).
 
190
        import inspect
 
191
        import pdb
 
192
        stack = inspect.stack()
 
193
        return any(frame[1] == pdb.__file__.replace('.pyc', '.py') for frame in stack)
 
194
 
 
195
    def flush(self):
 
196
        self._stream.flush()
 
197
 
 
198
    def getvalue(self):
 
199
        return self._buffer.getvalue()