testing/mochitest/mochitest_options.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/testing/mochitest/mochitest_options.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,784 @@
     1.4 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 +
     1.8 +import mozinfo
     1.9 +import moznetwork
    1.10 +import optparse
    1.11 +import os
    1.12 +import tempfile
    1.13 +
    1.14 +from automationutils import addCommonOptions, isURL
    1.15 +from mozprofile import DEFAULT_PORTS
    1.16 +
    1.17 +here = os.path.abspath(os.path.dirname(__file__))
    1.18 +
    1.19 +try:
    1.20 +    from mozbuild.base import MozbuildObject
    1.21 +    build_obj = MozbuildObject.from_environment(cwd=here)
    1.22 +except ImportError:
    1.23 +    build_obj = None
    1.24 +
    1.25 +__all__ = ["MochitestOptions", "B2GOptions"]
    1.26 +
    1.27 +VMWARE_RECORDING_HELPER_BASENAME = "vmwarerecordinghelper"
    1.28 +
    1.29 +class MochitestOptions(optparse.OptionParser):
    1.30 +    """Usage instructions for runtests.py.
    1.31 +    All arguments are optional.
    1.32 +    If --chrome is specified, chrome tests will be run instead of web content tests.
    1.33 +    If --browser-chrome is specified, browser-chrome tests will be run instead of web content tests.
    1.34 +    See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logging levels.
    1.35 +    """
    1.36 +
    1.37 +    LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR", "FATAL")
    1.38 +    LEVEL_STRING = ", ".join(LOG_LEVELS)
    1.39 +    mochitest_options = [
    1.40 +        [["--close-when-done"],
    1.41 +        { "action": "store_true",
    1.42 +          "dest": "closeWhenDone",
    1.43 +          "default": False,
    1.44 +          "help": "close the application when tests are done running",
    1.45 +        }],
    1.46 +        [["--appname"],
    1.47 +        { "action": "store",
    1.48 +          "type": "string",
    1.49 +          "dest": "app",
    1.50 +          "default": None,
    1.51 +          "help": "absolute path to application, overriding default",
    1.52 +        }],
    1.53 +        [["--utility-path"],
    1.54 +        { "action": "store",
    1.55 +          "type": "string",
    1.56 +          "dest": "utilityPath",
    1.57 +          "default": build_obj.bindir if build_obj is not None else None,
    1.58 +          "help": "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)",
    1.59 +        }],
    1.60 +        [["--certificate-path"],
    1.61 +        { "action": "store",
    1.62 +          "type": "string",
    1.63 +          "dest": "certPath",
    1.64 +          "help": "absolute path to directory containing certificate store to use testing profile",
    1.65 +          "default": os.path.join(build_obj.topsrcdir, 'build', 'pgo', 'certs') if build_obj is not None else None,
    1.66 +        }],
    1.67 +        [["--log-file"],
    1.68 +        { "action": "store",
    1.69 +          "type": "string",
    1.70 +          "dest": "logFile",
    1.71 +          "metavar": "FILE",
    1.72 +          "help": "file to which logging occurs",
    1.73 +          "default": "",
    1.74 +        }],
    1.75 +        [["--hide-subtests"],
    1.76 +        { "action": "store_true",
    1.77 +          "dest": "hide_subtests",
    1.78 +          "help": "only show subtest log output if there was a failure",
    1.79 +          "default": False,
    1.80 +        }],
    1.81 +        [["--autorun"],
    1.82 +        { "action": "store_true",
    1.83 +          "dest": "autorun",
    1.84 +          "help": "start running tests when the application starts",
    1.85 +          "default": False,
    1.86 +        }],
    1.87 +        [["--timeout"],
    1.88 +        { "type": "int",
    1.89 +          "dest": "timeout",
    1.90 +          "help": "per-test timeout in seconds",
    1.91 +          "default": None,
    1.92 +        }],
    1.93 +        [["--total-chunks"],
    1.94 +        { "type": "int",
    1.95 +          "dest": "totalChunks",
    1.96 +          "help": "how many chunks to split the tests up into",
    1.97 +          "default": None,
    1.98 +        }],
    1.99 +        [["--this-chunk"],
   1.100 +        { "type": "int",
   1.101 +          "dest": "thisChunk",
   1.102 +          "help": "which chunk to run",
   1.103 +          "default": None,
   1.104 +        }],
   1.105 +        [["--chunk-by-dir"],
   1.106 +        { "type": "int",
   1.107 +          "dest": "chunkByDir",
   1.108 +          "help": "group tests together in the same chunk that are in the same top chunkByDir directories",
   1.109 +          "default": 0,
   1.110 +        }],
   1.111 +        [["--shuffle"],
   1.112 +        { "dest": "shuffle",
   1.113 +          "action": "store_true",
   1.114 +          "help": "randomize test order",
   1.115 +          "default": False,
   1.116 +        }],
   1.117 +        [["--console-level"],
   1.118 +        { "action": "store",
   1.119 +          "type": "choice",
   1.120 +          "dest": "consoleLevel",
   1.121 +          "choices": LOG_LEVELS,
   1.122 +          "metavar": "LEVEL",
   1.123 +          "help": "one of %s to determine the level of console "
   1.124 +                  "logging" % LEVEL_STRING,
   1.125 +          "default": None,
   1.126 +        }],
   1.127 +        [["--file-level"],
   1.128 +        { "action": "store",
   1.129 +          "type": "choice",
   1.130 +          "dest": "fileLevel",
   1.131 +          "choices": LOG_LEVELS,
   1.132 +          "metavar": "LEVEL",
   1.133 +          "help": "one of %s to determine the level of file "
   1.134 +                 "logging if a file has been specified, defaulting "
   1.135 +                 "to INFO" % LEVEL_STRING,
   1.136 +          "default": "INFO",
   1.137 +        }],
   1.138 +        [["--chrome"],
   1.139 +        { "action": "store_true",
   1.140 +          "dest": "chrome",
   1.141 +          "help": "run chrome Mochitests",
   1.142 +          "default": False,
   1.143 +        }],
   1.144 +        [["--ipcplugins"],
   1.145 +        { "action": "store_true",
   1.146 +          "dest": "ipcplugins",
   1.147 +          "help": "run ipcplugins Mochitests",
   1.148 +          "default": False,
   1.149 +        }],
   1.150 +        [["--test-path"],
   1.151 +        { "action": "store",
   1.152 +          "type": "string",
   1.153 +          "dest": "testPath",
   1.154 +          "help": "start in the given directory's tests",
   1.155 +          "default": "",
   1.156 +        }],
   1.157 +        [["--start-at"],
   1.158 +        { "action": "store",
   1.159 +          "type": "string",
   1.160 +          "dest": "startAt",
   1.161 +          "help": "skip over tests until reaching the given test",
   1.162 +          "default": "",
   1.163 +        }],
   1.164 +        [["--end-at"],
   1.165 +        { "action": "store",
   1.166 +          "type": "string",
   1.167 +          "dest": "endAt",
   1.168 +          "help": "don't run any tests after the given one",
   1.169 +          "default": "",
   1.170 +        }],
   1.171 +        [["--browser-chrome"],
   1.172 +        { "action": "store_true",
   1.173 +          "dest": "browserChrome",
   1.174 +          "help": "run browser chrome Mochitests",
   1.175 +          "default": False,
   1.176 +        }],
   1.177 +        [["--subsuite"],
   1.178 +        { "action": "store",
   1.179 +          "dest": "subsuite",
   1.180 +          "help": "subsuite of tests to run",
   1.181 +          "default": "",
   1.182 +        }],
   1.183 +        [["--webapprt-content"],
   1.184 +        { "action": "store_true",
   1.185 +          "dest": "webapprtContent",
   1.186 +          "help": "run WebappRT content tests",
   1.187 +          "default": False,
   1.188 +        }],
   1.189 +        [["--webapprt-chrome"],
   1.190 +        { "action": "store_true",
   1.191 +          "dest": "webapprtChrome",
   1.192 +          "help": "run WebappRT chrome tests",
   1.193 +          "default": False,
   1.194 +        }],
   1.195 +        [["--a11y"],
   1.196 +        { "action": "store_true",
   1.197 +          "dest": "a11y",
   1.198 +          "help": "run accessibility Mochitests",
   1.199 +          "default": False,
   1.200 +        }],
   1.201 +        [["--setenv"],
   1.202 +        { "action": "append",
   1.203 +          "type": "string",
   1.204 +          "dest": "environment",
   1.205 +          "metavar": "NAME=VALUE",
   1.206 +          "help": "sets the given variable in the application's "
   1.207 +                 "environment",
   1.208 +          "default": [],
   1.209 +        }],
   1.210 +        [["--exclude-extension"],
   1.211 +        { "action": "append",
   1.212 +          "type": "string",
   1.213 +          "dest": "extensionsToExclude",
   1.214 +          "help": "excludes the given extension from being installed "
   1.215 +                 "in the test profile",
   1.216 +          "default": [],
   1.217 +        }],
   1.218 +        [["--browser-arg"],
   1.219 +        { "action": "append",
   1.220 +          "type": "string",
   1.221 +          "dest": "browserArgs",
   1.222 +          "metavar": "ARG",
   1.223 +          "help": "provides an argument to the test application",
   1.224 +          "default": [],
   1.225 +        }],
   1.226 +        [["--leak-threshold"],
   1.227 +        { "action": "store",
   1.228 +          "type": "int",
   1.229 +          "dest": "leakThreshold",
   1.230 +          "metavar": "THRESHOLD",
   1.231 +          "help": "fail if the number of bytes leaked through "
   1.232 +                 "refcounted objects (or bytes in classes with "
   1.233 +                 "MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) is greater "
   1.234 +                 "than the given number",
   1.235 +          "default": 0,
   1.236 +        }],
   1.237 +        [["--fatal-assertions"],
   1.238 +        { "action": "store_true",
   1.239 +          "dest": "fatalAssertions",
   1.240 +          "help": "abort testing whenever an assertion is hit "
   1.241 +                 "(requires a debug build to be effective)",
   1.242 +          "default": False,
   1.243 +        }],
   1.244 +        [["--extra-profile-file"],
   1.245 +        { "action": "append",
   1.246 +          "dest": "extraProfileFiles",
   1.247 +          "help": "copy specified files/dirs to testing profile",
   1.248 +          "default": [],
   1.249 +        }],
   1.250 +        [["--install-extension"],
   1.251 +        { "action": "append",
   1.252 +          "dest": "extensionsToInstall",
   1.253 +          "help": "install the specified extension in the testing profile."
   1.254 +                 "The extension file's name should be <id>.xpi where <id> is"
   1.255 +                 "the extension's id as indicated in its install.rdf."
   1.256 +                 "An optional path can be specified too.",
   1.257 +          "default": [],
   1.258 +        }],
   1.259 +        [["--profile-path"],
   1.260 +        { "action": "store",
   1.261 +          "type": "string",
   1.262 +          "dest": "profilePath",
   1.263 +          "help": "Directory where the profile will be stored."
   1.264 +                 "This directory will be deleted after the tests are finished",
   1.265 +          "default": tempfile.mkdtemp(),
   1.266 +        }],
   1.267 +        [["--testing-modules-dir"],
   1.268 +        { "action": "store",
   1.269 +          "type": "string",
   1.270 +          "dest": "testingModulesDir",
   1.271 +          "help": "Directory where testing-only JS modules are located.",
   1.272 +          "default": None,
   1.273 +        }],
   1.274 +        [["--use-vmware-recording"],
   1.275 +        { "action": "store_true",
   1.276 +          "dest": "vmwareRecording",
   1.277 +          "help": "enables recording while the application is running "
   1.278 +                 "inside a VMware Workstation 7.0 or later VM",
   1.279 +          "default": False,
   1.280 +        }],
   1.281 +        [["--repeat"],
   1.282 +        { "action": "store",
   1.283 +          "type": "int",
   1.284 +          "dest": "repeat",
   1.285 +          "metavar": "REPEAT",
   1.286 +          "help": "repeats the test or set of tests the given number of times, ie: repeat: 1 will run the test twice.",
   1.287 +          "default": 0,
   1.288 +        }],
   1.289 +        [["--run-until-failure"],
   1.290 +        { "action": "store_true",
   1.291 +          "dest": "runUntilFailure",
   1.292 +          "help": "Run tests repeatedly and stops on the first time a test fails. "
   1.293 +                "Default cap is 30 runs, which can be overwritten with the --repeat parameter.",
   1.294 +          "default": False,
   1.295 +        }],
   1.296 +        [["--run-only-tests"],
   1.297 +        { "action": "store",
   1.298 +          "type": "string",
   1.299 +          "dest": "runOnlyTests",
   1.300 +          "help": "JSON list of tests that we only want to run. [DEPRECATED- please use --test-manifest]",
   1.301 +          "default": None,
   1.302 +        }],
   1.303 +        [["--test-manifest"],
   1.304 +        { "action": "store",
   1.305 +          "type": "string",
   1.306 +          "dest": "testManifest",
   1.307 +          "help": "JSON list of tests to specify 'runtests'. Old format for mobile specific tests",
   1.308 +          "default": None,
   1.309 +        }],
   1.310 +        [["--manifest"],
   1.311 +        { "action": "store",
   1.312 +          "type": "string",
   1.313 +          "dest": "manifestFile",
   1.314 +          "help": ".ini format of tests to run.",
   1.315 +          "default": None,
   1.316 +        }],
   1.317 +        [["--failure-file"],
   1.318 +        { "action": "store",
   1.319 +          "type": "string",
   1.320 +          "dest": "failureFile",
   1.321 +          "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.",
   1.322 +          "default": None,
   1.323 +        }],
   1.324 +        [["--run-slower"],
   1.325 +        { "action": "store_true",
   1.326 +          "dest": "runSlower",
   1.327 +          "help": "Delay execution between test files.",
   1.328 +          "default": False,
   1.329 +        }],
   1.330 +        [["--metro-immersive"],
   1.331 +        { "action": "store_true",
   1.332 +          "dest": "immersiveMode",
   1.333 +          "help": "launches tests in immersive browser",
   1.334 +          "default": False,
   1.335 +        }],
   1.336 +        [["--httpd-path"],
   1.337 +        { "action": "store",
   1.338 +          "type": "string",
   1.339 +          "dest": "httpdPath",
   1.340 +          "default": None,
   1.341 +          "help": "path to the httpd.js file",
   1.342 +        }],
   1.343 +        [["--setpref"],
   1.344 +        { "action": "append",
   1.345 +          "type": "string",
   1.346 +          "default": [],
   1.347 +          "dest": "extraPrefs",
   1.348 +          "metavar": "PREF=VALUE",
   1.349 +          "help": "defines an extra user preference",
   1.350 +        }],
   1.351 +        [["--jsdebugger"],
   1.352 +        { "action": "store_true",
   1.353 +          "default": False,
   1.354 +          "dest": "jsdebugger",
   1.355 +          "help": "open the browser debugger",
   1.356 +        }],
   1.357 +        [["--debug-on-failure"],
   1.358 +        { "action": "store_true",
   1.359 +          "default": False,
   1.360 +          "dest": "debugOnFailure",
   1.361 +          "help": "breaks execution and enters the JS debugger on a test failure. Should be used together with --jsdebugger."
   1.362 +        }],
   1.363 +        [["--e10s"],
   1.364 +        { "action": "store_true",
   1.365 +          "default": False,
   1.366 +          "dest": "e10s",
   1.367 +          "help": "Run tests with electrolysis preferences and test filtering enabled.",
   1.368 +        }],
   1.369 +        [["--dmd-path"],
   1.370 +         { "action": "store",
   1.371 +           "default": None,
   1.372 +           "dest": "dmdPath",
   1.373 +           "help": "Specifies the path to the directory containing the shared library for DMD.",
   1.374 +        }],
   1.375 +        [["--dump-output-directory"],
   1.376 +         { "action": "store",
   1.377 +           "default": None,
   1.378 +           "dest": "dumpOutputDirectory",
   1.379 +           "help": "Specifies the directory in which to place dumped memory reports.",
   1.380 +        }],
   1.381 +        [["--dump-about-memory-after-test"],
   1.382 +         { "action": "store_true",
   1.383 +           "default": False,
   1.384 +           "dest": "dumpAboutMemoryAfterTest",
   1.385 +           "help": "Produce an about:memory dump after each test in the directory specified "
   1.386 +                  "by --dump-output-directory."
   1.387 +        }],
   1.388 +        [["--dump-dmd-after-test"],
   1.389 +         { "action": "store_true",
   1.390 +           "default": False,
   1.391 +           "dest": "dumpDMDAfterTest",
   1.392 +           "help": "Produce a DMD dump after each test in the directory specified "
   1.393 +                  "by --dump-output-directory."
   1.394 +        }],
   1.395 +        [["--slowscript"],
   1.396 +         { "action": "store_true",
   1.397 +           "default": False,
   1.398 +           "dest": "slowscript",
   1.399 +           "help": "Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; "
   1.400 +                   "when not set, recoverable but misleading SIGSEGV instances "
   1.401 +                   "may occur in Ion/Odin JIT code."
   1.402 +        }],
   1.403 +        [["--screenshot-on-fail"],
   1.404 +         { "action": "store_true",
   1.405 +           "default": False,
   1.406 +           "dest": "screenshotOnFail",
   1.407 +           "help": "Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots."
   1.408 +        }],
   1.409 +        [["--quiet"],
   1.410 +         { "action": "store_true",
   1.411 +           "default": False,
   1.412 +           "dest": "quiet",
   1.413 +           "help": "Do not print test log lines unless a failure occurs."
   1.414 +         }],
   1.415 +        [["--pidfile"],
   1.416 +        { "action": "store",
   1.417 +          "type": "string",
   1.418 +          "dest": "pidFile",
   1.419 +          "help": "name of the pidfile to generate",
   1.420 +          "default": "",
   1.421 +        }],
   1.422 +    ]
   1.423 +
   1.424 +    def __init__(self, **kwargs):
   1.425 +
   1.426 +        optparse.OptionParser.__init__(self, **kwargs)
   1.427 +        for option, value in self.mochitest_options:
   1.428 +            self.add_option(*option, **value)
   1.429 +        addCommonOptions(self)
   1.430 +        self.set_usage(self.__doc__)
   1.431 +
   1.432 +    def verifyOptions(self, options, mochitest):
   1.433 +        """ verify correct options and cleanup paths """
   1.434 +
   1.435 +        mozinfo.update({"e10s": options.e10s}) # for test manifest parsing.
   1.436 +
   1.437 +        if options.app is None:
   1.438 +            if build_obj is not None:
   1.439 +                options.app = build_obj.get_binary_path()
   1.440 +            else:
   1.441 +                self.error("could not find the application path, --appname must be specified")
   1.442 +
   1.443 +        if options.totalChunks is not None and options.thisChunk is None:
   1.444 +            self.error("thisChunk must be specified when totalChunks is specified")
   1.445 +
   1.446 +        if options.totalChunks:
   1.447 +            if not 1 <= options.thisChunk <= options.totalChunks:
   1.448 +                self.error("thisChunk must be between 1 and totalChunks")
   1.449 +
   1.450 +        if options.xrePath is None:
   1.451 +            # default xrePath to the app path if not provided
   1.452 +            # but only if an app path was explicitly provided
   1.453 +            if options.app != self.defaults['app']:
   1.454 +                options.xrePath = os.path.dirname(options.app)
   1.455 +            elif build_obj is not None:
   1.456 +                # otherwise default to dist/bin
   1.457 +                options.xrePath = build_obj.bindir
   1.458 +            else:
   1.459 +                self.error("could not find xre directory, --xre-path must be specified")
   1.460 +
   1.461 +        # allow relative paths
   1.462 +        options.xrePath = mochitest.getFullPath(options.xrePath)
   1.463 +        options.profilePath = mochitest.getFullPath(options.profilePath)
   1.464 +        options.app = mochitest.getFullPath(options.app)
   1.465 +        if options.dmdPath is not None:
   1.466 +            options.dmdPath = mochitest.getFullPath(options.dmdPath)
   1.467 +
   1.468 +        if not os.path.exists(options.app):
   1.469 +            msg = """\
   1.470 +            Error: Path %(app)s doesn't exist.
   1.471 +            Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
   1.472 +            self.error(msg % {"app": options.app})
   1.473 +            return None
   1.474 +
   1.475 +        if options.utilityPath:
   1.476 +            options.utilityPath = mochitest.getFullPath(options.utilityPath)
   1.477 +
   1.478 +        if options.certPath:
   1.479 +            options.certPath = mochitest.getFullPath(options.certPath)
   1.480 +
   1.481 +        if options.symbolsPath and not isURL(options.symbolsPath):
   1.482 +            options.symbolsPath = mochitest.getFullPath(options.symbolsPath)
   1.483 +
   1.484 +        # Set server information on the options object
   1.485 +        options.webServer = '127.0.0.1'
   1.486 +        options.httpPort = DEFAULT_PORTS['http']
   1.487 +        options.sslPort = DEFAULT_PORTS['https']
   1.488 +        #        options.webSocketPort = DEFAULT_PORTS['ws']
   1.489 +        options.webSocketPort = str(9988) # <- http://hg.mozilla.org/mozilla-central/file/b871dfb2186f/build/automation.py.in#l30
   1.490 +        # The default websocket port is incorrect in mozprofile; it is
   1.491 +        # set to the SSL proxy setting. See:
   1.492 +        # see https://bugzilla.mozilla.org/show_bug.cgi?id=916517
   1.493 +
   1.494 +        if options.vmwareRecording:
   1.495 +            if not mozinfo.isWin:
   1.496 +                self.error("use-vmware-recording is only supported on Windows.")
   1.497 +            mochitest.vmwareHelperPath = os.path.join(
   1.498 +                options.utilityPath, VMWARE_RECORDING_HELPER_BASENAME + ".dll")
   1.499 +            if not os.path.exists(mochitest.vmwareHelperPath):
   1.500 +                self.error("%s not found, cannot automate VMware recording." %
   1.501 +                           mochitest.vmwareHelperPath)
   1.502 +
   1.503 +        if options.testManifest and options.runOnlyTests:
   1.504 +            self.error("Please use --test-manifest only and not --run-only-tests")
   1.505 +
   1.506 +        if options.runOnlyTests:
   1.507 +            if not os.path.exists(os.path.abspath(os.path.join(here, options.runOnlyTests))):
   1.508 +                self.error("unable to find --run-only-tests file '%s'" % options.runOnlyTests)
   1.509 +            options.runOnly = True
   1.510 +            options.testManifest = options.runOnlyTests
   1.511 +            options.runOnlyTests = None
   1.512 +
   1.513 +        if options.manifestFile and options.testManifest:
   1.514 +            self.error("Unable to support both --manifest and --test-manifest/--run-only-tests at the same time")
   1.515 +
   1.516 +        if options.webapprtContent and options.webapprtChrome:
   1.517 +            self.error("Only one of --webapprt-content and --webapprt-chrome may be given.")
   1.518 +
   1.519 +        if options.jsdebugger:
   1.520 +            options.extraPrefs += [
   1.521 +                "devtools.debugger.remote-enabled=true",
   1.522 +                "devtools.debugger.chrome-enabled=true",
   1.523 +                "devtools.chrome.enabled=true",
   1.524 +                "devtools.debugger.prompt-connection=false"
   1.525 +            ]
   1.526 +            options.autorun = False
   1.527 +
   1.528 +        if options.debugOnFailure and not options.jsdebugger:
   1.529 +          self.error("--debug-on-failure should be used together with --jsdebugger.")
   1.530 +
   1.531 +        # Try to guess the testing modules directory.
   1.532 +        # This somewhat grotesque hack allows the buildbot machines to find the
   1.533 +        # modules directory without having to configure the buildbot hosts. This
   1.534 +        # code should never be executed in local runs because the build system
   1.535 +        # should always set the flag that populates this variable. If buildbot ever
   1.536 +        # passes this argument, this code can be deleted.
   1.537 +        if options.testingModulesDir is None:
   1.538 +            possible = os.path.join(here, os.path.pardir, 'modules')
   1.539 +
   1.540 +            if os.path.isdir(possible):
   1.541 +                options.testingModulesDir = possible
   1.542 +
   1.543 +        # Even if buildbot is updated, we still want this, as the path we pass in
   1.544 +        # to the app must be absolute and have proper slashes.
   1.545 +        if options.testingModulesDir is not None:
   1.546 +            options.testingModulesDir = os.path.normpath(options.testingModulesDir)
   1.547 +
   1.548 +            if not os.path.isabs(options.testingModulesDir):
   1.549 +                options.testingModulesDir = os.path.abspath(options.testingModulesDir)
   1.550 +
   1.551 +            if not os.path.isdir(options.testingModulesDir):
   1.552 +                self.error('--testing-modules-dir not a directory: %s' %
   1.553 +                    options.testingModulesDir)
   1.554 +
   1.555 +            options.testingModulesDir = options.testingModulesDir.replace('\\', '/')
   1.556 +            if options.testingModulesDir[-1] != '/':
   1.557 +                options.testingModulesDir += '/'
   1.558 +
   1.559 +        if options.immersiveMode:
   1.560 +            if not mozinfo.isWin:
   1.561 +                self.error("immersive is only supported on Windows 8 and up.")
   1.562 +            mochitest.immersiveHelperPath = os.path.join(
   1.563 +                options.utilityPath, "metrotestharness.exe")
   1.564 +            if not os.path.exists(mochitest.immersiveHelperPath):
   1.565 +                self.error("%s not found, cannot launch immersive tests." %
   1.566 +                           mochitest.immersiveHelperPath)
   1.567 +
   1.568 +        if options.runUntilFailure:
   1.569 +            if not options.repeat:
   1.570 +                options.repeat = 29
   1.571 +
   1.572 +        if options.dumpOutputDirectory is None:
   1.573 +            options.dumpOutputDirectory = tempfile.gettempdir()
   1.574 +
   1.575 +        if options.dumpAboutMemoryAfterTest or options.dumpDMDAfterTest:
   1.576 +            if not os.path.isdir(options.dumpOutputDirectory):
   1.577 +                self.error('--dump-output-directory not a directory: %s' %
   1.578 +                           options.dumpOutputDirectory)
   1.579 +
   1.580 +        return options
   1.581 +
   1.582 +
   1.583 +class B2GOptions(MochitestOptions):
   1.584 +    b2g_options = [
   1.585 +        [["--b2gpath"],
   1.586 +        { "action": "store",
   1.587 +          "type": "string",
   1.588 +          "dest": "b2gPath",
   1.589 +          "help": "path to B2G repo or qemu dir",
   1.590 +          "default": None,
   1.591 +        }],
   1.592 +        [["--desktop"],
   1.593 +        { "action": "store_true",
   1.594 +          "dest": "desktop",
   1.595 +          "help": "Run the tests on a B2G desktop build",
   1.596 +          "default": False,
   1.597 +        }],
   1.598 +        [["--marionette"],
   1.599 +        { "action": "store",
   1.600 +          "type": "string",
   1.601 +          "dest": "marionette",
   1.602 +          "help": "host:port to use when connecting to Marionette",
   1.603 +          "default": None,
   1.604 +        }],
   1.605 +        [["--emulator"],
   1.606 +        { "action": "store",
   1.607 +          "type": "string",
   1.608 +          "dest": "emulator",
   1.609 +          "help": "Architecture of emulator to use: x86 or arm",
   1.610 +          "default": None,
   1.611 +        }],
   1.612 +        [["--wifi"],
   1.613 +        { "action": "store",
   1.614 +          "type": "string",
   1.615 +          "dest": "wifi",
   1.616 +          "help": "Devine wifi configuration for on device mochitest",
   1.617 +          "default": False,
   1.618 +        }],
   1.619 +        [["--sdcard"],
   1.620 +        { "action": "store",
   1.621 +          "type": "string",
   1.622 +          "dest": "sdcard",
   1.623 +          "help": "Define size of sdcard: 1MB, 50MB...etc",
   1.624 +          "default": "10MB",
   1.625 +        }],
   1.626 +        [["--no-window"],
   1.627 +        { "action": "store_true",
   1.628 +          "dest": "noWindow",
   1.629 +          "help": "Pass --no-window to the emulator",
   1.630 +          "default": False,
   1.631 +        }],
   1.632 +        [["--adbpath"],
   1.633 +        { "action": "store",
   1.634 +          "type": "string",
   1.635 +          "dest": "adbPath",
   1.636 +          "help": "path to adb",
   1.637 +          "default": "adb",
   1.638 +        }],
   1.639 +        [["--deviceIP"],
   1.640 +        { "action": "store",
   1.641 +          "type": "string",
   1.642 +          "dest": "deviceIP",
   1.643 +          "help": "ip address of remote device to test",
   1.644 +          "default": None,
   1.645 +        }],
   1.646 +        [["--devicePort"],
   1.647 +        { "action": "store",
   1.648 +          "type": "string",
   1.649 +          "dest": "devicePort",
   1.650 +          "help": "port of remote device to test",
   1.651 +          "default": 20701,
   1.652 +        }],
   1.653 +        [["--remote-logfile"],
   1.654 +        { "action": "store",
   1.655 +          "type": "string",
   1.656 +          "dest": "remoteLogFile",
   1.657 +          "help": "Name of log file on the device relative to the device root. \
   1.658 +                  PLEASE ONLY USE A FILENAME.",
   1.659 +          "default" : None,
   1.660 +        }],
   1.661 +        [["--remote-webserver"],
   1.662 +        { "action": "store",
   1.663 +          "type": "string",
   1.664 +          "dest": "remoteWebServer",
   1.665 +          "help": "ip address where the remote web server is hosted at",
   1.666 +          "default": None,
   1.667 +        }],
   1.668 +        [["--http-port"],
   1.669 +        { "action": "store",
   1.670 +          "type": "string",
   1.671 +          "dest": "httpPort",
   1.672 +          "help": "ip address where the remote web server is hosted at",
   1.673 +          "default": None,
   1.674 +        }],
   1.675 +        [["--ssl-port"],
   1.676 +        { "action": "store",
   1.677 +          "type": "string",
   1.678 +          "dest": "sslPort",
   1.679 +          "help": "ip address where the remote web server is hosted at",
   1.680 +          "default": None,
   1.681 +        }],
   1.682 +        [["--gecko-path"],
   1.683 +        { "action": "store",
   1.684 +          "type": "string",
   1.685 +          "dest": "geckoPath",
   1.686 +          "help": "the path to a gecko distribution that should \
   1.687 +                   be installed on the emulator prior to test",
   1.688 +          "default": None,
   1.689 +        }],
   1.690 +        [["--profile"],
   1.691 +        { "action": "store",
   1.692 +          "type": "string",
   1.693 +          "dest": "profile",
   1.694 +          "help": "for desktop testing, the path to the \
   1.695 +                   gaia profile to use",
   1.696 +          "default": None,
   1.697 +        }],
   1.698 +        [["--logcat-dir"],
   1.699 +        { "action": "store",
   1.700 +          "type": "string",
   1.701 +          "dest": "logcat_dir",
   1.702 +          "help": "directory to store logcat dump files",
   1.703 +          "default": None,
   1.704 +        }],
   1.705 +        [['--busybox'],
   1.706 +        { "action": 'store',
   1.707 +          "type": 'string',
   1.708 +          "dest": 'busybox',
   1.709 +          "help": "Path to busybox binary to install on device",
   1.710 +          "default": None,
   1.711 +        }],
   1.712 +        [['--profile-data-dir'],
   1.713 +        { "action": 'store',
   1.714 +          "type": 'string',
   1.715 +          "dest": 'profile_data_dir',
   1.716 +          "help": "Path to a directory containing preference and other \
   1.717 +                   data to be installed into the profile",
   1.718 +          "default": os.path.join(here, 'profile_data'),
   1.719 +        }],
   1.720 +    ]
   1.721 +
   1.722 +    def __init__(self):
   1.723 +        MochitestOptions.__init__(self)
   1.724 +
   1.725 +        for option in self.b2g_options:
   1.726 +            self.add_option(*option[0], **option[1])
   1.727 +
   1.728 +        defaults = {}
   1.729 +        defaults["httpPort"] = DEFAULT_PORTS['http']
   1.730 +        defaults["sslPort"] = DEFAULT_PORTS['https']
   1.731 +        defaults["remoteTestRoot"] = "/data/local/tests"
   1.732 +        defaults["logFile"] = "mochitest.log"
   1.733 +        defaults["autorun"] = True
   1.734 +        defaults["closeWhenDone"] = True
   1.735 +        defaults["testPath"] = ""
   1.736 +        defaults["extensionsToExclude"] = ["specialpowers"]
   1.737 +        self.set_defaults(**defaults)
   1.738 +
   1.739 +    def verifyRemoteOptions(self, options):
   1.740 +        if options.remoteWebServer == None:
   1.741 +            if os.name != "nt":
   1.742 +                options.remoteWebServer = moznetwork.get_ip()
   1.743 +            else:
   1.744 +                self.error("You must specify a --remote-webserver=<ip address>")
   1.745 +        options.webServer = options.remoteWebServer
   1.746 +
   1.747 +        if options.geckoPath and not options.emulator:
   1.748 +            self.error("You must specify --emulator if you specify --gecko-path")
   1.749 +
   1.750 +        if options.logcat_dir and not options.emulator:
   1.751 +            self.error("You must specify --emulator if you specify --logcat-dir")
   1.752 +
   1.753 +        if not os.path.isdir(options.xrePath):
   1.754 +            self.error("--xre-path '%s' is not a directory" % options.xrePath)
   1.755 +        xpcshell = os.path.join(options.xrePath, 'xpcshell')
   1.756 +        if not os.access(xpcshell, os.F_OK):
   1.757 +            self.error('xpcshell not found at %s' % xpcshell)
   1.758 +        if self.elf_arm(xpcshell):
   1.759 +            self.error('--xre-path points to an ARM version of xpcshell; it '
   1.760 +                       'should instead point to a version that can run on '
   1.761 +                       'your desktop')
   1.762 +
   1.763 +        if options.pidFile != "":
   1.764 +            f = open(options.pidFile, 'w')
   1.765 +            f.write("%s" % os.getpid())
   1.766 +            f.close()
   1.767 +
   1.768 +        return options
   1.769 +
   1.770 +    def verifyOptions(self, options, mochitest):
   1.771 +        # since we are reusing verifyOptions, it will exit if App is not found
   1.772 +        temp = options.app
   1.773 +        options.app = __file__
   1.774 +        tempPort = options.httpPort
   1.775 +        tempSSL = options.sslPort
   1.776 +        tempIP = options.webServer
   1.777 +        options = MochitestOptions.verifyOptions(self, options, mochitest)
   1.778 +        options.webServer = tempIP
   1.779 +        options.app = temp
   1.780 +        options.sslPort = tempSSL
   1.781 +        options.httpPort = tempPort
   1.782 +
   1.783 +        return options
   1.784 +
   1.785 +    def elf_arm(self, filename):
   1.786 +        data = open(filename, 'rb').read(20)
   1.787 +        return data[:4] == "\x7fELF" and ord(data[18]) == 40 # EM_ARM

mercurial