[GTK] Clear application cache between tests in DumpRenderTree
[WebKit-https.git] / Tools / Scripts / webkitpy / layout_tests / run_webkit_tests.py
1 #!/usr/bin/env python
2 # Copyright (C) 2010 Google Inc. All rights reserved.
3 # Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
4 # Copyright (C) 2011 Apple Inc. All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
8 # met:
9 #
10 #     * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 #     * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following disclaimer
14 # in the documentation and/or other materials provided with the
15 # distribution.
16 #     * Neither the name of Google Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived from
18 # this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 import errno
33 import logging
34 import optparse
35 import os
36 import signal
37 import sys
38 import traceback
39
40 from webkitpy.common.host import Host
41 from webkitpy.common.system import stack_utils
42 from webkitpy.layout_tests.controllers.manager import Manager, WorkerException, TestRunInterruptedException
43 from webkitpy.layout_tests.models import test_expectations
44 from webkitpy.layout_tests.port import port_options
45 from webkitpy.layout_tests.views import printing
46
47
48 _log = logging.getLogger(__name__)
49
50
51 # This mirrors what the shell normally does.
52 INTERRUPTED_EXIT_STATUS = signal.SIGINT + 128
53
54 # This is a randomly chosen exit code that can be tested against to
55 # indicate that an unexpected exception occurred.
56 EXCEPTIONAL_EXIT_STATUS = 254
57
58
59 def lint(port, options):
60     host = port.host
61     if options.platform:
62         ports_to_lint = [port]
63     else:
64         ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names()]
65
66     files_linted = set()
67     lint_failed = False
68
69     for port_to_lint in ports_to_lint:
70         expectations_file = port_to_lint.path_to_test_expectations_file()
71         if expectations_file in files_linted:
72             continue
73
74         try:
75             test_expectations.TestExpectations(port_to_lint, is_lint_mode=True)
76         except test_expectations.ParseError, e:
77             lint_failed = True
78             _log.error('')
79             for warning in e.warnings:
80                 _log.error(warning)
81             _log.error('')
82         files_linted.add(expectations_file)
83
84     if lint_failed:
85         _log.error('Lint failed.')
86         return -1
87     _log.info('Lint succeeded.')
88     return 0
89
90
91 def run(port, options, args, regular_output=sys.stderr, buildbot_output=sys.stdout):
92     try:
93         warnings = _set_up_derived_options(port, options)
94
95         printer = printing.Printer(port, options, regular_output, buildbot_output, logger=logging.getLogger())
96
97         for warning in warnings:
98             _log.warning(warning)
99
100         if options.lint_test_files:
101             return lint(port, options)
102
103         # We wrap any parts of the run that are slow or likely to raise exceptions
104         # in a try/finally to ensure that we clean up the logging configuration.
105         unexpected_result_count = -1
106
107         manager = Manager(port, options, printer)
108         printer.print_config()
109
110         unexpected_result_count = manager.run(args)
111         _log.debug("Testing completed, Exit status: %d" % unexpected_result_count)
112     except Exception:
113         exception_type, exception_value, exception_traceback = sys.exc_info()
114         if exception_type not in (KeyboardInterrupt, TestRunInterruptedException, WorkerException):
115             print >> sys.stderr, '\n%s raised: %s' % (exception_type.__name__, exception_value)
116             stack_utils.log_traceback(_log.error, exception_traceback)
117         raise
118     finally:
119         printer.cleanup()
120
121     return unexpected_result_count
122
123
124 def _set_up_derived_options(port, options):
125     """Sets the options values that depend on other options values."""
126     # We return a list of warnings to print after the printer is initialized.
127     warnings = []
128
129     if not options.child_processes:
130         options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
131                                                  str(port.default_child_processes()))
132
133     if not options.configuration:
134         options.configuration = port.default_configuration()
135
136     if options.pixel_tests is None:
137         options.pixel_tests = port.default_pixel_tests()
138
139     if not options.time_out_ms:
140         options.time_out_ms = str(port.default_timeout_ms())
141
142     options.slow_time_out_ms = str(5 * int(options.time_out_ms))
143
144     if options.additional_platform_directory:
145         normalized_platform_directories = []
146         for path in options.additional_platform_directory:
147             if not port.host.filesystem.isabs(path):
148                 warnings.append("--additional-platform-directory=%s is ignored since it is not absolute" % path)
149                 continue
150             normalized_platform_directories.append(port.host.filesystem.normpath(path))
151         options.additional_platform_directory = normalized_platform_directories
152
153     if not options.http and options.skipped in ('ignore', 'only'):
154         warnings.append("--force/--skipped=%s overrides --no-http." % (options.skipped))
155         options.http = True
156
157     if options.ignore_metrics and (options.new_baseline or options.reset_results):
158         warnings.append("--ignore-metrics has no effect with --new-baselines or with --reset-results")
159
160     if options.new_baseline:
161         options.reset_results = True
162         options.add_platform_exceptions = True
163
164     if options.pixel_test_directories:
165         options.pixel_tests = True
166         varified_dirs = set()
167         pixel_test_directories = options.pixel_test_directories
168         for directory in pixel_test_directories:
169             # FIXME: we should support specifying the directories all the ways we support it for additional
170             # arguments specifying which tests and directories to run. We should also move the logic for that
171             # to Port.
172             filesystem = port.host.filesystem
173             if not filesystem.isdir(filesystem.join(port.layout_tests_dir(), directory)):
174                 warnings.append("'%s' was passed to --pixel-test-directories, which doesn't seem to be a directory" % str(directory))
175             else:
176                 varified_dirs.add(directory)
177
178         options.pixel_test_directories = list(varified_dirs)
179
180     if options.run_singly:
181         options.verbose = True
182
183     return warnings
184
185
186 def _compat_shim_callback(option, opt_str, value, parser):
187     print "Ignoring unsupported option: %s" % opt_str
188
189
190 def _compat_shim_option(option_name, **kwargs):
191     return optparse.make_option(option_name, action="callback",
192         callback=_compat_shim_callback,
193         help="Ignored, for old-run-webkit-tests compat only.", **kwargs)
194
195
196 def parse_args(args=None):
197     """Provides a default set of command line args.
198
199     Returns a tuple of options, args from optparse"""
200
201     option_group_definitions = []
202
203     option_group_definitions.append(("Configuration options", port_options()))
204     option_group_definitions.append(("Printing Options", printing.print_options()))
205
206     # FIXME: These options should move onto the ChromiumPort.
207     option_group_definitions.append(("Chromium-specific Options", [
208         optparse.make_option("--startup-dialog", action="store_true",
209             default=False, help="create a dialog on DumpRenderTree startup"),
210         optparse.make_option("--gp-fault-error-box", action="store_true",
211             default=False, help="enable Windows GP fault error box"),
212         optparse.make_option("--js-flags",
213             type="string", help="JavaScript flags to pass to tests"),
214         optparse.make_option("--stress-opt", action="store_true",
215             default=False,
216             help="Enable additional stress test to JavaScript optimization"),
217         optparse.make_option("--stress-deopt", action="store_true",
218             default=False,
219             help="Enable additional stress test to JavaScript optimization"),
220         optparse.make_option("--nocheck-sys-deps", action="store_true",
221             default=False,
222             help="Don't check the system dependencies (themes)"),
223         optparse.make_option("--accelerated-video",
224             action="store_true",
225             help="Use hardware-accelerated compositing for video"),
226         optparse.make_option("--no-accelerated-video",
227             action="store_false",
228             dest="accelerated_video",
229             help="Don't use hardware-accelerated compositing for video"),
230         optparse.make_option("--threaded-compositing",
231             action="store_true",
232             help="Use threaded compositing for rendering"),
233         optparse.make_option("--accelerated-2d-canvas",
234             action="store_true",
235             help="Use hardware-accelerated 2D Canvas calls"),
236         optparse.make_option("--no-accelerated-2d-canvas",
237             action="store_false",
238             dest="accelerated_2d_canvas",
239             help="Don't use hardware-accelerated 2D Canvas calls"),
240         optparse.make_option("--accelerated-painting",
241             action="store_true",
242             default=False,
243             help="Use hardware accelerated painting of composited pages"),
244         optparse.make_option("--per-tile-painting",
245             action="store_true",
246             help="Use per-tile painting of composited pages"),
247         optparse.make_option("--adb-device",
248             action="append", default=[],
249             help="Run Android layout tests on these devices."),
250     ]))
251
252     option_group_definitions.append(("EFL-specific Options", [
253         optparse.make_option("--webprocess-cmd-prefix", type="string",
254             default=False, help="Prefix used when spawning the Web process (Debug mode only)"),
255     ]))
256
257     option_group_definitions.append(("WebKit Options", [
258         optparse.make_option("--gc-between-tests", action="store_true", default=False,
259             help="Force garbage collection between each test"),
260         optparse.make_option("--complex-text", action="store_true", default=False,
261             help="Use the complex text code path for all text (Mac OS X and Windows only)"),
262         optparse.make_option("-l", "--leaks", action="store_true", default=False,
263             help="Enable leaks checking (Mac OS X only)"),
264         optparse.make_option("-g", "--guard-malloc", action="store_true", default=False,
265             help="Enable Guard Malloc (Mac OS X only)"),
266         optparse.make_option("--threaded", action="store_true", default=False,
267             help="Run a concurrent JavaScript thread with each test"),
268         optparse.make_option("--webkit-test-runner", "-2", action="store_true",
269             help="Use WebKitTestRunner rather than DumpRenderTree."),
270         # FIXME: We should merge this w/ --build-directory and only have one flag.
271         optparse.make_option("--root", action="store",
272             help="Path to a directory containing the executables needed to run tests."),
273     ]))
274
275     option_group_definitions.append(("ORWT Compatibility Options", [
276         # FIXME: Remove this option once the bots don't refer to it.
277         # results.html is smart enough to figure this out itself.
278         _compat_shim_option("--use-remote-links-to-tests"),
279     ]))
280
281     option_group_definitions.append(("Results Options", [
282         optparse.make_option("-p", "--pixel-tests", action="store_true",
283             dest="pixel_tests", help="Enable pixel-to-pixel PNG comparisons"),
284         optparse.make_option("--no-pixel-tests", action="store_false",
285             dest="pixel_tests", help="Disable pixel-to-pixel PNG comparisons"),
286         optparse.make_option("--no-sample-on-timeout", action="store_false",
287             dest="sample_on_timeout", help="Don't run sample on timeout (Mac OS X only)"),
288         optparse.make_option("--no-ref-tests", action="store_true",
289             dest="no_ref_tests", help="Skip all ref tests"),
290         optparse.make_option("--tolerance",
291             help="Ignore image differences less than this percentage (some "
292                 "ports may ignore this option)", type="float"),
293         optparse.make_option("--results-directory", help="Location of test results"),
294         optparse.make_option("--build-directory",
295             help="Path to the directory under which build files are kept (should not include configuration)"),
296         optparse.make_option("--add-platform-exceptions", action="store_true", default=False,
297             help="Save generated results into the *most-specific-platform* directory rather than the *generic-platform* directory"),
298         optparse.make_option("--new-baseline", action="store_true",
299             default=False, help="Save generated results as new baselines "
300                  "into the *most-specific-platform* directory, overwriting whatever's "
301                  "already there. Equivalent to --reset-results --add-platform-exceptions"),
302         optparse.make_option("--reset-results", action="store_true",
303             default=False, help="Reset expectations to the "
304                  "generated results in their existing location."),
305         optparse.make_option("--no-new-test-results", action="store_false",
306             dest="new_test_results", default=True,
307             help="Don't create new baselines when no expected results exist"),
308
309         #FIXME: we should support a comma separated list with --pixel-test-directory as well.
310         optparse.make_option("--pixel-test-directory", action="append", default=[], dest="pixel_test_directories",
311             help="A directory where it is allowed to execute tests as pixel tests. "
312                  "Specify multiple times to add multiple directories. "
313                  "This option implies --pixel-tests. If specified, only those tests "
314                  "will be executed as pixel tests that are located in one of the "
315                  "directories enumerated with the option. Some ports may ignore this "
316                  "option while others can have a default value that can be overridden here."),
317
318         optparse.make_option("--skip-failing-tests", action="store_true",
319             default=False, help="Skip tests that are expected to fail. "
320                  "Note: When using this option, you might miss new crashes "
321                  "in these tests."),
322         optparse.make_option("--additional-drt-flag", action="append",
323             default=[], help="Additional command line flag to pass to DumpRenderTree "
324                  "Specify multiple times to add multiple flags."),
325         optparse.make_option("--driver-name", type="string",
326             help="Alternative DumpRenderTree binary to use"),
327         optparse.make_option("--additional-platform-directory", action="append",
328             default=[], help="Additional directory where to look for test "
329                  "baselines (will take precendence over platform baselines). "
330                  "Specify multiple times to add multiple search path entries."),
331         optparse.make_option("--additional-expectations", action="append", default=[],
332             help="Path to a test_expectations file that will override previous expectations. "
333                  "Specify multiple times for multiple sets of overrides."),
334         optparse.make_option("--compare-port", action="store", default=None,
335             help="Use the specified port's baselines first"),
336         optparse.make_option("--no-show-results", action="store_false",
337             default=True, dest="show_results",
338             help="Don't launch a browser with results after the tests "
339                  "are done"),
340         # FIXME: We should have a helper function to do this sort of
341         # deprectated mapping and automatically log, etc.
342         optparse.make_option("--noshow-results", action="store_false", dest="show_results", help="Deprecated, same as --no-show-results."),
343         optparse.make_option("--no-launch-safari", action="store_false", dest="show_results", help="Deprecated, same as --no-show-results."),
344         optparse.make_option("--full-results-html", action="store_true",
345             default=False,
346             help="Show all failures in results.html, rather than only regressions"),
347         optparse.make_option("--clobber-old-results", action="store_true",
348             default=False, help="Clobbers test results from previous runs."),
349         optparse.make_option("--no-record-results", action="store_false",
350             default=True, dest="record_results",
351             help="Don't record the results."),
352         optparse.make_option("--http", action="store_true", dest="http",
353             default=True, help="Run HTTP and WebSocket tests (default)"),
354         optparse.make_option("--no-http", action="store_false", dest="http",
355             help="Don't run HTTP and WebSocket tests"),
356         optparse.make_option("--ignore-metrics", action="store_true", dest="ignore_metrics",
357             default=False, help="Ignore rendering metrics related information from test "
358             "output, only compare the structure of the rendertree."),
359     ]))
360
361     option_group_definitions.append(("Testing Options", [
362         optparse.make_option("--build", dest="build",
363             action="store_true", default=True,
364             help="Check to ensure the DumpRenderTree build is up-to-date "
365                  "(default)."),
366         optparse.make_option("--no-build", dest="build",
367             action="store_false", help="Don't check to see if the "
368                                        "DumpRenderTree build is up-to-date."),
369         optparse.make_option("-n", "--dry-run", action="store_true",
370             default=False,
371             help="Do everything but actually run the tests or upload results."),
372         optparse.make_option("--wrapper",
373             help="wrapper command to insert before invocations of "
374                  "DumpRenderTree; option is split on whitespace before "
375                  "running. (Example: --wrapper='valgrind --smc-check=all')"),
376         optparse.make_option("-i", "--ignore-tests", action="append", default=[],
377             help="directories or test to ignore (may specify multiple times)"),
378         optparse.make_option("--test-list", action="append",
379             help="read list of tests to run from file", metavar="FILE"),
380         optparse.make_option("--skipped", action="store", default="default",
381             help="control how tests marked SKIP are run. 'default' == Skip, 'ignore' == Run them anyway, 'only' == only run the SKIP tests."),
382         optparse.make_option("--force", dest="skipped", action="store_const", const='ignore',
383             help="Run all tests, even those marked SKIP in the test list (same as --skipped=ignore)"),
384         optparse.make_option("--time-out-ms",
385             help="Set the timeout for each test"),
386         optparse.make_option("--randomize-order", action="store_true",
387             default=False, help=("Run tests in random order (useful "
388                                 "for tracking down corruption)")),
389         optparse.make_option("--run-chunk",
390             help=("Run a specified chunk (n:l), the nth of len l, "
391                  "of the layout tests")),
392         optparse.make_option("--run-part", help=("Run a specified part (n:m), "
393                   "the nth of m parts, of the layout tests")),
394         optparse.make_option("--batch-size",
395             help=("Run a the tests in batches (n), after every n tests, "
396                   "DumpRenderTree is relaunched."), type="int", default=None),
397         optparse.make_option("--run-singly", action="store_true",
398             default=False, help="run a separate DumpRenderTree for each test (implies --verbose)"),
399         optparse.make_option("--child-processes",
400             help="Number of DumpRenderTrees to run in parallel."),
401         # FIXME: Display default number of child processes that will run.
402         optparse.make_option("-f", "--fully-parallel", action="store_true",
403             help="run all tests in parallel"),
404         optparse.make_option("--exit-after-n-failures", type="int", default=None,
405             help="Exit after the first N failures instead of running all "
406             "tests"),
407         optparse.make_option("--exit-after-n-crashes-or-timeouts", type="int",
408             default=None, help="Exit after the first N crashes instead of "
409             "running all tests"),
410         optparse.make_option("--iterations", type="int", default=1, help="Number of times to run the set of tests (e.g. ABCABCABC)"),
411         optparse.make_option("--repeat-each", type="int", default=1, help="Number of times to run each test (e.g. AAABBBCCC)"),
412         optparse.make_option("--retry-failures", action="store_true",
413             default=True,
414             help="Re-try any tests that produce unexpected results (default)"),
415         optparse.make_option("--no-retry-failures", action="store_false",
416             dest="retry_failures",
417             help="Don't re-try any tests that produce unexpected results."),
418         optparse.make_option("--max-locked-shards", type="int", default=1,
419             help="Set the maximum number of locked shards"),
420         optparse.make_option("--additional-env-var", type="string", action="append", default=[],
421             help="Passes that environment variable to the tests (--additional-env-var=NAME=VALUE)"),
422     ]))
423
424     option_group_definitions.append(("Miscellaneous Options", [
425         optparse.make_option("--lint-test-files", action="store_true",
426         default=False, help=("Makes sure the test files parse for all "
427                             "configurations. Does not run any tests.")),
428     ]))
429
430     # FIXME: Move these into json_results_generator.py
431     option_group_definitions.append(("Result JSON Options", [
432         optparse.make_option("--master-name", help="The name of the buildbot master."),
433         optparse.make_option("--builder-name", default="",
434             help=("The name of the builder shown on the waterfall running "
435                   "this script e.g. WebKit.")),
436         optparse.make_option("--build-name", default="DUMMY_BUILD_NAME",
437             help=("The name of the builder used in its path, e.g. "
438                   "webkit-rel.")),
439         optparse.make_option("--build-number", default="DUMMY_BUILD_NUMBER",
440             help=("The build number of the builder running this script.")),
441         optparse.make_option("--test-results-server", default="",
442             help=("If specified, upload results json files to this appengine "
443                   "server.")),
444     ]))
445
446     option_parser = optparse.OptionParser()
447
448     for group_name, group_options in option_group_definitions:
449         option_group = optparse.OptionGroup(option_parser, group_name)
450         option_group.add_options(group_options)
451         option_parser.add_option_group(option_group)
452
453     return option_parser.parse_args(args)
454
455
456 def main(argv=None):
457     try:
458         options, args = parse_args(argv)
459         if options.platform and 'test' in options.platform:
460             # It's a bit lame to import mocks into real code, but this allows the user
461             # to run tests against the test platform interactively, which is useful for
462             # debugging test failures.
463             from webkitpy.common.host_mock import MockHost
464             host = MockHost()
465         else:
466             host = Host()
467         port = host.port_factory.get(options.platform, options)
468     except NotImplementedError, e:
469         # FIXME: is this the best way to handle unsupported port names?
470         print >> sys.stderr, str(e)
471         return EXCEPTIONAL_EXIT_STATUS
472     except Exception, e:
473         print >> sys.stderr, '\n%s raised: %s' % (e.__class__.__name__, str(e))
474         traceback.print_exc(file=sys.stderr)
475         raise
476
477     logging.getLogger().setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
478     return run(port, options, args)
479
480
481 if '__main__' == __name__:
482     try:
483         return_code = main()
484     except BaseException, e:
485         if e.__class__ in (KeyboardInterrupt, TestRunInterruptedException):
486             sys.exit(INTERRUPTED_EXIT_STATUS)
487         sys.exit(EXCEPTIONAL_EXIT_STATUS)
488
489     sys.exit(return_code)