82543330d9d8c782e023071e87f3d07b96a4f448
[WebKit-https.git] / 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, 2016 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.test_run_results import INTERRUPTED_EXIT_STATUS
40 from webkitpy.port import configuration_options, platform_options
41 from webkitpy.layout_tests.views import buildbot_results
42 from webkitpy.layout_tests.views import printing
43
44
45 _log = logging.getLogger(__name__)
46
47
48 # This is a randomly chosen exit code that can be tested against to
49 # indicate that an unexpected exception occurred.
50 EXCEPTIONAL_EXIT_STATUS = 254
51
52
53 def main(argv, stdout, stderr):
54     options, args = parse_args(argv)
55
56     if options.platform and 'test' in options.platform:
57         # It's a bit lame to import mocks into real code, but this allows the user
58         # to run tests against the test platform interactively, which is useful for
59         # debugging test failures.
60         from webkitpy.common.host_mock import MockHost
61         host = MockHost()
62     else:
63         host = Host()
64
65     if options.lint_test_files:
66         from webkitpy.layout_tests.lint_test_expectations import lint
67         return lint(host, options, stderr)
68
69     try:
70         port = host.port_factory.get(options.platform, options)
71     except NotImplementedError, e:
72         # FIXME: is this the best way to handle unsupported port names?
73         print >> stderr, str(e)
74         return EXCEPTIONAL_EXIT_STATUS
75
76     if options.print_expectations:
77         return _print_expectations(port, options, args, stderr)
78
79     try:
80         # Force all tests to use a smaller stack so that stack overflow tests can run faster.
81         stackSizeInBytes = int(1.5 * 1024 * 1024)
82         options.additional_env_var.append('JSC_maxPerThreadStackUsage=' + str(stackSizeInBytes))
83         options.additional_env_var.append('__XPC_JSC_maxPerThreadStackUsage=' + str(stackSizeInBytes))
84         run_details = run(port, options, args, stderr)
85         if run_details.exit_code != -1 and not run_details.initial_results.keyboard_interrupted:
86             bot_printer = buildbot_results.BuildBotPrinter(stdout, options.debug_rwt_logging)
87             bot_printer.print_results(run_details)
88
89         return run_details.exit_code
90     # We still need to handle KeyboardInterrupt, at least for webkitpy unittest cases.
91     except KeyboardInterrupt:
92         return INTERRUPTED_EXIT_STATUS
93     except BaseException as e:
94         if isinstance(e, Exception):
95             print >> stderr, '\n%s raised: %s' % (e.__class__.__name__, str(e))
96             traceback.print_exc(file=stderr)
97         return EXCEPTIONAL_EXIT_STATUS
98
99
100 def parse_args(args):
101     option_group_definitions = []
102
103     option_group_definitions.append(("Platform options", platform_options()))
104     option_group_definitions.append(("Configuration options", configuration_options()))
105     option_group_definitions.append(("Printing Options", printing.print_options()))
106
107     option_group_definitions.append(("EFL-specific Options", [
108         optparse.make_option("--webprocess-cmd-prefix", type="string",
109             default=False, help="Prefix used when spawning the Web process (Debug mode only)"),
110     ]))
111
112     option_group_definitions.append(("Feature Switches", [
113         optparse.make_option("--complex-text", action="store_true", default=False,
114             help="Use the complex text code path for all text (OS X and Windows only)"),
115         optparse.make_option("--accelerated-drawing", action="store_true", default=False,
116             help="Use accelerated drawing (OS X only)"),
117         optparse.make_option("--remote-layer-tree", action="store_true", default=False,
118             help="Use the remote layer tree drawing model (OS X WebKit2 only)"),
119     ]))
120
121     option_group_definitions.append(("WebKit Options", [
122         optparse.make_option("--gc-between-tests", action="store_true", default=False,
123             help="Force garbage collection between each test"),
124         optparse.make_option("-l", "--leaks", action="store_true", default=False,
125             help="Enable leaks checking (OS X and Gtk+ only)"),
126         optparse.make_option("-g", "--guard-malloc", action="store_true", default=False,
127             help="Enable Guard Malloc (OS X only)"),
128         optparse.make_option("--threaded", action="store_true", default=False,
129             help="Run a concurrent JavaScript thread with each test"),
130         optparse.make_option("--dump-render-tree", "-1", action="store_false", default=True, dest="webkit_test_runner",
131             help="Use DumpRenderTree rather than WebKitTestRunner."),
132         # FIXME: We should merge this w/ --build-directory and only have one flag.
133         optparse.make_option("--root", action="store",
134             help="Path to a directory containing the executables needed to run tests."),
135     ]))
136
137     option_group_definitions.append(("Results Options", [
138         optparse.make_option("-p", "--pixel", "--pixel-tests", action="store_true",
139             dest="pixel_tests", help="Enable pixel-to-pixel PNG comparisons"),
140         optparse.make_option("--no-pixel", "--no-pixel-tests", action="store_false",
141             dest="pixel_tests", help="Disable pixel-to-pixel PNG comparisons"),
142         optparse.make_option("--no-sample-on-timeout", action="store_false", default=True,
143             dest="sample_on_timeout", help="Don't run sample on timeout (OS X only)"),
144         optparse.make_option("--no-ref-tests", action="store_true",
145             dest="no_ref_tests", help="Skip all ref tests"),
146         optparse.make_option("--tolerance",
147             help="Ignore image differences less than this percentage (some "
148                 "ports may ignore this option)", type="float"),
149         optparse.make_option("--results-directory", help="Location of test results"),
150         optparse.make_option("--build-directory",
151             help="Path to the directory under which build files are kept (should not include configuration)"),
152         optparse.make_option("--add-platform-exceptions", action="store_true", default=False,
153             help="Save generated results into the *most-specific-platform* directory rather than the *generic-platform* directory"),
154         optparse.make_option("--new-baseline", action="store_true",
155             default=False, help="Save generated results as new baselines "
156                  "into the *most-specific-platform* directory, overwriting whatever's "
157                  "already there. Equivalent to --reset-results --add-platform-exceptions"),
158         optparse.make_option("--reset-results", action="store_true",
159             default=False, help="Reset expectations to the "
160                  "generated results in their existing location."),
161         optparse.make_option("--no-new-test-results", action="store_false",
162             dest="new_test_results", default=True,
163             help="Don't create new baselines when no expected results exist"),
164         optparse.make_option("--treat-ref-tests-as-pixel-tests", action="store_true", default=False,
165             help="Run ref tests, but treat them as if they were traditional pixel tests"),
166
167         #FIXME: we should support a comma separated list with --pixel-test-directory as well.
168         optparse.make_option("--pixel-test-directory", action="append", default=[], dest="pixel_test_directories",
169             help="A directory where it is allowed to execute tests as pixel tests. "
170                  "Specify multiple times to add multiple directories. "
171                  "This option implies --pixel-tests. If specified, only those tests "
172                  "will be executed as pixel tests that are located in one of the "
173                  "directories enumerated with the option. Some ports may ignore this "
174                  "option while others can have a default value that can be overridden here."),
175
176         optparse.make_option("--skip-failing-tests", action="store_true",
177             default=False, help="Skip tests that are expected to fail. "
178                  "Note: When using this option, you might miss new crashes "
179                  "in these tests."),
180         optparse.make_option("--additional-drt-flag", action="append",
181             default=[], help="Additional command line flag to pass to DumpRenderTree "
182                  "Specify multiple times to add multiple flags."),
183         optparse.make_option("--driver-name", type="string",
184             help="Alternative DumpRenderTree binary to use"),
185         optparse.make_option("--additional-platform-directory", action="append",
186             default=[], help="Additional directory where to look for test "
187                  "baselines (will take precendence over platform baselines). "
188                  "Specify multiple times to add multiple search path entries."),
189         optparse.make_option("--additional-expectations", action="append", default=[],
190             help="Path to a test_expectations file that will override previous expectations. "
191                  "Specify multiple times for multiple sets of overrides."),
192         optparse.make_option("--compare-port", action="store", default=None,
193             help="Use the specified port's baselines first"),
194         optparse.make_option("--no-show-results", action="store_false",
195             default=True, dest="show_results",
196             help="Don't launch a browser with results after the tests "
197                  "are done"),
198         optparse.make_option("--full-results-html", action="store_true",
199             default=False,
200             help="Show all failures in results.html, rather than only regressions"),
201         optparse.make_option("--clobber-old-results", action="store_true",
202             default=False, help="Clobbers test results from previous runs."),
203         optparse.make_option("--http", action="store_true", dest="http",
204             default=True, help="Run HTTP and WebSocket tests (default)"),
205         optparse.make_option("--no-http", action="store_false", dest="http",
206             help="Don't run HTTP and WebSocket tests"),
207         optparse.make_option("--ignore-metrics", action="store_true", dest="ignore_metrics",
208             default=False, help="Ignore rendering metrics related information from test "
209             "output, only compare the structure of the rendertree."),
210         optparse.make_option("--nocheck-sys-deps", action="store_true",
211             default=False,
212             help="Don't check the system dependencies (themes)"),
213         optparse.make_option("--java", action="store_true",
214             default=False,
215             help="Build java support files"),
216         optparse.make_option("--layout-tests-directory", action="store", default=None,
217             help="Override the default layout test directory.", dest="layout_tests_dir")
218     ]))
219
220     option_group_definitions.append(("Testing Options", [
221         optparse.make_option("--build", dest="build",
222             action="store_true", default=True,
223             help="Check to ensure the DumpRenderTree build is up-to-date "
224                  "(default)."),
225         optparse.make_option("--no-build", dest="build",
226             action="store_false", help="Don't check to see if the "
227                                        "DumpRenderTree build is up-to-date."),
228         optparse.make_option("-n", "--dry-run", action="store_true",
229             default=False,
230             help="Do everything but actually run the tests or upload results."),
231         optparse.make_option("--wrapper",
232             help="wrapper command to insert before invocations of "
233                  "DumpRenderTree or WebKitTestRunner; option is split on whitespace before "
234                  "running. (Example: --wrapper='valgrind --smc-check=all')"),
235         optparse.make_option("-i", "--ignore-tests", action="append", default=[],
236             help="directories or test to ignore (may specify multiple times)"),
237         optparse.make_option("--test-list", action="append",
238             help="read list of tests to run from file", metavar="FILE"),
239         optparse.make_option("--skipped", action="store", default="default",
240             help=("control how tests marked SKIP are run. "
241                  "'default' == Skip tests unless explicitly listed on the command line, "
242                  "'ignore' == Run them anyway, "
243                  "'only' == only run the SKIP tests, "
244                  "'always' == always skip, even if listed on the command line.")),
245         optparse.make_option("--force", action="store_true", default=False,
246             help="Run all tests with PASS as expected result, even those marked SKIP in the test list (implies --skipped=ignore)"),
247         optparse.make_option("--time-out-ms",
248             help="Set the timeout for each test"),
249         optparse.make_option("--order", action="store", default="natural",
250             help=("determine the order in which the test cases will be run. "
251                   "'none' == use the order in which the tests were listed either in arguments or test list, "
252                   "'natural' == use the natural order (default), "
253                   "'random' == randomize the test order.")),
254         optparse.make_option("--run-chunk",
255             help=("Run a specified chunk (n:l), the nth of len l, "
256                  "of the layout tests")),
257         optparse.make_option("--run-part", help=("Run a specified part (n:m), "
258                   "the nth of m parts, of the layout tests")),
259         optparse.make_option("--batch-size",
260             help=("Run a the tests in batches (n), after every n tests, "
261                   "DumpRenderTree is relaunched."), type="int", default=None),
262         optparse.make_option("--run-singly", action="store_true",
263             default=False, help="run a separate DumpRenderTree for each test (implies --verbose)"),
264         optparse.make_option("--child-processes",
265             help="Number of DumpRenderTrees to run in parallel."),
266         # FIXME: Display default number of child processes that will run.
267         optparse.make_option("-f", "--fully-parallel", action="store_true",
268             help="run all tests in parallel"),
269         optparse.make_option("--exit-after-n-failures", type="int", default=None,
270             help="Exit after the first N failures instead of running all "
271             "tests"),
272         optparse.make_option("--exit-after-n-crashes-or-timeouts", type="int",
273             default=None, help="Exit after the first N crashes instead of "
274             "running all tests"),
275         optparse.make_option("--iterations", type="int", default=1, help="Number of times to run the set of tests (e.g. ABCABCABC)"),
276         optparse.make_option("--repeat-each", type="int", default=1, help="Number of times to run each test (e.g. AAABBBCCC)"),
277         optparse.make_option("--retry-failures", action="store_true",
278             default=True,
279             help="Re-try any tests that produce unexpected results (default)"),
280         optparse.make_option("--no-retry-failures", action="store_false",
281             dest="retry_failures",
282             help="Don't re-try any tests that produce unexpected results."),
283         optparse.make_option("--max-locked-shards", type="int", default=0,
284             help="Set the maximum number of locked shards"),
285         optparse.make_option("--additional-env-var", type="string", action="append", default=[],
286             help="Passes that environment variable to the tests (--additional-env-var=NAME=VALUE)"),
287         optparse.make_option("--profile", action="store_true",
288             help="Output per-test profile information."),
289         optparse.make_option("--profiler", action="store",
290             help="Output per-test profile information, using the specified profiler."),
291         optparse.make_option("--no-timeout", action="store_true", default=False, help="Disable test timeouts"),
292         optparse.make_option("--wayland",  action="store_true", default=False,
293             help="Run the layout tests inside a (virtualized) weston compositor (GTK only)."),
294     ]))
295
296     option_group_definitions.append(("iOS Simulator Options", [
297         optparse.make_option('--runtime', help='iOS Simulator runtime identifier (default: latest runtime)'),
298         optparse.make_option('--device-type', help='iOS Simulator device type identifier (default: i386 -> iPhone 5, x86_64 -> iPhone 5s)'),
299     ]))
300
301     option_group_definitions.append(("Miscellaneous Options", [
302         optparse.make_option("--lint-test-files", action="store_true",
303         default=False, help=("Makes sure the test files parse for all "
304                             "configurations. Does not run any tests.")),
305         optparse.make_option("--print-expectations", action="store_true",
306         default=False, help=("Print the expected outcome for the given test, or all tests listed in TestExpectations. "
307                             "Does not run any tests.")),
308     ]))
309
310     option_group_definitions.append(("Web Platform Test Server Options", [
311         optparse.make_option("--wptserver-doc-root", type="string", help=("Set web platform server document root, relative to LayoutTests directory")),
312     ]))
313
314     # FIXME: Move these into json_results_generator.py
315     option_group_definitions.append(("Result JSON Options", [
316         optparse.make_option("--master-name", help="The name of the buildbot master."),
317         optparse.make_option("--builder-name", default="",
318             help=("The name of the builder shown on the waterfall running this script. e.g. Apple MountainLion Release WK2 (Tests).")),
319         optparse.make_option("--build-name", default="DUMMY_BUILD_NAME",
320             help=("The name of the builder used in its path, e.g. webkit-rel.")),
321         optparse.make_option("--build-slave", default="DUMMY_BUILD_SLAVE",
322             help=("The name of the buildslave used. e.g. apple-macpro-6.")),
323         optparse.make_option("--build-number", default="DUMMY_BUILD_NUMBER",
324             help=("The build number of the builder running this script.")),
325         optparse.make_option("--test-results-server", default="",
326             help=("If specified, upload results json files to this appengine server.")),
327         optparse.make_option("--results-server-host", default="",
328             help=("If specified, upload results JSON file to this results server.")),
329         optparse.make_option("--additional-repository-name",
330             help=("The name of an additional subversion or git checkout")),
331         optparse.make_option("--additional-repository-path",
332             help=("The path to an additional subversion or git checkout (requires --additional-repository-name)")),
333         optparse.make_option("--allowed-host", type="string", action="append", default=[],
334             help=("If specified, tests are allowed to make requests to the specified hostname."))
335     ]))
336
337     option_parser = optparse.OptionParser()
338
339     for group_name, group_options in option_group_definitions:
340         option_group = optparse.OptionGroup(option_parser, group_name)
341         option_group.add_options(group_options)
342         option_parser.add_option_group(option_group)
343
344     return option_parser.parse_args(args)
345
346
347 def _print_expectations(port, options, args, logging_stream):
348     logger = logging.getLogger()
349     logger.setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
350     try:
351         printer = printing.Printer(port, options, logging_stream, logger=logger)
352
353         _set_up_derived_options(port, options)
354         manager = Manager(port, options, printer)
355
356         exit_code = manager.print_expectations(args)
357         _log.debug("Printing expectations completed, Exit status: %d", exit_code)
358         return exit_code
359     except Exception as error:
360         _log.error('Error printing expectations: {}'.format(error))
361     finally:
362         printer.cleanup()
363         return -1
364
365 def _set_up_derived_options(port, options):
366     """Sets the options values that depend on other options values."""
367     if not options.child_processes:
368         options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
369                                                  str(port.default_child_processes()))
370
371     if not options.configuration:
372         options.configuration = port.default_configuration()
373
374     if options.pixel_tests is None:
375         options.pixel_tests = port.default_pixel_tests()
376
377     if not options.time_out_ms:
378         options.time_out_ms = str(port.default_timeout_ms())
379
380     options.slow_time_out_ms = str(5 * int(options.time_out_ms))
381
382     if options.additional_platform_directory:
383         additional_platform_directories = []
384         for path in options.additional_platform_directory:
385             additional_platform_directories.append(port.host.filesystem.abspath(path))
386         options.additional_platform_directory = additional_platform_directories
387
388     if options.force:
389         if options.skipped not in ('ignore', 'default'):
390             _log.warning("--force overrides --skipped=%s" % (options.skipped))
391         options.skipped = 'ignore'
392
393     if not options.http and options.skipped in ('ignore', 'only'):
394         _log.warning("--force/--skipped=%s overrides --no-http." % (options.skipped))
395         options.http = True
396
397     if options.ignore_metrics and (options.new_baseline or options.reset_results):
398         _log.warning("--ignore-metrics has no effect with --new-baselines or with --reset-results")
399
400     if options.new_baseline:
401         options.reset_results = True
402         options.add_platform_exceptions = True
403
404     if options.pixel_test_directories:
405         options.pixel_tests = True
406         varified_dirs = set()
407         pixel_test_directories = options.pixel_test_directories
408         for directory in pixel_test_directories:
409             # FIXME: we should support specifying the directories all the ways we support it for additional
410             # arguments specifying which tests and directories to run. We should also move the logic for that
411             # to Port.
412             filesystem = port.host.filesystem
413             if not filesystem.isdir(filesystem.join(port.layout_tests_dir(), directory)):
414                 _log.warning("'%s' was passed to --pixel-test-directories, which doesn't seem to be a directory" % str(directory))
415             else:
416                 varified_dirs.add(directory)
417
418         options.pixel_test_directories = list(varified_dirs)
419
420     if options.run_singly:
421         options.verbose = True
422
423     # The GTK+ and EFL ports only support WebKit2 so they always use WKTR.
424     if options.platform == "gtk" or options.platform == "efl":
425         options.webkit_test_runner = True
426
427
428 def run(port, options, args, logging_stream):
429     logger = logging.getLogger()
430     logger.setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
431
432     try:
433         printer = printing.Printer(port, options, logging_stream, logger=logger)
434
435         _set_up_derived_options(port, options)
436         manager = Manager(port, options, printer)
437         printer.print_config(port.results_directory())
438
439         run_details = manager.run(args)
440         _log.debug("Testing completed, Exit status: %d" % run_details.exit_code)
441         return run_details
442     finally:
443         printer.cleanup()
444
445 if __name__ == '__main__':
446     sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))