Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / Scripts / webkitpy / layout_tests / run_webkit_tests.py
1 # Copyright (C) 2010 Google Inc. All rights reserved.
2 # Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
3 # Copyright (C) 2011 Apple Inc. 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
31 import logging
32 import optparse
33 import os
34 import sys
35 import traceback
36
37 from webkitpy.common.host import Host
38 from webkitpy.layout_tests.controllers.manager import Manager
39 from webkitpy.layout_tests.models import test_run_results
40 from webkitpy.layout_tests.port import configuration_options, platform_options
41 from webkitpy.layout_tests.views import buildbot_results
42 from webkitpy.layout_tests.views import printing
43 from webkitpy.layout_tests.generate_results_dashboard import DashBoardGenerator
44
45 _log = logging.getLogger(__name__)
46
47
48
49 def main(argv, stdout, stderr):
50     options, args = parse_args(argv)
51
52     if options.platform and 'test' in options.platform and not 'browser_test' in options.platform:
53         # It's a bit lame to import mocks into real code, but this allows the user
54         # to run tests against the test platform interactively, which is useful for
55         # debugging test failures.
56         from webkitpy.common.host_mock import MockHost
57         host = MockHost()
58     else:
59         host = Host()
60
61     if options.lint_test_files:
62         from webkitpy.layout_tests.lint_test_expectations import run_checks
63         return run_checks(host, options, stderr)
64
65     try:
66         port = host.port_factory.get(options.platform, options)
67     except NotImplementedError, e:
68         # FIXME: is this the best way to handle unsupported port names?
69         print >> stderr, str(e)
70         return test_run_results.UNEXPECTED_ERROR_EXIT_STATUS
71
72     try:
73         run_details = run(port, options, args, stderr)
74         if ((run_details.exit_code not in test_run_results.ERROR_CODES or
75              run_details.exit_code == test_run_results.EARLY_EXIT_STATUS) and
76             not run_details.initial_results.keyboard_interrupted):
77             bot_printer = buildbot_results.BuildBotPrinter(stdout, options.debug_rwt_logging)
78             bot_printer.print_results(run_details)
79             gen_dash_board = DashBoardGenerator(port)
80             gen_dash_board.generate()
81
82         return run_details.exit_code
83
84     # We need to still handle KeyboardInterrupt, atleast for webkitpy unittest cases.
85     except KeyboardInterrupt:
86         return test_run_results.INTERRUPTED_EXIT_STATUS
87     except test_run_results.TestRunException as e:
88         print >> stderr, e.msg
89         return e.code
90     except BaseException as e:
91         if isinstance(e, Exception):
92             print >> stderr, '\n%s raised: %s' % (e.__class__.__name__, str(e))
93             traceback.print_exc(file=stderr)
94         return test_run_results.UNEXPECTED_ERROR_EXIT_STATUS
95
96
97 def parse_args(args):
98     option_group_definitions = []
99
100     option_group_definitions.append(("Platform options", platform_options()))
101     option_group_definitions.append(("Configuration options", configuration_options()))
102     option_group_definitions.append(("Printing Options", printing.print_options()))
103
104     option_group_definitions.append(("Android-specific Options", [
105         optparse.make_option("--adb-device",
106             action="append", default=[],
107             help="Run Android layout tests on these devices."),
108
109         # FIXME: Flip this to be off by default once we can log the device setup more cleanly.
110         optparse.make_option("--no-android-logging",
111             action="store_false", dest='android_logging', default=True,
112             help="Do not log android-specific debug messages (default is to log as part of --debug-rwt-logging"),
113     ]))
114
115     option_group_definitions.append(("Results Options", [
116         optparse.make_option("--add-platform-exceptions", action="store_true", default=False,
117             help="Save generated results into the *most-specific-platform* directory rather than the *generic-platform* directory"),
118         optparse.make_option("--additional-drt-flag", action="append",
119             default=[], help="Additional command line flag to pass to the driver "
120                  "Specify multiple times to add multiple flags."),
121         optparse.make_option("--additional-expectations", action="append", default=[],
122             help="Path to a test_expectations file that will override previous expectations. "
123                  "Specify multiple times for multiple sets of overrides."),
124         optparse.make_option("--additional-platform-directory", action="append",
125             default=[], help="Additional directory where to look for test "
126                  "baselines (will take precendence over platform baselines). "
127                  "Specify multiple times to add multiple search path entries."),
128         optparse.make_option("--build-directory",
129             help="Path to the directory under which build files are kept (should not include configuration)"),
130         optparse.make_option("--clobber-old-results", action="store_true",
131             default=False, help="Clobbers test results from previous runs."),
132         optparse.make_option("--compare-port", action="store", default=None,
133             help="Use the specified port's baselines first"),
134         optparse.make_option("--driver-name", type="string",
135             help="Alternative driver binary to use"),
136         optparse.make_option("--full-results-html", action="store_true",
137             default=False,
138             help="Show all failures in results.html, rather than only regressions"),
139         optparse.make_option("--new-baseline", action="store_true",
140             default=False, help="Save generated results as new baselines "
141                  "into the *most-specific-platform* directory, overwriting whatever's "
142                  "already there. Equivalent to --reset-results --add-platform-exceptions"),
143         optparse.make_option("--no-new-test-results", action="store_false",
144             dest="new_test_results", default=True,
145             help="Don't create new baselines when no expected results exist"),
146         optparse.make_option("--no-show-results", action="store_false",
147             default=True, dest="show_results",
148             help="Don't launch a browser with results after the tests "
149                  "are done"),
150         optparse.make_option("-p", "--pixel", "--pixel-tests", action="store_true",
151             dest="pixel_tests", help="Enable pixel-to-pixel PNG comparisons"),
152         optparse.make_option("--no-pixel", "--no-pixel-tests", action="store_false",
153             dest="pixel_tests", help="Disable pixel-to-pixel PNG comparisons"),
154
155         #FIXME: we should support a comma separated list with --pixel-test-directory as well.
156         optparse.make_option("--pixel-test-directory", action="append", default=[], dest="pixel_test_directories",
157             help="A directory where it is allowed to execute tests as pixel tests. "
158                  "Specify multiple times to add multiple directories. "
159                  "This option implies --pixel-tests. If specified, only those tests "
160                  "will be executed as pixel tests that are located in one of the "
161                  "directories enumerated with the option. Some ports may ignore this "
162                  "option while others can have a default value that can be overridden here."),
163
164         optparse.make_option("--reset-results", action="store_true",
165             default=False, help="Reset expectations to the "
166                  "generated results in their existing location."),
167         optparse.make_option("--results-directory", help="Location of test results"),
168         optparse.make_option("--skip-failing-tests", action="store_true",
169             default=False, help="Skip tests that are expected to fail. "
170                  "Note: When using this option, you might miss new crashes "
171                  "in these tests."),
172         optparse.make_option("--smoke", action="store_true",
173             help="Run just the SmokeTests"),
174         optparse.make_option("--no-smoke", dest="smoke", action="store_false",
175             help="Do not run just the SmokeTests"),
176     ]))
177
178     option_group_definitions.append(("Testing Options", [
179         optparse.make_option("--additional-env-var", type="string", action="append", default=[],
180             help="Passes that environment variable to the tests (--additional-env-var=NAME=VALUE)"),
181         optparse.make_option("--batch-size",
182             help=("Run a the tests in batches (n), after every n tests, "
183                   "the driver is relaunched."), type="int", default=None),
184         optparse.make_option("--build", dest="build",
185             action="store_true", default=True,
186             help="Check to ensure the build is up-to-date (default)."),
187         optparse.make_option("--no-build", dest="build",
188             action="store_false", help="Don't check to see if the build is up-to-date."),
189         optparse.make_option("--child-processes",
190             help="Number of drivers to run in parallel."),
191         optparse.make_option("--disable-breakpad", action="store_true",
192             help="Don't use breakpad to symbolize unexpected crashes."),
193         optparse.make_option("--driver-logging", action="store_true",
194             help="Print detailed logging of the driver/content_shell"),
195         optparse.make_option("--enable-leak-detection", action="store_true",
196             help="Enable the leak detection of DOM objects."),
197         optparse.make_option("--enable-sanitizer", action="store_true",
198             help="Only alert on sanitizer-related errors and crashes"),
199         optparse.make_option("--exit-after-n-crashes-or-timeouts", type="int",
200             default=None, help="Exit after the first N crashes instead of "
201             "running all tests"),
202         optparse.make_option("--exit-after-n-failures", type="int", default=None,
203             help="Exit after the first N failures instead of running all "
204             "tests"),
205         optparse.make_option("--ignore-builder-category", action="store",
206             help=("The category of builders to use with the --ignore-flaky-tests "
207                 "option ('layout' or 'deps').")),
208         optparse.make_option("--ignore-flaky-tests", action="store",
209             help=("Control whether tests that are flaky on the bots get ignored."
210                 "'very-flaky' == Ignore any tests that flaked more than once on the bot."
211                 "'maybe-flaky' == Ignore any tests that flaked once on the bot."
212                 "'unexpected' == Ignore any tests that had unexpected results on the bot.")),
213         optparse.make_option("--iterations", type="int", default=1, help="Number of times to run the set of tests (e.g. ABCABCABC)"),
214         optparse.make_option("--max-locked-shards", type="int", default=0,
215             help="Set the maximum number of locked shards"),
216         optparse.make_option("--no-retry-failures", action="store_false",
217             dest="retry_failures",
218             help="Don't re-try any tests that produce unexpected results."),
219         optparse.make_option("--nocheck-sys-deps", action="store_true",
220             default=False,
221             help="Don't check the system dependencies (themes)"),
222         optparse.make_option("--order", action="store", default="natural",
223             help=("determine the order in which the test cases will be run. "
224                   "'none' == use the order in which the tests were listed either in arguments or test list, "
225                   "'natural' == use the natural order (default), "
226                   "'random-seeded' == randomize the test order using a fixed seed, "
227                   "'random' == randomize the test order.")),
228         optparse.make_option("--profile", action="store_true",
229             help="Output per-test profile information."),
230         optparse.make_option("--profiler", action="store",
231             help="Output per-test profile information, using the specified profiler."),
232         optparse.make_option("--repeat-each", type="int", default=1, help="Number of times to run each test (e.g. AAABBBCCC)"),
233         optparse.make_option("--retry-failures", action="store_true",
234             help="Re-try any tests that produce unexpected results. Default is to not retry if an explicit list of tests is passed to run-webkit-tests."),
235         optparse.make_option("--run-chunk",
236             help=("Run a specified chunk (n:l), the nth of len l, "
237                  "of the layout tests")),
238         optparse.make_option("--run-part", help=("Run a specified part (n:m), "
239                   "the nth of m parts, of the layout tests")),
240         optparse.make_option("--run-singly", action="store_true",
241             default=False, help="DEPRECATED, same as --batch-size=1 --verbose"),
242         optparse.make_option("--skipped", action="store", default=None,
243             help=("control how tests marked SKIP are run. "
244                  "'default' == Skip tests unless explicitly listed on the command line, "
245                  "'ignore' == Run them anyway, "
246                  "'only' == only run the SKIP tests, "
247                  "'always' == always skip, even if listed on the command line.")),
248         optparse.make_option("--test-list", action="append",
249             help="read list of tests to run from file", metavar="FILE"),
250         optparse.make_option("--time-out-ms",
251             help="Set the timeout for each test"),
252         optparse.make_option("--wrapper",
253             help="wrapper command to insert before invocations of "
254                  "the driver; option is split on whitespace before "
255                  "running. (Example: --wrapper='valgrind --smc-check=all')"),
256         # FIXME: Display default number of child processes that will run.
257         optparse.make_option("-f", "--fully-parallel", action="store_true",
258             help="run all tests in parallel"),
259         optparse.make_option("-i", "--ignore-tests", action="append", default=[],
260             help="directories or test to ignore (may specify multiple times)"),
261         optparse.make_option("-n", "--dry-run", action="store_true",
262             default=False,
263             help="Do everything but actually run the tests or upload results."),
264     ]))
265
266     option_group_definitions.append(("Miscellaneous Options", [
267         optparse.make_option("--lint-test-files", action="store_true",
268         default=False, help=("Makes sure the test files parse for all "
269                             "configurations. Does not run any tests.")),
270     ]))
271
272     # FIXME: Move these into json_results_generator.py
273     option_group_definitions.append(("Result JSON Options", [
274         optparse.make_option("--build-name", default="DUMMY_BUILD_NAME",
275             help=("The name of the builder used in its path, e.g. "
276                   "webkit-rel.")),
277         optparse.make_option("--build-number", default="DUMMY_BUILD_NUMBER",
278             help=("The build number of the builder running this script.")),
279         optparse.make_option("--builder-name", default="",
280             help=("The name of the builder shown on the waterfall running "
281                   "this script e.g. WebKit.")),
282         optparse.make_option("--master-name", help="The name of the buildbot master."),
283         optparse.make_option("--test-results-server", default="",
284             help=("If specified, upload results json files to this appengine "
285                   "server.")),
286         optparse.make_option("--write-full-results-to",
287             help=("If specified, copy full_results.json from the results dir "
288                   "to the specified path.")),
289     ]))
290
291     option_parser = optparse.OptionParser()
292
293     for group_name, group_options in option_group_definitions:
294         option_group = optparse.OptionGroup(option_parser, group_name)
295         option_group.add_options(group_options)
296         option_parser.add_option_group(option_group)
297
298     return option_parser.parse_args(args)
299
300
301 def _set_up_derived_options(port, options, args):
302     """Sets the options values that depend on other options values."""
303     if not options.child_processes:
304         options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
305                                                  str(port.default_child_processes()))
306     if not options.max_locked_shards:
307         options.max_locked_shards = int(os.environ.get("WEBKIT_TEST_MAX_LOCKED_SHARDS",
308                                                        str(port.default_max_locked_shards())))
309
310     if not options.configuration:
311         options.configuration = port.default_configuration()
312
313     if options.pixel_tests is None:
314         options.pixel_tests = port.default_pixel_tests()
315
316     if not options.time_out_ms:
317         options.time_out_ms = str(port.default_timeout_ms())
318
319     options.slow_time_out_ms = str(5 * int(options.time_out_ms))
320
321     if options.additional_platform_directory:
322         additional_platform_directories = []
323         for path in options.additional_platform_directory:
324             additional_platform_directories.append(port.host.filesystem.abspath(path))
325         options.additional_platform_directory = additional_platform_directories
326
327     if options.new_baseline:
328         options.reset_results = True
329         options.add_platform_exceptions = True
330
331     if options.pixel_test_directories:
332         options.pixel_tests = True
333         varified_dirs = set()
334         pixel_test_directories = options.pixel_test_directories
335         for directory in pixel_test_directories:
336             # FIXME: we should support specifying the directories all the ways we support it for additional
337             # arguments specifying which tests and directories to run. We should also move the logic for that
338             # to Port.
339             filesystem = port.host.filesystem
340             if not filesystem.isdir(filesystem.join(port.layout_tests_dir(), directory)):
341                 _log.warning("'%s' was passed to --pixel-test-directories, which doesn't seem to be a directory" % str(directory))
342             else:
343                 varified_dirs.add(directory)
344
345         options.pixel_test_directories = list(varified_dirs)
346
347     if options.run_singly:
348         options.batch_size = 1
349         options.verbose = True
350
351     if not args and not options.test_list and options.smoke is None:
352         options.smoke = port.default_smoke_test_only()
353     if options.smoke:
354         if not args and not options.test_list and options.retry_failures is None:
355             # Retry failures by default if we're doing just a smoke test (no additional tests).
356             options.retry_failures = True
357
358         if not options.test_list:
359             options.test_list = []
360         options.test_list.append(port.host.filesystem.join(port.layout_tests_dir(), 'SmokeTests'))
361         if not options.skipped:
362             options.skipped = 'always'
363
364     if not options.skipped:
365         options.skipped = 'default'
366
367 def run(port, options, args, logging_stream):
368     logger = logging.getLogger()
369     logger.setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
370
371     try:
372         printer = printing.Printer(port, options, logging_stream, logger=logger)
373
374         _set_up_derived_options(port, options, args)
375         manager = Manager(port, options, printer)
376         printer.print_config(port.results_directory())
377
378         run_details = manager.run(args)
379         _log.debug("Testing completed, Exit status: %d" % run_details.exit_code)
380         return run_details
381     finally:
382         printer.cleanup()
383
384 if __name__ == '__main__':
385     sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))