1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 from abc
import ABCMeta
, abstractmethod
, abstractproperty
10 from argparse
import SUPPRESS
, ArgumentParser
11 from distutils
import spawn
12 from distutils
.util
import strtobool
13 from itertools
import chain
19 from mozprofile
import DEFAULT_PORTS
20 from six
.moves
.urllib
.parse
import urlparse
22 here
= os
.path
.abspath(os
.path
.dirname(__file__
))
25 from mozbuild
.base
import MachCommandConditions
as conditions
26 from mozbuild
.base
import MozbuildObject
28 build_obj
= MozbuildObject
.from_environment(cwd
=here
)
34 # Maps test flavors to data needed to run them
38 "aliases": ("plain", "mochitest"),
39 "enabled_apps": ("firefox", "android"),
43 "install_subdir": "tests",
47 "aliases": ("chrome", "mochitest-chrome"),
48 "enabled_apps": ("firefox"),
55 "aliases": ("browser", "browser-chrome", "mochitest-browser-chrome", "bc"),
56 "enabled_apps": ("firefox", "thunderbird"),
63 "aliases": ("a11y", "mochitest-a11y", "accessibility"),
64 "enabled_apps": ("firefox",),
70 SUPPORTED_FLAVORS
= list(
71 chain
.from_iterable([f
["aliases"] for f
in ALL_FLAVORS
.values()])
73 CANONICAL_FLAVORS
= sorted([f
["aliases"][0] for f
in ALL_FLAVORS
.values()])
76 def get_default_valgrind_suppression_files():
77 # We are trying to locate files in the source tree. So if we
78 # don't know where the source tree is, we must give up.
80 # When this is being run by |mach mochitest --valgrind ...|, it is
81 # expected that |build_obj| is not None, and so the logic below will
82 # select the correct suppression files.
84 # When this is run from mozharness, |build_obj| is None, and we expect
85 # that testing/mozharness/configs/unittests/linux_unittests.py will
86 # select the correct suppression files (and paths to them) and
87 # will specify them using the --valgrind-supp-files= flag. Hence this
88 # function will not get called when running from mozharness.
90 # Note: keep these Valgrind .sup file names consistent with those
91 # in testing/mozharness/configs/unittests/linux_unittest.py.
92 if build_obj
is None or build_obj
.topsrcdir
is None:
95 supps_path
= os
.path
.join(build_obj
.topsrcdir
, "build", "valgrind")
98 if mozinfo
.os
== "linux":
99 if mozinfo
.processor
== "x86_64":
100 rv
.append(os
.path
.join(supps_path
, "x86_64-pc-linux-gnu.sup"))
101 rv
.append(os
.path
.join(supps_path
, "cross-architecture.sup"))
102 elif mozinfo
.processor
== "x86":
103 rv
.append(os
.path
.join(supps_path
, "i386-pc-linux-gnu.sup"))
104 rv
.append(os
.path
.join(supps_path
, "cross-architecture.sup"))
109 @six.add_metaclass(ABCMeta
)
110 class ArgumentContainer
:
120 def validate(self
, parser
, args
, context
):
123 def get_full_path(self
, path
, cwd
):
124 """Get an absolute path relative to cwd."""
125 return os
.path
.normpath(os
.path
.join(cwd
, os
.path
.expanduser(path
)))
128 class MochitestArguments(ArgumentContainer
):
129 """General mochitest arguments."""
131 LOG_LEVELS
= ("DEBUG", "INFO", "WARNING", "ERROR", "FATAL")
140 "help": "Test to run. Can be a single test file or a directory of tests "
141 "(to run recursively). If omitted, the entire suite is run.",
147 "choices": SUPPORTED_FLAVORS
,
148 "metavar": "{{{}}}".format(", ".join(CANONICAL_FLAVORS
)),
150 "help": "Only run tests of this flavor.",
160 "help": "Always keep the browser open after tests complete. Or always close the "
161 "browser with --keep-open=false",
170 "Override the default binary used to run tests with the path provided, e.g "
171 "/usr/bin/firefox. If you have run ./mach package beforehand, you can "
172 "specify 'dist' to run tests against the distribution bundle's binary."
179 "dest": "utilityPath",
180 "default": build_obj
.bindir
if build_obj
is not None else None,
181 "help": "absolute path to directory containing utility programs "
182 "(xpcshell, ssltunnel, certutil)",
187 ["--certificate-path"],
191 "help": "absolute path to directory containing certificate store to use testing profile", # NOQA: E501
198 "action": "store_false",
201 "help": "Do not start running tests automatically.",
209 "help": "The per-test timeout in seconds (default: 60 seconds).",
216 "dest": "maxTimeouts",
218 "help": "The maximum number of timeouts permitted before halting testing.",
225 "dest": "totalChunks",
226 "help": "Total number of chunks to split tests into.",
235 "help": "If running tests by chunks, the chunk number to run.",
240 ["--chunk-by-runtime"],
242 "action": "store_true",
243 "dest": "chunkByRuntime",
244 "help": "Group tests such that each chunk has roughly the same runtime.",
252 "dest": "chunkByDir",
253 "help": "Group tests together in the same chunk that are in the same top "
254 "chunkByDir directories.",
259 ["--run-by-manifest"],
261 "action": "store_true",
262 "dest": "runByManifest",
263 "help": "Run each manifest in a single browser instance with a fresh profile.",
271 "action": "store_true",
272 "help": "Shuffle execution order of tests.",
279 "dest": "consoleLevel",
280 "choices": LOG_LEVELS
,
282 "help": "One of {} to determine the level of console logging.".format(
283 ", ".join(LOG_LEVELS
)
291 "dest": "bisectChunk",
293 "help": "Specify the failing test name to find the previous tests that may be "
294 "causing the failure.",
302 "help": "Start running the test sequence at this test.",
310 "help": "Stop running the test sequence at this test.",
317 "help": "Subsuite of tests to run. Unlike tags, subsuites also remove tests from "
318 "the default set. Only one can be specified at once.",
325 "dest": "environment",
326 "metavar": "NAME=VALUE",
328 "help": "Sets the given variable in the application's environment.",
332 ["--exclude-extension"],
335 "dest": "extensionsToExclude",
337 "help": "Excludes the given extension from being installed in the test profile.",
345 "dest": "browserArgs",
347 "help": "Provides an argument to the test application (e.g Firefox).",
352 ["--leak-threshold"],
355 "dest": "defaultLeakThreshold",
357 "help": "Fail if the number of bytes leaked in default processes through "
358 "refcounted objects (or bytes in classes with MOZ_COUNT_CTOR and "
359 "MOZ_COUNT_DTOR) is greater than the given number.",
364 ["--fatal-assertions"],
366 "action": "store_true",
367 "dest": "fatalAssertions",
369 "help": "Abort testing whenever an assertion is hit (requires a debug build to "
375 ["--extra-profile-file"],
378 "dest": "extraProfileFiles",
380 "help": "Copy specified files/dirs to testing profile. Can be specified more "
386 ["--install-extension"],
389 "dest": "extensionsToInstall",
391 "help": "Install the specified extension in the testing profile. Can be a path "
398 "dest": "profilePath",
400 "help": "Directory where the profile will be stored. This directory will be "
401 "deleted after the tests are finished.",
406 ["--conditioned-profile"],
408 "dest": "conditionedProfile",
409 "action": "store_true",
411 "help": "Download and run with a full conditioned profile.",
415 ["--testing-modules-dir"],
417 "dest": "testingModulesDir",
419 "help": "Directory where testing-only JS modules are located.",
428 "help": "Repeat the tests the given number of times.",
432 ["--run-until-failure"],
434 "action": "store_true",
435 "dest": "runUntilFailure",
437 "help": "Run tests repeatedly but stop the first time a test fails. Default cap "
438 "is 30 runs, which can be overridden with the --repeat parameter.",
444 "dest": "manifestFile",
446 "help": "Path to a manifestparser (.ini formatted) manifest of tests to run.",
451 ["--extra-mozinfo-json"],
453 "dest": "extra_mozinfo_json",
455 "help": "Filter tests based on a given mozinfo file.",
460 ["--testrun-manifest-file"],
462 "dest": "testRunManifestFile",
463 "default": "tests.json",
464 "help": "Overrides the default filename of the tests.json manifest file that is "
465 "generated by the harness and used by SimpleTest. Only useful when running "
466 "multiple test runs simulatenously on the same machine.",
473 "dest": "dump_tests",
475 "help": "Specify path to a filename to dump all the tests that will be run",
482 "dest": "failureFile",
484 "help": "Filename of the output file where we can store a .json list of failures "
485 "to be run in the future with --run-only-tests.",
492 "action": "store_true",
495 "help": "Delay execution between tests.",
503 "help": "Path to the httpd.js file.",
508 ["--use-http3-server"],
510 "dest": "useHttp3Server",
512 "help": "Whether to use the Http3 server",
513 "action": "store_true",
517 ["--use-http2-server"],
519 "dest": "useHttp2Server",
521 "help": "Whether to use the Http2 server",
522 "action": "store_true",
529 "metavar": "PREF=VALUE",
531 "dest": "extraPrefs",
532 "help": "Defines an extra user preference.",
538 "action": "store_true",
540 "help": "Open the Browser Console.",
546 "action": "store_true",
548 "help": "Start the browser JS debugger before running the test.",
552 ["--jsdebugger-path"],
555 "dest": "jsdebuggerPath",
556 "help": "Path to a Firefox binary that will be used to run the toolbox. Should "
557 "be used together with --jsdebugger.",
561 ["--debug-on-failure"],
563 "action": "store_true",
565 "dest": "debugOnFailure",
566 "help": "Breaks execution and enters the JS debugger on a test failure. Should "
567 "be used together with --jsdebugger.",
573 "action": "store_false",
576 "help": "Run tests with electrolysis preferences and test filtering disabled.",
580 ["--enable-a11y-checks"],
582 "action": "store_true",
584 "dest": "a11y_checks",
585 "help": "Run tests with accessibility checks enabled.",
589 ["--disable-fission"],
591 "action": "store_true",
593 "dest": "disable_fission",
594 "help": "Run tests with fission (site isolation) disabled.",
598 ["--enable-xorigin-tests"],
600 "action": "store_true",
602 "dest": "xOriginTests",
603 "help": "Run tests in a cross origin iframe.",
607 ["--store-chrome-manifest"],
610 "help": "Destination path to write a copy of any chrome manifest "
611 "written by the harness.",
617 ["--jscov-dir-prefix"],
620 "help": "Directory to store per-test line coverage data as json "
621 "(browser-chrome only). To emit lcov formatted data, set "
622 "JS_CODE_COVERAGE_OUTPUT_DIR in the environment.",
630 "action": "store_true",
632 "help": "Run tests with DMD active.",
636 ["--dump-output-directory"],
639 "dest": "dumpOutputDirectory",
640 "help": "Specifies the directory in which to place dumped memory reports.",
644 ["--dump-about-memory-after-test"],
646 "action": "store_true",
648 "dest": "dumpAboutMemoryAfterTest",
649 "help": "Dump an about:memory log after each test in the directory specified "
650 "by --dump-output-directory.",
654 ["--dump-dmd-after-test"],
656 "action": "store_true",
658 "dest": "dumpDMDAfterTest",
659 "help": "Dump a DMD log (and an accompanying about:memory log) after each test. "
660 "These will be dumped into your default temp directory, NOT the directory "
661 "specified by --dump-output-directory. The logs are numbered by test, and "
662 "each test will include output that indicates the DMD output filename.",
666 ["--screenshot-on-fail"],
668 "action": "store_true",
670 "dest": "screenshotOnFail",
671 "help": "Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory " # NOQA: E501
672 "for storing the screenshots.",
678 "action": "store_true",
681 "help": "Do not print test log lines unless a failure occurs.",
687 "action": "store_true",
690 "help": "Run tests in headless mode.",
698 "help": "Name of the pidfile to generate.",
703 ["--use-test-media-devices"],
705 "action": "store_true",
707 "dest": "useTestMediaDevices",
708 "help": "Use test media device drivers for media testing.",
715 "help": "Path to fake GMP plugin. Will be deduced from the binary if not passed.",
723 "default": None, # individual scripts will set a sane default
724 "help": "Absolute path to directory containing XRE (probably xulrunner).",
731 "dest": "symbolsPath",
733 "help": "Absolute path to directory containing breakpad symbols, or the URL of a "
734 "zip file containing symbols",
742 "help": "Debugger binary to run tests in. Program name or path.",
748 "dest": "debuggerArgs",
750 "help": "Arguments to pass to the debugger.",
757 "help": "Valgrind binary to run tests with. Program name or path.",
763 "dest": "valgrindArgs",
765 "help": "Comma-separated list of extra arguments to pass to Valgrind.",
769 ["--valgrind-supp-files"],
771 "dest": "valgrindSuppFiles",
773 "help": "Comma-separated list of suppression files to pass to Valgrind.",
777 ["--debugger-interactive"],
779 "action": "store_true",
780 "dest": "debuggerInteractive",
782 "help": "Prevents the test harness from redirecting stdout and stderr for "
783 "interactive debuggers.",
793 "help": "Filter out tests that don't have the given tag. Can be used multiple "
794 "times in which case the test must contain at least one of the given tags.",
801 "help": "host:port to use when connecting to Marionette",
805 ["--marionette-socket-timeout"],
808 "help": "Timeout while waiting to receive a message from the marionette server.",
813 ["--marionette-startup-timeout"],
816 "help": "Timeout while waiting for marionette server startup.",
821 ["--cleanup-crashes"],
823 "action": "store_true",
824 "dest": "cleanupCrashes",
826 "help": "Delete pending crash reports before running tests.",
831 ["--websocket-process-bridge-port"],
834 "dest": "websocket_process_bridge_port",
835 "help": "Port for websocket/process bridge. Default 8191.",
839 ["--failure-pattern-file"],
842 "dest": "failure_pattern_file",
843 "help": "File describes all failure patterns of the tests.",
848 ["--sandbox-read-whitelist"],
851 "dest": "sandboxReadWhitelist",
853 "help": "Path to add to the sandbox whitelist.",
860 "action": "store_true",
862 "help": "Run tests in verification mode: Run many times in different "
863 "ways, to see if there are intermittent failures.",
867 ["--verify-fission"],
869 "action": "store_true",
871 "help": "Run tests once without Fission, once with Fission",
875 ["--verify-max-time"],
879 "help": "Maximum time, in seconds, to run in --verify mode.",
885 "action": "store_true",
888 "help": "Run the Firefox Profiler and get a performance profile of the "
889 "mochitest. This is useful to find performance issues, and also "
890 "to see what exactly the test is doing. To get profiler options run: "
891 "`MOZ_PROFILER_HELP=1 ./mach run`",
895 ["--profiler-save-only"],
897 "action": "store_true",
898 "dest": "profilerSaveOnly",
900 "help": "Run the Firefox Profiler and save it to the path specified by the "
901 "MOZ_UPLOAD_DIR environment variable.",
908 "dest": "runFailures",
910 "help": "Run fail-if/skip-if tests that match a keyword given.",
914 ["--timeout-as-pass"],
916 "action": "store_true",
917 "dest": "timeoutAsPass",
919 "help": "treat harness level timeouts as passing (used for quarantine jobs).",
925 "action": "store_true",
926 "dest": "crashAsPass",
928 "help": "treat harness level crashes as passing (used for quarantine jobs).",
932 ["--compare-preferences"],
934 "action": "store_true",
935 "dest": "comparePrefs",
937 "help": "Compare preferences at the end of each test and report changed ones as failures.",
943 # Bug 1065098 - The gmplugin process fails to produce a leak
944 # log for some reason.
945 "ignoreMissingLeaks": ["gmplugin"],
946 "extensionsToExclude": ["specialpowers"],
947 # Set server information on the args object
948 "webServer": "127.0.0.1",
949 "httpPort": DEFAULT_PORTS
["http"],
950 "sslPort": DEFAULT_PORTS
["https"],
951 "webSocketPort": "9988",
952 # The default websocket port is incorrect in mozprofile; it is
953 # set to the SSL proxy setting. See:
954 # see https://bugzilla.mozilla.org/show_bug.cgi?id=916517
955 # args.webSocketPort = DEFAULT_PORTS['ws']
958 def validate(self
, parser
, options
, context
):
959 """Validate generic options."""
961 # and android doesn't use 'app' the same way, so skip validation
962 if parser
.app
!= "android":
963 if options
.app
is None:
965 from mozbuild
.base
import BinaryNotFoundException
968 options
.app
= build_obj
.get_binary_path()
969 except BinaryNotFoundException
as e
:
970 print("{}\n\n{}\n".format(e
, e
.help()))
974 "could not find the application path, --appname must be specified"
976 elif options
.app
== "dist" and build_obj
:
977 options
.app
= build_obj
.get_binary_path(where
="staged-package")
979 options
.app
= self
.get_full_path(options
.app
, parser
.oldcwd
)
980 if not os
.path
.exists(options
.app
):
982 "Error: Path {} doesn't exist. Are you executing "
983 "$objdir/_tests/testing/mochitest/runtests.py?".format(options
.app
)
986 if options
.flavor
is None:
987 options
.flavor
= "plain"
989 for value
in ALL_FLAVORS
.values():
990 if options
.flavor
in value
["aliases"]:
991 options
.flavor
= value
["suite"]
994 if options
.gmp_path
is None and options
.app
and build_obj
:
995 # Need to fix the location of gmp_fake which might not be shipped in the binary
998 ("gmp-clearkey", "0.1"),
999 ("gmp-fakeopenh264", "1.0"),
1001 options
.gmp_path
= os
.pathsep
.join(
1002 os
.path
.join(build_obj
.bindir
, *p
) for p
in gmp_modules
1005 if options
.totalChunks
is not None and options
.thisChunk
is None:
1006 parser
.error("thisChunk must be specified when totalChunks is specified")
1008 if options
.extra_mozinfo_json
:
1009 if not os
.path
.isfile(options
.extra_mozinfo_json
):
1011 "Error: couldn't find mozinfo.json at '%s'."
1012 % options
.extra_mozinfo_json
1015 options
.extra_mozinfo_json
= json
.load(open(options
.extra_mozinfo_json
))
1017 if options
.totalChunks
:
1018 if not 1 <= options
.thisChunk
<= options
.totalChunks
:
1019 parser
.error("thisChunk must be between 1 and totalChunks")
1021 if options
.chunkByDir
and options
.chunkByRuntime
:
1022 parser
.error("can only use one of --chunk-by-dir or --chunk-by-runtime")
1024 if options
.xrePath
is None:
1025 # default xrePath to the app path if not provided
1026 # but only if an app path was explicitly provided
1027 if options
.app
!= parser
.get_default("app"):
1028 options
.xrePath
= os
.path
.dirname(options
.app
)
1030 options
.xrePath
= os
.path
.join(
1031 os
.path
.dirname(options
.xrePath
), "Resources"
1033 elif build_obj
is not None:
1034 # otherwise default to dist/bin
1035 options
.xrePath
= build_obj
.bindir
1038 "could not find xre directory, --xre-path must be specified"
1041 # allow relative paths
1043 options
.xrePath
= self
.get_full_path(options
.xrePath
, parser
.oldcwd
)
1045 if options
.profilePath
:
1046 options
.profilePath
= self
.get_full_path(options
.profilePath
, parser
.oldcwd
)
1048 if options
.utilityPath
:
1049 options
.utilityPath
= self
.get_full_path(options
.utilityPath
, parser
.oldcwd
)
1051 if options
.certPath
:
1052 options
.certPath
= self
.get_full_path(options
.certPath
, parser
.oldcwd
)
1054 options
.certPath
= os
.path
.join(
1055 build_obj
.topsrcdir
, "build", "pgo", "certs"
1058 if options
.symbolsPath
and len(urlparse(options
.symbolsPath
).scheme
) < 2:
1059 options
.symbolsPath
= self
.get_full_path(options
.symbolsPath
, parser
.oldcwd
)
1060 elif not options
.symbolsPath
and build_obj
:
1061 options
.symbolsPath
= os
.path
.join(
1062 build_obj
.distdir
, "crashreporter-symbols"
1065 if options
.debugOnFailure
and not options
.jsdebugger
:
1066 parser
.error("--debug-on-failure requires --jsdebugger.")
1068 if options
.jsdebuggerPath
and not options
.jsdebugger
:
1069 parser
.error("--jsdebugger-path requires --jsdebugger.")
1071 if options
.debuggerArgs
and not options
.debugger
:
1072 parser
.error("--debugger-args requires --debugger.")
1074 if options
.valgrind
or options
.debugger
:
1075 # valgrind and some debuggers may cause Gecko to start slowly. Make sure
1076 # marionette waits long enough to connect.
1077 options
.marionette_startup_timeout
= 900
1078 options
.marionette_socket_timeout
= 540
1080 if options
.store_chrome_manifest
:
1081 options
.store_chrome_manifest
= os
.path
.abspath(
1082 options
.store_chrome_manifest
1084 if not os
.path
.isdir(os
.path
.dirname(options
.store_chrome_manifest
)):
1086 "directory for %s does not exist as a destination to copy a "
1087 "chrome manifest." % options
.store_chrome_manifest
1090 if options
.jscov_dir_prefix
:
1091 options
.jscov_dir_prefix
= os
.path
.abspath(options
.jscov_dir_prefix
)
1092 if not os
.path
.isdir(options
.jscov_dir_prefix
):
1094 "directory %s does not exist as a destination for coverage "
1095 "data." % options
.jscov_dir_prefix
1098 if options
.testingModulesDir
is None:
1099 # Try to guess the testing modules directory.
1100 possible
= [os
.path
.join(here
, os
.path
.pardir
, "modules")]
1103 0, os
.path
.join(build_obj
.topobjdir
, "_tests", "modules")
1107 if os
.path
.isdir(p
):
1108 options
.testingModulesDir
= p
1111 # Paths to specialpowers and mochijar from the tests archive.
1112 options
.stagedAddons
= [
1113 os
.path
.join(here
, "extensions", "specialpowers"),
1114 os
.path
.join(here
, "mochijar"),
1117 objdir_xpi_stage
= os
.path
.join(build_obj
.distdir
, "xpi-stage")
1118 if os
.path
.isdir(objdir_xpi_stage
):
1119 options
.stagedAddons
= [
1120 os
.path
.join(objdir_xpi_stage
, "specialpowers"),
1121 os
.path
.join(objdir_xpi_stage
, "mochijar"),
1123 plugins_dir
= os
.path
.join(build_obj
.distdir
, "plugins")
1125 os
.path
.isdir(plugins_dir
)
1126 and plugins_dir
not in options
.extraProfileFiles
1128 options
.extraProfileFiles
.append(plugins_dir
)
1130 # Even if buildbot is updated, we still want this, as the path we pass in
1131 # to the app must be absolute and have proper slashes.
1132 if options
.testingModulesDir
is not None:
1133 options
.testingModulesDir
= os
.path
.normpath(options
.testingModulesDir
)
1135 if not os
.path
.isabs(options
.testingModulesDir
):
1136 options
.testingModulesDir
= os
.path
.abspath(options
.testingModulesDir
)
1138 if not os
.path
.isdir(options
.testingModulesDir
):
1140 "--testing-modules-dir not a directory: %s"
1141 % options
.testingModulesDir
1144 options
.testingModulesDir
= options
.testingModulesDir
.replace("\\", "/")
1145 if options
.testingModulesDir
[-1] != "/":
1146 options
.testingModulesDir
+= "/"
1148 if options
.runUntilFailure
:
1149 if not options
.repeat
:
1152 if options
.dumpOutputDirectory
is None:
1153 options
.dumpOutputDirectory
= tempfile
.gettempdir()
1155 if options
.dumpAboutMemoryAfterTest
or options
.dumpDMDAfterTest
:
1156 if not os
.path
.isdir(options
.dumpOutputDirectory
):
1158 "--dump-output-directory not a directory: %s"
1159 % options
.dumpOutputDirectory
1162 if options
.useTestMediaDevices
:
1163 if not mozinfo
.isLinux
:
1165 "--use-test-media-devices is only supported on Linux currently"
1168 gst01
= spawn
.find_executable("gst-launch-0.1")
1169 gst010
= spawn
.find_executable("gst-launch-0.10")
1170 gst10
= spawn
.find_executable("gst-launch-1.0")
1171 pactl
= spawn
.find_executable("pactl")
1173 if not (gst01
or gst10
or gst010
):
1175 "Missing gst-launch-{0.1,0.10,1.0}, required for "
1176 "--use-test-media-devices"
1181 "Missing binary pactl required for " "--use-test-media-devices"
1184 # The a11y and chrome flavors can't run with e10s.
1185 if options
.flavor
in ("a11y", "chrome") and options
.e10s
:
1187 "mochitest-{} does not support e10s, try again with "
1188 "--disable-e10s.".format(options
.flavor
)
1191 # If e10s explicitly disabled and no fission option specified, disable fission
1192 if (not options
.e10s
) and (not options
.disable_fission
):
1193 options
.disable_fission
= True
1195 options
.leakThresholds
= {
1196 "default": options
.defaultLeakThreshold
,
1197 "tab": options
.defaultLeakThreshold
,
1198 "forkserver": options
.defaultLeakThreshold
,
1199 # GMP rarely gets a log, but when it does, it leaks a little.
1203 # See the dependencies of bug 1401764.
1205 options
.leakThresholds
["tab"] = 1000
1207 # XXX We can't normalize test_paths in the non build_obj case here,
1208 # because testRoot depends on the flavor, which is determined by the
1209 # mach command and therefore not finalized yet. Conversely, test paths
1210 # need to be normalized here for the mach case.
1211 if options
.test_paths
and build_obj
:
1212 # Normalize test paths so they are relative to test root
1213 options
.test_paths
= [
1214 build_obj
._wrap
_path
_argument
(p
).relpath() for p
in options
.test_paths
1220 class AndroidArguments(ArgumentContainer
):
1221 """Android specific arguments."""
1227 "action": "store_true",
1229 "help": "Skip the installation of the APK.",
1235 "action": "store_true",
1237 "help": "Install the test_runner app using AAB.",
1243 "dest": "deviceSerial",
1244 "help": "adb serial number of remote device. This is required "
1245 "when more than one device is connected to the host. "
1246 "Use 'adb devices' to see connected devices.",
1255 "help": "Path to adb binary.",
1260 ["--remote-webserver"],
1262 "dest": "remoteWebServer",
1264 "help": "IP address of the remote web server.",
1271 "default": DEFAULT_PORTS
["http"],
1272 "help": "http port of the remote web server.",
1280 "default": DEFAULT_PORTS
["https"],
1281 "help": "ssl port of the remote web server.",
1286 ["--remoteTestRoot"],
1288 "dest": "remoteTestRoot",
1290 "help": "Remote directory to use as test root "
1291 "(eg. /data/local/tmp/test_root).",
1296 ["--enable-coverage"],
1298 "action": "store_true",
1300 "help": "Enable collecting code coverage information when running "
1305 ["--coverage-output-dir"],
1309 "help": "When using --enable-java-coverage, save the code coverage report "
1310 "files to this directory.",
1316 # we don't want to exclude specialpowers on android just yet
1317 "extensionsToExclude": [],
1318 # mochijar doesn't get installed via marionette on android
1319 "extensionsToInstall": [os
.path
.join(here
, "mochijar")],
1320 "logFile": "mochitest.log",
1321 "utilityPath": None,
1324 def validate(self
, parser
, options
, context
):
1325 """Validate android options."""
1328 options
.log_mach
= "-"
1330 objdir_xpi_stage
= os
.path
.join(build_obj
.distdir
, "xpi-stage")
1331 if os
.path
.isdir(objdir_xpi_stage
):
1332 options
.extensionsToInstall
= [
1333 os
.path
.join(objdir_xpi_stage
, "mochijar"),
1334 os
.path
.join(objdir_xpi_stage
, "specialpowers"),
1337 if options
.remoteWebServer
is None:
1338 options
.remoteWebServer
= moznetwork
.get_ip()
1340 options
.webServer
= options
.remoteWebServer
1342 if options
.app
is None:
1343 options
.app
= "org.mozilla.geckoview.test_runner"
1345 if build_obj
and "MOZ_HOST_BIN" in os
.environ
:
1346 options
.xrePath
= os
.environ
["MOZ_HOST_BIN"]
1348 # Only reset the xrePath if it wasn't provided
1349 if options
.xrePath
is None:
1350 options
.xrePath
= options
.utilityPath
1353 options
.topsrcdir
= build_obj
.topsrcdir
1355 if options
.pidFile
!= "":
1356 f
= open(options
.pidFile
, "w")
1357 f
.write("%s" % os
.getpid())
1360 if options
.coverage_output_dir
and not options
.enable_coverage
:
1361 parser
.error("--coverage-output-dir must be used with --enable-coverage")
1362 if options
.enable_coverage
:
1363 if not options
.autorun
:
1364 parser
.error("--enable-coverage cannot be used with --no-autorun")
1365 if not options
.coverage_output_dir
:
1367 "--coverage-output-dir must be specified when using --enable-coverage"
1369 parent_dir
= os
.path
.dirname(options
.coverage_output_dir
)
1370 if not os
.path
.isdir(options
.coverage_output_dir
):
1372 "The directory for the coverage output does not exist: %s"
1376 # allow us to keep original application around for cleanup while
1378 options
.remoteappname
= options
.app
1383 "generic": [MochitestArguments
],
1384 "android": [MochitestArguments
, AndroidArguments
],
1388 class MochitestArgumentParser(ArgumentParser
):
1389 """%(prog)s [options] [test paths]"""
1394 def __init__(self
, app
=None, **kwargs
):
1395 ArgumentParser
.__init
__(
1396 self
, usage
=self
.__doc
__, conflict_handler
="resolve", **kwargs
1399 self
.oldcwd
= os
.getcwd()
1401 if not self
.app
and build_obj
:
1402 if conditions
.is_android(build_obj
):
1403 self
.app
= "android"
1405 # platform can't be determined and app wasn't specified explicitly,
1406 # so just use generic arguments and hope for the best
1407 self
.app
= "generic"
1409 if self
.app
not in container_map
:
1411 "Unrecognized app '{}'! Must be one of: {}".format(
1412 self
.app
, ", ".join(container_map
.keys())
1417 for container
in self
.containers
:
1418 defaults
.update(container
.defaults
)
1419 group
= self
.add_argument_group(
1420 container
.__class
__.__name
__, container
.__doc
__
1423 for cli
, kwargs
in container
.args
:
1424 # Allocate new lists so references to original don't get mutated.
1425 # allowing multiple uses within a single process.
1426 if "default" in kwargs
and isinstance(kwargs
["default"], list):
1427 kwargs
["default"] = []
1429 if "suppress" in kwargs
:
1430 if kwargs
["suppress"]:
1431 kwargs
["help"] = SUPPRESS
1432 del kwargs
["suppress"]
1434 group
.add_argument(*cli
, **kwargs
)
1436 self
.set_defaults(**defaults
)
1437 mozlog
.commandline
.add_logging_group(self
)
1440 def containers(self
):
1441 if self
._containers
:
1442 return self
._containers
1444 containers
= container_map
[self
.app
]
1445 self
._containers
= [c() for c
in containers
]
1446 return self
._containers
1448 def validate(self
, args
):
1449 for container
in self
.containers
:
1450 args
= container
.validate(self
, args
, self
.context
)