• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2009 Google Inc. All rights reserved.
2# Copyright (c) 2009 Apple Inc. All rights reserved.
3# Copyright (c) 2012 Intel Corporation. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15#     * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31import fnmatch
32import logging
33import re
34
35from optparse import make_option
36
37from webkitpy.common.system.crashlogs import CrashLogs
38from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
39from webkitpy.layout_tests.models.test_expectations import TestExpectations
40from webkitpy.layout_tests.port import platform_options
41
42_log = logging.getLogger(__name__)
43
44
45class CrashLog(AbstractDeclarativeCommand):
46    name = "crash-log"
47    help_text = "Print the newest crash log for the given process"
48    show_in_main_help = True
49    long_help = """Finds the newest crash log matching the given process name
50and PID and prints it to stdout."""
51    argument_names = "PROCESS_NAME [PID]"
52
53    def execute(self, options, args, tool):
54        crash_logs = CrashLogs(tool)
55        pid = None
56        if len(args) > 1:
57            pid = int(args[1])
58        print crash_logs.find_newest_log(args[0], pid)
59
60
61class PrintExpectations(AbstractDeclarativeCommand):
62    name = 'print-expectations'
63    help_text = 'Print the expected result for the given test(s) on the given port(s)'
64    show_in_main_help = True
65
66    def __init__(self):
67        options = [
68            make_option('--all', action='store_true', default=False,
69                        help='display the expectations for *all* tests'),
70            make_option('-x', '--exclude-keyword', action='append', default=[],
71                        help='limit to tests not matching the given keyword (for example, "skip", "slow", or "crash". May specify multiple times'),
72            make_option('-i', '--include-keyword', action='append', default=[],
73                        help='limit to tests with the given keyword (for example, "skip", "slow", or "crash". May specify multiple times'),
74            make_option('--csv', action='store_true', default=False,
75                        help='Print a CSV-style report that includes the port name, bugs, specifiers, tests, and expectations'),
76            make_option('-f', '--full', action='store_true', default=False,
77                        help='Print a full TestExpectations-style line for every match'),
78            make_option('--paths', action='store_true', default=False,
79                        help='display the paths for all applicable expectation files'),
80        ] + platform_options(use_globs=True)
81
82        AbstractDeclarativeCommand.__init__(self, options=options)
83        self._expectation_models = {}
84
85    def execute(self, options, args, tool):
86        if not options.paths and not args and not options.all:
87            print "You must either specify one or more test paths or --all."
88            return
89
90        if options.platform:
91            port_names = fnmatch.filter(tool.port_factory.all_port_names(), options.platform)
92            if not port_names:
93                default_port = tool.port_factory.get(options.platform)
94                if default_port:
95                    port_names = [default_port.name()]
96                else:
97                    print "No port names match '%s'" % options.platform
98                    return
99            else:
100                default_port = tool.port_factory.get(port_names[0])
101        else:
102            default_port = tool.port_factory.get(options=options)
103            port_names = [default_port.name()]
104
105        if options.paths:
106            files = default_port.expectations_files()
107            layout_tests_dir = default_port.layout_tests_dir()
108            for file in files:
109                if file.startswith(layout_tests_dir):
110                    file = file.replace(layout_tests_dir, 'LayoutTests')
111                print file
112            return
113
114        tests = set(default_port.tests(args))
115        for port_name in port_names:
116            model = self._model(options, port_name, tests)
117            tests_to_print = self._filter_tests(options, model, tests)
118            lines = [model.get_expectation_line(test) for test in sorted(tests_to_print)]
119            if port_name != port_names[0]:
120                print
121            print '\n'.join(self._format_lines(options, port_name, lines))
122
123    def _filter_tests(self, options, model, tests):
124        filtered_tests = set()
125        if options.include_keyword:
126            for keyword in options.include_keyword:
127                filtered_tests.update(model.get_test_set_for_keyword(keyword))
128        else:
129            filtered_tests = tests
130
131        for keyword in options.exclude_keyword:
132            filtered_tests.difference_update(model.get_test_set_for_keyword(keyword))
133        return filtered_tests
134
135    def _format_lines(self, options, port_name, lines):
136        output = []
137        if options.csv:
138            for line in lines:
139                output.append("%s,%s" % (port_name, line.to_csv()))
140        elif lines:
141            include_modifiers = options.full
142            include_expectations = options.full or len(options.include_keyword) != 1 or len(options.exclude_keyword)
143            output.append("// For %s" % port_name)
144            for line in lines:
145                output.append("%s" % line.to_string(None, include_modifiers, include_expectations, include_comment=False))
146        return output
147
148    def _model(self, options, port_name, tests):
149        port = self._tool.port_factory.get(port_name, options)
150        return TestExpectations(port, tests).model()
151
152
153class PrintBaselines(AbstractDeclarativeCommand):
154    name = 'print-baselines'
155    help_text = 'Prints the baseline locations for given test(s) on the given port(s)'
156    show_in_main_help = True
157
158    def __init__(self):
159        options = [
160            make_option('--all', action='store_true', default=False,
161                        help='display the baselines for *all* tests'),
162            make_option('--csv', action='store_true', default=False,
163                        help='Print a CSV-style report that includes the port name, test_name, test platform, baseline type, baseline location, and baseline platform'),
164            make_option('--include-virtual-tests', action='store_true',
165                        help='Include virtual tests'),
166        ] + platform_options(use_globs=True)
167        AbstractDeclarativeCommand.__init__(self, options=options)
168        self._platform_regexp = re.compile('platform/([^\/]+)/(.+)')
169
170    def execute(self, options, args, tool):
171        if not args and not options.all:
172            print "You must either specify one or more test paths or --all."
173            return
174
175        default_port = tool.port_factory.get()
176        if options.platform:
177            port_names = fnmatch.filter(tool.port_factory.all_port_names(), options.platform)
178            if not port_names:
179                print "No port names match '%s'" % options.platform
180        else:
181            port_names = [default_port.name()]
182
183        if options.include_virtual_tests:
184            tests = sorted(default_port.tests(args))
185        else:
186            # FIXME: make real_tests() a public method.
187            tests = sorted(default_port._real_tests(args))
188
189        for port_name in port_names:
190            if port_name != port_names[0]:
191                print
192            if not options.csv:
193                print "// For %s" % port_name
194            port = tool.port_factory.get(port_name)
195            for test_name in tests:
196                self._print_baselines(options, port_name, test_name, port.expected_baselines_by_extension(test_name))
197
198    def _print_baselines(self, options, port_name, test_name, baselines):
199        for extension in sorted(baselines.keys()):
200            baseline_location = baselines[extension]
201            if baseline_location:
202                if options.csv:
203                    print "%s,%s,%s,%s,%s,%s" % (port_name, test_name, self._platform_for_path(test_name),
204                                                 extension[1:], baseline_location, self._platform_for_path(baseline_location))
205                else:
206                    print baseline_location
207
208    def _platform_for_path(self, relpath):
209        platform_matchobj = self._platform_regexp.match(relpath)
210        if platform_matchobj:
211            return platform_matchobj.group(1)
212        return None
213