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