michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: import mozinfo michael@0: import moznetwork michael@0: import optparse michael@0: import os michael@0: import tempfile michael@0: michael@0: from automationutils import addCommonOptions, isURL michael@0: from mozprofile import DEFAULT_PORTS michael@0: michael@0: here = os.path.abspath(os.path.dirname(__file__)) michael@0: michael@0: try: michael@0: from mozbuild.base import MozbuildObject michael@0: build_obj = MozbuildObject.from_environment(cwd=here) michael@0: except ImportError: michael@0: build_obj = None michael@0: michael@0: __all__ = ["MochitestOptions", "B2GOptions"] michael@0: michael@0: VMWARE_RECORDING_HELPER_BASENAME = "vmwarerecordinghelper" michael@0: michael@0: class MochitestOptions(optparse.OptionParser): michael@0: """Usage instructions for runtests.py. michael@0: All arguments are optional. michael@0: If --chrome is specified, chrome tests will be run instead of web content tests. michael@0: If --browser-chrome is specified, browser-chrome tests will be run instead of web content tests. michael@0: See for details on the logging levels. michael@0: """ michael@0: michael@0: LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR", "FATAL") michael@0: LEVEL_STRING = ", ".join(LOG_LEVELS) michael@0: mochitest_options = [ michael@0: [["--close-when-done"], michael@0: { "action": "store_true", michael@0: "dest": "closeWhenDone", michael@0: "default": False, michael@0: "help": "close the application when tests are done running", michael@0: }], michael@0: [["--appname"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "app", michael@0: "default": None, michael@0: "help": "absolute path to application, overriding default", michael@0: }], michael@0: [["--utility-path"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "utilityPath", michael@0: "default": build_obj.bindir if build_obj is not None else None, michael@0: "help": "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)", michael@0: }], michael@0: [["--certificate-path"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "certPath", michael@0: "help": "absolute path to directory containing certificate store to use testing profile", michael@0: "default": os.path.join(build_obj.topsrcdir, 'build', 'pgo', 'certs') if build_obj is not None else None, michael@0: }], michael@0: [["--log-file"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "logFile", michael@0: "metavar": "FILE", michael@0: "help": "file to which logging occurs", michael@0: "default": "", michael@0: }], michael@0: [["--hide-subtests"], michael@0: { "action": "store_true", michael@0: "dest": "hide_subtests", michael@0: "help": "only show subtest log output if there was a failure", michael@0: "default": False, michael@0: }], michael@0: [["--autorun"], michael@0: { "action": "store_true", michael@0: "dest": "autorun", michael@0: "help": "start running tests when the application starts", michael@0: "default": False, michael@0: }], michael@0: [["--timeout"], michael@0: { "type": "int", michael@0: "dest": "timeout", michael@0: "help": "per-test timeout in seconds", michael@0: "default": None, michael@0: }], michael@0: [["--total-chunks"], michael@0: { "type": "int", michael@0: "dest": "totalChunks", michael@0: "help": "how many chunks to split the tests up into", michael@0: "default": None, michael@0: }], michael@0: [["--this-chunk"], michael@0: { "type": "int", michael@0: "dest": "thisChunk", michael@0: "help": "which chunk to run", michael@0: "default": None, michael@0: }], michael@0: [["--chunk-by-dir"], michael@0: { "type": "int", michael@0: "dest": "chunkByDir", michael@0: "help": "group tests together in the same chunk that are in the same top chunkByDir directories", michael@0: "default": 0, michael@0: }], michael@0: [["--shuffle"], michael@0: { "dest": "shuffle", michael@0: "action": "store_true", michael@0: "help": "randomize test order", michael@0: "default": False, michael@0: }], michael@0: [["--console-level"], michael@0: { "action": "store", michael@0: "type": "choice", michael@0: "dest": "consoleLevel", michael@0: "choices": LOG_LEVELS, michael@0: "metavar": "LEVEL", michael@0: "help": "one of %s to determine the level of console " michael@0: "logging" % LEVEL_STRING, michael@0: "default": None, michael@0: }], michael@0: [["--file-level"], michael@0: { "action": "store", michael@0: "type": "choice", michael@0: "dest": "fileLevel", michael@0: "choices": LOG_LEVELS, michael@0: "metavar": "LEVEL", michael@0: "help": "one of %s to determine the level of file " michael@0: "logging if a file has been specified, defaulting " michael@0: "to INFO" % LEVEL_STRING, michael@0: "default": "INFO", michael@0: }], michael@0: [["--chrome"], michael@0: { "action": "store_true", michael@0: "dest": "chrome", michael@0: "help": "run chrome Mochitests", michael@0: "default": False, michael@0: }], michael@0: [["--ipcplugins"], michael@0: { "action": "store_true", michael@0: "dest": "ipcplugins", michael@0: "help": "run ipcplugins Mochitests", michael@0: "default": False, michael@0: }], michael@0: [["--test-path"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "testPath", michael@0: "help": "start in the given directory's tests", michael@0: "default": "", michael@0: }], michael@0: [["--start-at"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "startAt", michael@0: "help": "skip over tests until reaching the given test", michael@0: "default": "", michael@0: }], michael@0: [["--end-at"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "endAt", michael@0: "help": "don't run any tests after the given one", michael@0: "default": "", michael@0: }], michael@0: [["--browser-chrome"], michael@0: { "action": "store_true", michael@0: "dest": "browserChrome", michael@0: "help": "run browser chrome Mochitests", michael@0: "default": False, michael@0: }], michael@0: [["--subsuite"], michael@0: { "action": "store", michael@0: "dest": "subsuite", michael@0: "help": "subsuite of tests to run", michael@0: "default": "", michael@0: }], michael@0: [["--webapprt-content"], michael@0: { "action": "store_true", michael@0: "dest": "webapprtContent", michael@0: "help": "run WebappRT content tests", michael@0: "default": False, michael@0: }], michael@0: [["--webapprt-chrome"], michael@0: { "action": "store_true", michael@0: "dest": "webapprtChrome", michael@0: "help": "run WebappRT chrome tests", michael@0: "default": False, michael@0: }], michael@0: [["--a11y"], michael@0: { "action": "store_true", michael@0: "dest": "a11y", michael@0: "help": "run accessibility Mochitests", michael@0: "default": False, michael@0: }], michael@0: [["--setenv"], michael@0: { "action": "append", michael@0: "type": "string", michael@0: "dest": "environment", michael@0: "metavar": "NAME=VALUE", michael@0: "help": "sets the given variable in the application's " michael@0: "environment", michael@0: "default": [], michael@0: }], michael@0: [["--exclude-extension"], michael@0: { "action": "append", michael@0: "type": "string", michael@0: "dest": "extensionsToExclude", michael@0: "help": "excludes the given extension from being installed " michael@0: "in the test profile", michael@0: "default": [], michael@0: }], michael@0: [["--browser-arg"], michael@0: { "action": "append", michael@0: "type": "string", michael@0: "dest": "browserArgs", michael@0: "metavar": "ARG", michael@0: "help": "provides an argument to the test application", michael@0: "default": [], michael@0: }], michael@0: [["--leak-threshold"], michael@0: { "action": "store", michael@0: "type": "int", michael@0: "dest": "leakThreshold", michael@0: "metavar": "THRESHOLD", michael@0: "help": "fail if the number of bytes leaked through " michael@0: "refcounted objects (or bytes in classes with " michael@0: "MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) is greater " michael@0: "than the given number", michael@0: "default": 0, michael@0: }], michael@0: [["--fatal-assertions"], michael@0: { "action": "store_true", michael@0: "dest": "fatalAssertions", michael@0: "help": "abort testing whenever an assertion is hit " michael@0: "(requires a debug build to be effective)", michael@0: "default": False, michael@0: }], michael@0: [["--extra-profile-file"], michael@0: { "action": "append", michael@0: "dest": "extraProfileFiles", michael@0: "help": "copy specified files/dirs to testing profile", michael@0: "default": [], michael@0: }], michael@0: [["--install-extension"], michael@0: { "action": "append", michael@0: "dest": "extensionsToInstall", michael@0: "help": "install the specified extension in the testing profile." michael@0: "The extension file's name should be .xpi where is" michael@0: "the extension's id as indicated in its install.rdf." michael@0: "An optional path can be specified too.", michael@0: "default": [], michael@0: }], michael@0: [["--profile-path"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "profilePath", michael@0: "help": "Directory where the profile will be stored." michael@0: "This directory will be deleted after the tests are finished", michael@0: "default": tempfile.mkdtemp(), michael@0: }], michael@0: [["--testing-modules-dir"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "testingModulesDir", michael@0: "help": "Directory where testing-only JS modules are located.", michael@0: "default": None, michael@0: }], michael@0: [["--use-vmware-recording"], michael@0: { "action": "store_true", michael@0: "dest": "vmwareRecording", michael@0: "help": "enables recording while the application is running " michael@0: "inside a VMware Workstation 7.0 or later VM", michael@0: "default": False, michael@0: }], michael@0: [["--repeat"], michael@0: { "action": "store", michael@0: "type": "int", michael@0: "dest": "repeat", michael@0: "metavar": "REPEAT", michael@0: "help": "repeats the test or set of tests the given number of times, ie: repeat: 1 will run the test twice.", michael@0: "default": 0, michael@0: }], michael@0: [["--run-until-failure"], michael@0: { "action": "store_true", michael@0: "dest": "runUntilFailure", michael@0: "help": "Run tests repeatedly and stops on the first time a test fails. " michael@0: "Default cap is 30 runs, which can be overwritten with the --repeat parameter.", michael@0: "default": False, michael@0: }], michael@0: [["--run-only-tests"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "runOnlyTests", michael@0: "help": "JSON list of tests that we only want to run. [DEPRECATED- please use --test-manifest]", michael@0: "default": None, michael@0: }], michael@0: [["--test-manifest"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "testManifest", michael@0: "help": "JSON list of tests to specify 'runtests'. Old format for mobile specific tests", michael@0: "default": None, michael@0: }], michael@0: [["--manifest"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "manifestFile", michael@0: "help": ".ini format of tests to run.", michael@0: "default": None, michael@0: }], michael@0: [["--failure-file"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "failureFile", michael@0: "help": "Filename of the output file where we can store a .json list of failures to be run in the future with --run-only-tests.", michael@0: "default": None, michael@0: }], michael@0: [["--run-slower"], michael@0: { "action": "store_true", michael@0: "dest": "runSlower", michael@0: "help": "Delay execution between test files.", michael@0: "default": False, michael@0: }], michael@0: [["--metro-immersive"], michael@0: { "action": "store_true", michael@0: "dest": "immersiveMode", michael@0: "help": "launches tests in immersive browser", michael@0: "default": False, michael@0: }], michael@0: [["--httpd-path"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "httpdPath", michael@0: "default": None, michael@0: "help": "path to the httpd.js file", michael@0: }], michael@0: [["--setpref"], michael@0: { "action": "append", michael@0: "type": "string", michael@0: "default": [], michael@0: "dest": "extraPrefs", michael@0: "metavar": "PREF=VALUE", michael@0: "help": "defines an extra user preference", michael@0: }], michael@0: [["--jsdebugger"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "jsdebugger", michael@0: "help": "open the browser debugger", michael@0: }], michael@0: [["--debug-on-failure"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "debugOnFailure", michael@0: "help": "breaks execution and enters the JS debugger on a test failure. Should be used together with --jsdebugger." michael@0: }], michael@0: [["--e10s"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "e10s", michael@0: "help": "Run tests with electrolysis preferences and test filtering enabled.", michael@0: }], michael@0: [["--dmd-path"], michael@0: { "action": "store", michael@0: "default": None, michael@0: "dest": "dmdPath", michael@0: "help": "Specifies the path to the directory containing the shared library for DMD.", michael@0: }], michael@0: [["--dump-output-directory"], michael@0: { "action": "store", michael@0: "default": None, michael@0: "dest": "dumpOutputDirectory", michael@0: "help": "Specifies the directory in which to place dumped memory reports.", michael@0: }], michael@0: [["--dump-about-memory-after-test"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "dumpAboutMemoryAfterTest", michael@0: "help": "Produce an about:memory dump after each test in the directory specified " michael@0: "by --dump-output-directory." michael@0: }], michael@0: [["--dump-dmd-after-test"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "dumpDMDAfterTest", michael@0: "help": "Produce a DMD dump after each test in the directory specified " michael@0: "by --dump-output-directory." michael@0: }], michael@0: [["--slowscript"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "slowscript", michael@0: "help": "Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; " michael@0: "when not set, recoverable but misleading SIGSEGV instances " michael@0: "may occur in Ion/Odin JIT code." michael@0: }], michael@0: [["--screenshot-on-fail"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "screenshotOnFail", michael@0: "help": "Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots." michael@0: }], michael@0: [["--quiet"], michael@0: { "action": "store_true", michael@0: "default": False, michael@0: "dest": "quiet", michael@0: "help": "Do not print test log lines unless a failure occurs." michael@0: }], michael@0: [["--pidfile"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "pidFile", michael@0: "help": "name of the pidfile to generate", michael@0: "default": "", michael@0: }], michael@0: ] michael@0: michael@0: def __init__(self, **kwargs): michael@0: michael@0: optparse.OptionParser.__init__(self, **kwargs) michael@0: for option, value in self.mochitest_options: michael@0: self.add_option(*option, **value) michael@0: addCommonOptions(self) michael@0: self.set_usage(self.__doc__) michael@0: michael@0: def verifyOptions(self, options, mochitest): michael@0: """ verify correct options and cleanup paths """ michael@0: michael@0: mozinfo.update({"e10s": options.e10s}) # for test manifest parsing. michael@0: michael@0: if options.app is None: michael@0: if build_obj is not None: michael@0: options.app = build_obj.get_binary_path() michael@0: else: michael@0: self.error("could not find the application path, --appname must be specified") michael@0: michael@0: if options.totalChunks is not None and options.thisChunk is None: michael@0: self.error("thisChunk must be specified when totalChunks is specified") michael@0: michael@0: if options.totalChunks: michael@0: if not 1 <= options.thisChunk <= options.totalChunks: michael@0: self.error("thisChunk must be between 1 and totalChunks") michael@0: michael@0: if options.xrePath is None: michael@0: # default xrePath to the app path if not provided michael@0: # but only if an app path was explicitly provided michael@0: if options.app != self.defaults['app']: michael@0: options.xrePath = os.path.dirname(options.app) michael@0: elif build_obj is not None: michael@0: # otherwise default to dist/bin michael@0: options.xrePath = build_obj.bindir michael@0: else: michael@0: self.error("could not find xre directory, --xre-path must be specified") michael@0: michael@0: # allow relative paths michael@0: options.xrePath = mochitest.getFullPath(options.xrePath) michael@0: options.profilePath = mochitest.getFullPath(options.profilePath) michael@0: options.app = mochitest.getFullPath(options.app) michael@0: if options.dmdPath is not None: michael@0: options.dmdPath = mochitest.getFullPath(options.dmdPath) michael@0: michael@0: if not os.path.exists(options.app): michael@0: msg = """\ michael@0: Error: Path %(app)s doesn't exist. michael@0: Are you executing $objdir/_tests/testing/mochitest/runtests.py?""" michael@0: self.error(msg % {"app": options.app}) michael@0: return None michael@0: michael@0: if options.utilityPath: michael@0: options.utilityPath = mochitest.getFullPath(options.utilityPath) michael@0: michael@0: if options.certPath: michael@0: options.certPath = mochitest.getFullPath(options.certPath) michael@0: michael@0: if options.symbolsPath and not isURL(options.symbolsPath): michael@0: options.symbolsPath = mochitest.getFullPath(options.symbolsPath) michael@0: michael@0: # Set server information on the options object michael@0: options.webServer = '127.0.0.1' michael@0: options.httpPort = DEFAULT_PORTS['http'] michael@0: options.sslPort = DEFAULT_PORTS['https'] michael@0: # options.webSocketPort = DEFAULT_PORTS['ws'] michael@0: options.webSocketPort = str(9988) # <- http://hg.mozilla.org/mozilla-central/file/b871dfb2186f/build/automation.py.in#l30 michael@0: # The default websocket port is incorrect in mozprofile; it is michael@0: # set to the SSL proxy setting. See: michael@0: # see https://bugzilla.mozilla.org/show_bug.cgi?id=916517 michael@0: michael@0: if options.vmwareRecording: michael@0: if not mozinfo.isWin: michael@0: self.error("use-vmware-recording is only supported on Windows.") michael@0: mochitest.vmwareHelperPath = os.path.join( michael@0: options.utilityPath, VMWARE_RECORDING_HELPER_BASENAME + ".dll") michael@0: if not os.path.exists(mochitest.vmwareHelperPath): michael@0: self.error("%s not found, cannot automate VMware recording." % michael@0: mochitest.vmwareHelperPath) michael@0: michael@0: if options.testManifest and options.runOnlyTests: michael@0: self.error("Please use --test-manifest only and not --run-only-tests") michael@0: michael@0: if options.runOnlyTests: michael@0: if not os.path.exists(os.path.abspath(os.path.join(here, options.runOnlyTests))): michael@0: self.error("unable to find --run-only-tests file '%s'" % options.runOnlyTests) michael@0: options.runOnly = True michael@0: options.testManifest = options.runOnlyTests michael@0: options.runOnlyTests = None michael@0: michael@0: if options.manifestFile and options.testManifest: michael@0: self.error("Unable to support both --manifest and --test-manifest/--run-only-tests at the same time") michael@0: michael@0: if options.webapprtContent and options.webapprtChrome: michael@0: self.error("Only one of --webapprt-content and --webapprt-chrome may be given.") michael@0: michael@0: if options.jsdebugger: michael@0: options.extraPrefs += [ michael@0: "devtools.debugger.remote-enabled=true", michael@0: "devtools.debugger.chrome-enabled=true", michael@0: "devtools.chrome.enabled=true", michael@0: "devtools.debugger.prompt-connection=false" michael@0: ] michael@0: options.autorun = False michael@0: michael@0: if options.debugOnFailure and not options.jsdebugger: michael@0: self.error("--debug-on-failure should be used together with --jsdebugger.") michael@0: michael@0: # Try to guess the testing modules directory. michael@0: # This somewhat grotesque hack allows the buildbot machines to find the michael@0: # modules directory without having to configure the buildbot hosts. This michael@0: # code should never be executed in local runs because the build system michael@0: # should always set the flag that populates this variable. If buildbot ever michael@0: # passes this argument, this code can be deleted. michael@0: if options.testingModulesDir is None: michael@0: possible = os.path.join(here, os.path.pardir, 'modules') michael@0: michael@0: if os.path.isdir(possible): michael@0: options.testingModulesDir = possible michael@0: michael@0: # Even if buildbot is updated, we still want this, as the path we pass in michael@0: # to the app must be absolute and have proper slashes. michael@0: if options.testingModulesDir is not None: michael@0: options.testingModulesDir = os.path.normpath(options.testingModulesDir) michael@0: michael@0: if not os.path.isabs(options.testingModulesDir): michael@0: options.testingModulesDir = os.path.abspath(options.testingModulesDir) michael@0: michael@0: if not os.path.isdir(options.testingModulesDir): michael@0: self.error('--testing-modules-dir not a directory: %s' % michael@0: options.testingModulesDir) michael@0: michael@0: options.testingModulesDir = options.testingModulesDir.replace('\\', '/') michael@0: if options.testingModulesDir[-1] != '/': michael@0: options.testingModulesDir += '/' michael@0: michael@0: if options.immersiveMode: michael@0: if not mozinfo.isWin: michael@0: self.error("immersive is only supported on Windows 8 and up.") michael@0: mochitest.immersiveHelperPath = os.path.join( michael@0: options.utilityPath, "metrotestharness.exe") michael@0: if not os.path.exists(mochitest.immersiveHelperPath): michael@0: self.error("%s not found, cannot launch immersive tests." % michael@0: mochitest.immersiveHelperPath) michael@0: michael@0: if options.runUntilFailure: michael@0: if not options.repeat: michael@0: options.repeat = 29 michael@0: michael@0: if options.dumpOutputDirectory is None: michael@0: options.dumpOutputDirectory = tempfile.gettempdir() michael@0: michael@0: if options.dumpAboutMemoryAfterTest or options.dumpDMDAfterTest: michael@0: if not os.path.isdir(options.dumpOutputDirectory): michael@0: self.error('--dump-output-directory not a directory: %s' % michael@0: options.dumpOutputDirectory) michael@0: michael@0: return options michael@0: michael@0: michael@0: class B2GOptions(MochitestOptions): michael@0: b2g_options = [ michael@0: [["--b2gpath"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "b2gPath", michael@0: "help": "path to B2G repo or qemu dir", michael@0: "default": None, michael@0: }], michael@0: [["--desktop"], michael@0: { "action": "store_true", michael@0: "dest": "desktop", michael@0: "help": "Run the tests on a B2G desktop build", michael@0: "default": False, michael@0: }], michael@0: [["--marionette"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "marionette", michael@0: "help": "host:port to use when connecting to Marionette", michael@0: "default": None, michael@0: }], michael@0: [["--emulator"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "emulator", michael@0: "help": "Architecture of emulator to use: x86 or arm", michael@0: "default": None, michael@0: }], michael@0: [["--wifi"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "wifi", michael@0: "help": "Devine wifi configuration for on device mochitest", michael@0: "default": False, michael@0: }], michael@0: [["--sdcard"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "sdcard", michael@0: "help": "Define size of sdcard: 1MB, 50MB...etc", michael@0: "default": "10MB", michael@0: }], michael@0: [["--no-window"], michael@0: { "action": "store_true", michael@0: "dest": "noWindow", michael@0: "help": "Pass --no-window to the emulator", michael@0: "default": False, michael@0: }], michael@0: [["--adbpath"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "adbPath", michael@0: "help": "path to adb", michael@0: "default": "adb", michael@0: }], michael@0: [["--deviceIP"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "deviceIP", michael@0: "help": "ip address of remote device to test", michael@0: "default": None, michael@0: }], michael@0: [["--devicePort"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "devicePort", michael@0: "help": "port of remote device to test", michael@0: "default": 20701, michael@0: }], michael@0: [["--remote-logfile"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "remoteLogFile", michael@0: "help": "Name of log file on the device relative to the device root. \ michael@0: PLEASE ONLY USE A FILENAME.", michael@0: "default" : None, michael@0: }], michael@0: [["--remote-webserver"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "remoteWebServer", michael@0: "help": "ip address where the remote web server is hosted at", michael@0: "default": None, michael@0: }], michael@0: [["--http-port"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "httpPort", michael@0: "help": "ip address where the remote web server is hosted at", michael@0: "default": None, michael@0: }], michael@0: [["--ssl-port"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "sslPort", michael@0: "help": "ip address where the remote web server is hosted at", michael@0: "default": None, michael@0: }], michael@0: [["--gecko-path"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "geckoPath", michael@0: "help": "the path to a gecko distribution that should \ michael@0: be installed on the emulator prior to test", michael@0: "default": None, michael@0: }], michael@0: [["--profile"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "profile", michael@0: "help": "for desktop testing, the path to the \ michael@0: gaia profile to use", michael@0: "default": None, michael@0: }], michael@0: [["--logcat-dir"], michael@0: { "action": "store", michael@0: "type": "string", michael@0: "dest": "logcat_dir", michael@0: "help": "directory to store logcat dump files", michael@0: "default": None, michael@0: }], michael@0: [['--busybox'], michael@0: { "action": 'store', michael@0: "type": 'string', michael@0: "dest": 'busybox', michael@0: "help": "Path to busybox binary to install on device", michael@0: "default": None, michael@0: }], michael@0: [['--profile-data-dir'], michael@0: { "action": 'store', michael@0: "type": 'string', michael@0: "dest": 'profile_data_dir', michael@0: "help": "Path to a directory containing preference and other \ michael@0: data to be installed into the profile", michael@0: "default": os.path.join(here, 'profile_data'), michael@0: }], michael@0: ] michael@0: michael@0: def __init__(self): michael@0: MochitestOptions.__init__(self) michael@0: michael@0: for option in self.b2g_options: michael@0: self.add_option(*option[0], **option[1]) michael@0: michael@0: defaults = {} michael@0: defaults["httpPort"] = DEFAULT_PORTS['http'] michael@0: defaults["sslPort"] = DEFAULT_PORTS['https'] michael@0: defaults["remoteTestRoot"] = "/data/local/tests" michael@0: defaults["logFile"] = "mochitest.log" michael@0: defaults["autorun"] = True michael@0: defaults["closeWhenDone"] = True michael@0: defaults["testPath"] = "" michael@0: defaults["extensionsToExclude"] = ["specialpowers"] michael@0: self.set_defaults(**defaults) michael@0: michael@0: def verifyRemoteOptions(self, options): michael@0: if options.remoteWebServer == None: michael@0: if os.name != "nt": michael@0: options.remoteWebServer = moznetwork.get_ip() michael@0: else: michael@0: self.error("You must specify a --remote-webserver=") michael@0: options.webServer = options.remoteWebServer michael@0: michael@0: if options.geckoPath and not options.emulator: michael@0: self.error("You must specify --emulator if you specify --gecko-path") michael@0: michael@0: if options.logcat_dir and not options.emulator: michael@0: self.error("You must specify --emulator if you specify --logcat-dir") michael@0: michael@0: if not os.path.isdir(options.xrePath): michael@0: self.error("--xre-path '%s' is not a directory" % options.xrePath) michael@0: xpcshell = os.path.join(options.xrePath, 'xpcshell') michael@0: if not os.access(xpcshell, os.F_OK): michael@0: self.error('xpcshell not found at %s' % xpcshell) michael@0: if self.elf_arm(xpcshell): michael@0: self.error('--xre-path points to an ARM version of xpcshell; it ' michael@0: 'should instead point to a version that can run on ' michael@0: 'your desktop') michael@0: michael@0: if options.pidFile != "": michael@0: f = open(options.pidFile, 'w') michael@0: f.write("%s" % os.getpid()) michael@0: f.close() michael@0: michael@0: return options michael@0: michael@0: def verifyOptions(self, options, mochitest): michael@0: # since we are reusing verifyOptions, it will exit if App is not found michael@0: temp = options.app michael@0: options.app = __file__ michael@0: tempPort = options.httpPort michael@0: tempSSL = options.sslPort michael@0: tempIP = options.webServer michael@0: options = MochitestOptions.verifyOptions(self, options, mochitest) michael@0: options.webServer = tempIP michael@0: options.app = temp michael@0: options.sslPort = tempSSL michael@0: options.httpPort = tempPort michael@0: michael@0: return options michael@0: michael@0: def elf_arm(self, filename): michael@0: data = open(filename, 'rb').read(20) michael@0: return data[:4] == "\x7fELF" and ord(data[18]) == 40 # EM_ARM