run_webkit_tests.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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. import logging
  31. import optparse
  32. import os
  33. import signal
  34. import sys
  35. import traceback
  36. from webkitpy.common.host import Host
  37. from webkitpy.layout_tests.controllers.manager import Manager
  38. from webkitpy.port import configuration_options, platform_options
  39. from webkitpy.layout_tests.views import buildbot_results
  40. from webkitpy.layout_tests.views import printing
  41. _log = logging.getLogger(__name__)
  42. # This mirrors what the shell normally does.
  43. INTERRUPTED_EXIT_STATUS = signal.SIGINT + 128
  44. # This is a randomly chosen exit code that can be tested against to
  45. # indicate that an unexpected exception occurred.
  46. EXCEPTIONAL_EXIT_STATUS = 254
  47. def main(argv, stdout, stderr):
  48. options, args = parse_args(argv)
  49. if options.platform and 'test' in options.platform:
  50. # It's a bit lame to import mocks into real code, but this allows the user
  51. # to run tests against the test platform interactively, which is useful for
  52. # debugging test failures.
  53. from webkitpy.common.host_mock import MockHost
  54. host = MockHost()
  55. else:
  56. host = Host()
  57. if options.lint_test_files:
  58. from webkitpy.layout_tests.lint_test_expectations import lint
  59. return lint(host, options, stderr)
  60. try:
  61. port = host.port_factory.get(options.platform, options)
  62. except NotImplementedError, e:
  63. # FIXME: is this the best way to handle unsupported port names?
  64. print >> stderr, str(e)
  65. return EXCEPTIONAL_EXIT_STATUS
  66. try:
  67. run_details = run(port, options, args, stderr)
  68. if run_details.exit_code != -1:
  69. bot_printer = buildbot_results.BuildBotPrinter(stdout, options.debug_rwt_logging)
  70. bot_printer.print_results(run_details)
  71. return run_details.exit_code
  72. except KeyboardInterrupt:
  73. return INTERRUPTED_EXIT_STATUS
  74. except BaseException as e:
  75. if isinstance(e, Exception):
  76. print >> stderr, '\n%s raised: %s' % (e.__class__.__name__, str(e))
  77. traceback.print_exc(file=stderr)
  78. return EXCEPTIONAL_EXIT_STATUS
  79. def parse_args(args):
  80. option_group_definitions = []
  81. option_group_definitions.append(("Platform options", platform_options()))
  82. option_group_definitions.append(("Configuration options", configuration_options()))
  83. option_group_definitions.append(("Printing Options", printing.print_options()))
  84. option_group_definitions.append(("EFL-specific Options", [
  85. optparse.make_option("--webprocess-cmd-prefix", type="string",
  86. default=False, help="Prefix used when spawning the Web process (Debug mode only)"),
  87. ]))
  88. option_group_definitions.append(("WebKit Options", [
  89. optparse.make_option("--gc-between-tests", action="store_true", default=False,
  90. help="Force garbage collection between each test"),
  91. optparse.make_option("--complex-text", action="store_true", default=False,
  92. help="Use the complex text code path for all text (Mac OS X and Windows only)"),
  93. optparse.make_option("-l", "--leaks", action="store_true", default=False,
  94. help="Enable leaks checking (Mac OS X only)"),
  95. optparse.make_option("-g", "--guard-malloc", action="store_true", default=False,
  96. help="Enable Guard Malloc (Mac OS X only)"),
  97. optparse.make_option("--threaded", action="store_true", default=False,
  98. help="Run a concurrent JavaScript thread with each test"),
  99. optparse.make_option("--webkit-test-runner", "-2", action="store_true",
  100. help="Use WebKitTestRunner rather than DumpRenderTree."),
  101. # FIXME: We should merge this w/ --build-directory and only have one flag.
  102. optparse.make_option("--root", action="store",
  103. help="Path to a directory containing the executables needed to run tests."),
  104. ]))
  105. option_group_definitions.append(("Results Options", [
  106. optparse.make_option("-p", "--pixel", "--pixel-tests", action="store_true",
  107. dest="pixel_tests", help="Enable pixel-to-pixel PNG comparisons"),
  108. optparse.make_option("--no-pixel", "--no-pixel-tests", action="store_false",
  109. dest="pixel_tests", help="Disable pixel-to-pixel PNG comparisons"),
  110. optparse.make_option("--no-sample-on-timeout", action="store_false",
  111. dest="sample_on_timeout", help="Don't run sample on timeout (Mac OS X only)"),
  112. optparse.make_option("--no-ref-tests", action="store_true",
  113. dest="no_ref_tests", help="Skip all ref tests"),
  114. optparse.make_option("--tolerance",
  115. help="Ignore image differences less than this percentage (some "
  116. "ports may ignore this option)", type="float"),
  117. optparse.make_option("--results-directory", help="Location of test results"),
  118. optparse.make_option("--build-directory",
  119. help="Path to the directory under which build files are kept (should not include configuration)"),
  120. optparse.make_option("--add-platform-exceptions", action="store_true", default=False,
  121. help="Save generated results into the *most-specific-platform* directory rather than the *generic-platform* directory"),
  122. optparse.make_option("--new-baseline", action="store_true",
  123. default=False, help="Save generated results as new baselines "
  124. "into the *most-specific-platform* directory, overwriting whatever's "
  125. "already there. Equivalent to --reset-results --add-platform-exceptions"),
  126. optparse.make_option("--reset-results", action="store_true",
  127. default=False, help="Reset expectations to the "
  128. "generated results in their existing location."),
  129. optparse.make_option("--no-new-test-results", action="store_false",
  130. dest="new_test_results", default=True,
  131. help="Don't create new baselines when no expected results exist"),
  132. #FIXME: we should support a comma separated list with --pixel-test-directory as well.
  133. optparse.make_option("--pixel-test-directory", action="append", default=[], dest="pixel_test_directories",
  134. help="A directory where it is allowed to execute tests as pixel tests. "
  135. "Specify multiple times to add multiple directories. "
  136. "This option implies --pixel-tests. If specified, only those tests "
  137. "will be executed as pixel tests that are located in one of the "
  138. "directories enumerated with the option. Some ports may ignore this "
  139. "option while others can have a default value that can be overridden here."),
  140. optparse.make_option("--skip-failing-tests", action="store_true",
  141. default=False, help="Skip tests that are expected to fail. "
  142. "Note: When using this option, you might miss new crashes "
  143. "in these tests."),
  144. optparse.make_option("--additional-drt-flag", action="append",
  145. default=[], help="Additional command line flag to pass to DumpRenderTree "
  146. "Specify multiple times to add multiple flags."),
  147. optparse.make_option("--driver-name", type="string",
  148. help="Alternative DumpRenderTree binary to use"),
  149. optparse.make_option("--additional-platform-directory", action="append",
  150. default=[], help="Additional directory where to look for test "
  151. "baselines (will take precendence over platform baselines). "
  152. "Specify multiple times to add multiple search path entries."),
  153. optparse.make_option("--additional-expectations", action="append", default=[],
  154. help="Path to a test_expectations file that will override previous expectations. "
  155. "Specify multiple times for multiple sets of overrides."),
  156. optparse.make_option("--compare-port", action="store", default=None,
  157. help="Use the specified port's baselines first"),
  158. optparse.make_option("--no-show-results", action="store_false",
  159. default=True, dest="show_results",
  160. help="Don't launch a browser with results after the tests "
  161. "are done"),
  162. optparse.make_option("--full-results-html", action="store_true",
  163. default=False,
  164. help="Show all failures in results.html, rather than only regressions"),
  165. optparse.make_option("--clobber-old-results", action="store_true",
  166. default=False, help="Clobbers test results from previous runs."),
  167. optparse.make_option("--http", action="store_true", dest="http",
  168. default=True, help="Run HTTP and WebSocket tests (default)"),
  169. optparse.make_option("--no-http", action="store_false", dest="http",
  170. help="Don't run HTTP and WebSocket tests"),
  171. optparse.make_option("--ignore-metrics", action="store_true", dest="ignore_metrics",
  172. default=False, help="Ignore rendering metrics related information from test "
  173. "output, only compare the structure of the rendertree."),
  174. optparse.make_option("--nocheck-sys-deps", action="store_true",
  175. default=False,
  176. help="Don't check the system dependencies (themes)"),
  177. optparse.make_option("--nojava", action="store_true",
  178. default=False,
  179. help="Don't build java support files"),
  180. ]))
  181. option_group_definitions.append(("Testing Options", [
  182. optparse.make_option("--build", dest="build",
  183. action="store_true", default=True,
  184. help="Check to ensure the DumpRenderTree build is up-to-date "
  185. "(default)."),
  186. optparse.make_option("--no-build", dest="build",
  187. action="store_false", help="Don't check to see if the "
  188. "DumpRenderTree build is up-to-date."),
  189. optparse.make_option("-n", "--dry-run", action="store_true",
  190. default=False,
  191. help="Do everything but actually run the tests or upload results."),
  192. optparse.make_option("--wrapper",
  193. help="wrapper command to insert before invocations of "
  194. "DumpRenderTree; option is split on whitespace before "
  195. "running. (Example: --wrapper='valgrind --smc-check=all')"),
  196. optparse.make_option("-i", "--ignore-tests", action="append", default=[],
  197. help="directories or test to ignore (may specify multiple times)"),
  198. optparse.make_option("--test-list", action="append",
  199. help="read list of tests to run from file", metavar="FILE"),
  200. optparse.make_option("--skipped", action="store", default="default",
  201. help=("control how tests marked SKIP are run. "
  202. "'default' == Skip tests unless explicitly listed on the command line, "
  203. "'ignore' == Run them anyway, "
  204. "'only' == only run the SKIP tests, "
  205. "'always' == always skip, even if listed on the command line.")),
  206. optparse.make_option("--force", dest="skipped", action="store_const", const='ignore',
  207. help="Run all tests, even those marked SKIP in the test list (same as --skipped=ignore)"),
  208. optparse.make_option("--time-out-ms",
  209. help="Set the timeout for each test"),
  210. optparse.make_option("--order", action="store", default="natural",
  211. help=("determine the order in which the test cases will be run. "
  212. "'none' == use the order in which the tests were listed either in arguments or test list, "
  213. "'natural' == use the natural order (default), "
  214. "'random' == randomize the test order.")),
  215. optparse.make_option("--run-chunk",
  216. help=("Run a specified chunk (n:l), the nth of len l, "
  217. "of the layout tests")),
  218. optparse.make_option("--run-part", help=("Run a specified part (n:m), "
  219. "the nth of m parts, of the layout tests")),
  220. optparse.make_option("--batch-size",
  221. help=("Run a the tests in batches (n), after every n tests, "
  222. "DumpRenderTree is relaunched."), type="int", default=None),
  223. optparse.make_option("--chunk-size",
  224. help=("Run a chunk of n tests with every launch of WebKitTestRunnerOrbis"), type="int", default="1"),
  225. optparse.make_option("--run-singly", action="store_true",
  226. default=False, help="run a separate DumpRenderTree for each test (implies --verbose)"),
  227. optparse.make_option("--child-processes",
  228. help="Number of DumpRenderTrees to run in parallel."),
  229. # FIXME: Display default number of child processes that will run.
  230. optparse.make_option("-f", "--fully-parallel", action="store_true",
  231. help="run all tests in parallel"),
  232. optparse.make_option("--exit-after-n-failures", type="int", default=None,
  233. help="Exit after the first N failures instead of running all "
  234. "tests"),
  235. optparse.make_option("--exit-after-n-crashes-or-timeouts", type="int",
  236. default=None, help="Exit after the first N crashes instead of "
  237. "running all tests"),
  238. optparse.make_option("--iterations", type="int", default=1, help="Number of times to run the set of tests (e.g. ABCABCABC)"),
  239. optparse.make_option("--repeat-each", type="int", default=1, help="Number of times to run each test (e.g. AAABBBCCC)"),
  240. optparse.make_option("--retry-failures", action="store_true",
  241. default=True,
  242. help="Re-try any tests that produce unexpected results (default)"),
  243. optparse.make_option("--no-retry-failures", action="store_false",
  244. dest="retry_failures",
  245. help="Don't re-try any tests that produce unexpected results."),
  246. optparse.make_option("--max-locked-shards", type="int", default=0,
  247. help="Set the maximum number of locked shards"),
  248. optparse.make_option("--additional-env-var", type="string", action="append", default=[],
  249. help="Passes that environment variable to the tests (--additional-env-var=NAME=VALUE)"),
  250. optparse.make_option("--profile", action="store_true",
  251. help="Output per-test profile information."),
  252. optparse.make_option("--profiler", action="store",
  253. help="Output per-test profile information, using the specified profiler."),
  254. ]))
  255. option_group_definitions.append(("Miscellaneous Options", [
  256. optparse.make_option("--lint-test-files", action="store_true",
  257. default=False, help=("Makes sure the test files parse for all "
  258. "configurations. Does not run any tests.")),
  259. ]))
  260. # FIXME: Move these into json_results_generator.py
  261. option_group_definitions.append(("Result JSON Options", [
  262. optparse.make_option("--master-name", help="The name of the buildbot master."),
  263. optparse.make_option("--builder-name", default="",
  264. help=("The name of the builder shown on the waterfall running "
  265. "this script e.g. WebKit.")),
  266. optparse.make_option("--build-name", default="DUMMY_BUILD_NAME",
  267. help=("The name of the builder used in its path, e.g. "
  268. "webkit-rel.")),
  269. optparse.make_option("--build-number", default="DUMMY_BUILD_NUMBER",
  270. help=("The build number of the builder running this script.")),
  271. optparse.make_option("--test-results-server", default="",
  272. help=("If specified, upload results json files to this appengine "
  273. "server.")),
  274. ]))
  275. option_parser = optparse.OptionParser()
  276. for group_name, group_options in option_group_definitions:
  277. option_group = optparse.OptionGroup(option_parser, group_name)
  278. option_group.add_options(group_options)
  279. option_parser.add_option_group(option_group)
  280. return option_parser.parse_args(args)
  281. def _set_up_derived_options(port, options):
  282. """Sets the options values that depend on other options values."""
  283. if not options.child_processes:
  284. options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
  285. str(port.default_child_processes()))
  286. if not options.max_locked_shards:
  287. options.max_locked_shards = int(os.environ.get("WEBKIT_TEST_MAX_LOCKED_SHARDS",
  288. str(port.default_max_locked_shards())))
  289. if not options.configuration:
  290. options.configuration = port.default_configuration()
  291. if options.pixel_tests is None:
  292. options.pixel_tests = port.default_pixel_tests()
  293. if not options.time_out_ms:
  294. options.time_out_ms = str(port.default_timeout_ms())
  295. options.slow_time_out_ms = str(5 * int(options.time_out_ms))
  296. if options.additional_platform_directory:
  297. additional_platform_directories = []
  298. for path in options.additional_platform_directory:
  299. additional_platform_directories.append(port.host.filesystem.abspath(path))
  300. options.additional_platform_directory = additional_platform_directories
  301. if not options.http and options.skipped in ('ignore', 'only'):
  302. _log.warning("--force/--skipped=%s overrides --no-http." % (options.skipped))
  303. options.http = True
  304. if options.ignore_metrics and (options.new_baseline or options.reset_results):
  305. _log.warning("--ignore-metrics has no effect with --new-baselines or with --reset-results")
  306. if options.new_baseline:
  307. options.reset_results = True
  308. options.add_platform_exceptions = True
  309. if options.pixel_test_directories:
  310. options.pixel_tests = True
  311. varified_dirs = set()
  312. pixel_test_directories = options.pixel_test_directories
  313. for directory in pixel_test_directories:
  314. # FIXME: we should support specifying the directories all the ways we support it for additional
  315. # arguments specifying which tests and directories to run. We should also move the logic for that
  316. # to Port.
  317. filesystem = port.host.filesystem
  318. if not filesystem.isdir(filesystem.join(port.layout_tests_dir(), directory)):
  319. _log.warning("'%s' was passed to --pixel-test-directories, which doesn't seem to be a directory" % str(directory))
  320. else:
  321. varified_dirs.add(directory)
  322. options.pixel_test_directories = list(varified_dirs)
  323. if options.run_singly:
  324. options.verbose = True
  325. def _validate_options(port, options):
  326. format_string = '%s option not supported with Multi-test-runner mode, option will be reset'
  327. if options.pixel_tests:
  328. _log.warning(format_string % '--pixel-tests')
  329. options.pixel_tests = False
  330. if int(options.child_processes) > 1 or options.fully_parallel:
  331. _log.warning(format_string % '--child-processes or --fully-parallel')
  332. options.child_processes = 1
  333. options.fully_parallel = False
  334. def run(port, options, args, logging_stream):
  335. logger = logging.getLogger()
  336. logger.setLevel(logging.DEBUG if options.debug_rwt_logging else logging.INFO)
  337. try:
  338. printer = printing.Printer(port, options, logging_stream, logger=logger)
  339. _set_up_derived_options(port, options)
  340. # Validate options for compatibility running WKTR MultiTestRunner Mode; --chunk-size > 1
  341. if options.chunk_size > 1 and options.platform == 'orbis':
  342. _validate_options(port, options)
  343. manager = Manager(port, options, printer)
  344. printer.print_config(port.results_directory())
  345. run_details = manager.run(args)
  346. _log.debug("Testing completed, Exit status: %d" % run_details.exit_code)
  347. return run_details
  348. finally:
  349. printer.cleanup()
  350. if __name__ == '__main__':
  351. sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))