Bug 1193257 - Make xpcshell harness command line arguments path filters for tests, r=ahal

This commit is contained in:
James Graham 2015-08-27 13:05:50 +01:00
parent f4efe79d62
commit 6969ca055e
7 changed files with 467 additions and 619 deletions

View File

@ -221,11 +221,13 @@ config = {
'tests/reftest/tests/testing/crashtest/crashtests.list']},
},
"all_xpcshell_suites": {
"xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list",
"%(abs_app_dir)s/" + XPCSHELL_NAME],
"xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list",
"--tag=addons",
"%(abs_app_dir)s/" + XPCSHELL_NAME]
"xpcshell": {'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME,
"--manifest=tests/xpcshell/tests/all-test-dirs.list"],
'tests': []},
"xpcshell-addons": {'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME,
"--manifest=tests/xpcshell/tests/all-test-dirs.list",
"--tag=addons"],
'tests': []}
},
"all_cppunittest_suites": {
"cppunittest": ['tests/cppunittest']

View File

@ -10,6 +10,7 @@ TEST_HARNESS_FILES := \
runxpcshelltests.py \
remotexpcshelltests.py \
runtestsb2g.py \
xpcshellcommandline.py \
head.js \
node-spdy \
moz-spdy \

View File

@ -25,8 +25,7 @@ from mach.decorators import (
Command,
)
_parser = argparse.ArgumentParser()
structured.commandline.add_logging_group(_parser)
from xpcshellcommandline import parser_desktop, parser_remote, parser_b2g
ADB_NOT_FOUND = '''
The %s command requires the adb binary to be on your path.
@ -40,6 +39,7 @@ BUSYBOX_URLS = {
'x86': 'http://www.busybox.net/downloads/binaries/latest/busybox-i686'
}
here = os.path.abspath(os.path.dirname(__file__))
if sys.version_info[0] < 3:
unicode_type = unicode
@ -55,20 +55,9 @@ class InvalidTestPathError(Exception):
class XPCShellRunner(MozbuildObject):
"""Run xpcshell tests."""
def run_suite(self, **kwargs):
from manifestparser import TestManifest
manifest = TestManifest(manifests=[os.path.join(self.topobjdir,
'_tests', 'xpcshell', 'xpcshell.ini')])
return self._run_xpcshell_harness(**kwargs)
return self._run_xpcshell_harness(manifest=manifest, **kwargs)
def run_test(self, test_paths, interactive=False,
keep_going=False, sequential=False, shuffle=False,
debugger=None, debuggerArgs=None, debuggerInteractive=None,
jsDebugger=False, jsDebuggerPort=None,
rerun_failures=False, test_objects=None, verbose=False,
log=None, test_tags=None, dump_tests=None,
# ignore parameters from other platforms' options
**kwargs):
def run_test(self, **kwargs):
"""Runs an individual xpcshell test."""
from mozbuild.testing import TestResolver
from manifestparser import TestManifest
@ -82,65 +71,15 @@ class XPCShellRunner(MozbuildObject):
if os.path.isdir(src_build_path):
sys.path.append(src_build_path)
if test_paths == 'all':
self.run_suite(interactive=interactive,
keep_going=keep_going, shuffle=shuffle, sequential=sequential,
debugger=debugger, debuggerArgs=debuggerArgs,
debuggerInteractive=debuggerInteractive,
jsDebugger=jsDebugger, jsDebuggerPort=jsDebuggerPort,
rerun_failures=rerun_failures,
verbose=verbose, log=log, test_tags=test_tags, dump_tests=dump_tests)
return
elif test_paths:
test_paths = [self._wrap_path_argument(p).relpath() for p in test_paths]
self.run_suite(**kwargs)
if test_objects:
tests = test_objects
else:
resolver = self._spawn(TestResolver)
tests = list(resolver.resolve_tests(paths=test_paths,
flavor='xpcshell'))
if not tests:
raise InvalidTestPathError('We could not find an xpcshell test '
'for the passed test path. Please select a path that is '
'a test file or is a directory containing xpcshell tests.')
# Dynamically write out a manifest holding all the discovered tests.
manifest = TestManifest()
manifest.tests.extend(tests)
args = {
'interactive': interactive,
'keep_going': keep_going,
'shuffle': shuffle,
'sequential': sequential,
'debugger': debugger,
'debuggerArgs': debuggerArgs,
'debuggerInteractive': debuggerInteractive,
'jsDebugger': jsDebugger,
'jsDebuggerPort': jsDebuggerPort,
'rerun_failures': rerun_failures,
'manifest': manifest,
'verbose': verbose,
'log': log,
'test_tags': test_tags,
'dump_tests': dump_tests,
}
return self._run_xpcshell_harness(**args)
def _run_xpcshell_harness(self, manifest,
test_path=None, shuffle=False, interactive=False,
keep_going=False, sequential=False,
debugger=None, debuggerArgs=None, debuggerInteractive=None,
jsDebugger=False, jsDebuggerPort=None,
rerun_failures=False, verbose=False, log=None, test_tags=None,
dump_tests=None):
def _run_xpcshell_harness(self, **kwargs):
# Obtain a reference to the xpcshell test runner.
import runxpcshelltests
log = kwargs.pop("log")
xpcshell = runxpcshelltests.XPCShellTests(log=log)
self.log_manager.enable_unstructured()
@ -148,59 +87,41 @@ class XPCShellRunner(MozbuildObject):
modules_dir = os.path.join(self.topobjdir, '_tests', 'modules')
# We want output from the test to be written immediately if we are only
# running a single test.
single_test = (test_path is not None or
single_test = (kwargs["testPaths"] is not None or
(manifest and len(manifest.test_paths())==1))
sequential = sequential or single_test
sequential = kwargs["sequential"] or single_test
args = {
'manifest': manifest,
'xpcshell': self.get_binary_path('xpcshell'),
'mozInfo': os.path.join(self.topobjdir, 'mozinfo.json'),
'symbolsPath': os.path.join(self.distdir, 'crashreporter-symbols'),
'interactive': interactive,
'keepGoing': keep_going,
'logfiles': False,
'sequential': sequential,
'shuffle': shuffle,
'testingModulesDir': modules_dir,
'profileName': 'firefox',
'verbose': verbose or single_test,
'xunitFilename': os.path.join(self.statedir, 'xpchsell.xunit.xml'),
'xunitName': 'xpcshell',
'pluginsPath': os.path.join(self.distdir, 'plugins'),
'debugger': debugger,
'debuggerArgs': debuggerArgs,
'debuggerInteractive': debuggerInteractive,
'jsDebugger': jsDebugger,
'jsDebuggerPort': jsDebuggerPort,
'test_tags': test_tags,
'dump_tests': dump_tests,
'utility_path': self.bindir,
}
if kwargs["xpcshell"] is None:
kwargs["xpcshell"] = self.get_binary_path('xpcshell')
if test_path is not None:
args['testPath'] = test_path
if kwargs["mozInfo"] is None:
kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json')
# A failure manifest is written by default. If --rerun-failures is
# specified and a prior failure manifest is found, the prior manifest
# will be run. A new failure manifest is always written over any
# prior failure manifest.
failure_manifest_path = os.path.join(self.statedir, 'xpcshell.failures.ini')
rerun_manifest_path = os.path.join(self.statedir, 'xpcshell.rerun.ini')
if os.path.exists(failure_manifest_path) and rerun_failures:
shutil.move(failure_manifest_path, rerun_manifest_path)
args['manifest'] = rerun_manifest_path
elif os.path.exists(failure_manifest_path):
os.remove(failure_manifest_path)
elif rerun_failures:
print("No failures were found to re-run.")
return 0
args['failureManifest'] = failure_manifest_path
if kwargs["symbolsPath"] is None:
kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols')
if kwargs["logfiles"] is None:
kwargs["logfiles"] = False
if kwargs["profileName"] is None:
kwargs["profileName"] = "firefox"
if kwargs["pluginsPath"] is None:
kwargs['pluginsPath'] = os.path.join(self.distdir, 'plugins')
if kwargs["utility_path"] is None:
kwargs['utility_path'] = self.bindir
if kwargs["manifest"] is None:
kwargs["manifest"] = os.path.join(tests_dir, "xpcshell.ini")
if kwargs["failure_manifest"] is None:
kwargs["failure_manifest"] = os.path.join(self.statedir, 'xpcshell.failures.ini')
# Python through 2.7.2 has issues with unicode in some of the
# arguments. Work around that.
filtered_args = {}
for k, v in args.items():
for k, v in kwargs.iteritems():
if isinstance(v, unicode_type):
v = v.encode('utf-8')
@ -236,12 +157,7 @@ class AndroidXPCShellRunner(MozbuildObject):
return dm
"""Run Android xpcshell tests."""
def run_test(self,
test_paths, keep_going,
devicemanager, ip, port, remote_test_root, no_setup, local_apk,
test_objects=None, log=None,
# ignore parameters from other platforms' options
**kwargs):
def run_test(self, **kwargs):
# TODO Bug 794506 remove once mach integrates with virtualenv.
build_path = os.path.join(self.topobjdir, 'build')
if build_path not in sys.path:
@ -249,60 +165,53 @@ class AndroidXPCShellRunner(MozbuildObject):
import remotexpcshelltests
dm = self.get_devicemanager(devicemanager, ip, port, remote_test_root)
dm = self.get_devicemanager(kwargs["dm_trans"], kwargs["deviceIP"], kwargs["devicePort"],
kwargs["remoteTestRoot"])
options = remotexpcshelltests.RemoteXPCShellOptions()
options.shuffle = False
options.sequential = True
options.interactive = False
options.debugger = None
options.debuggerArgs = None
options.setup = not no_setup
options.keepGoing = keep_going
options.objdir = self.topobjdir
options.localLib = os.path.join(self.topobjdir, 'dist/fennec')
options.localBin = os.path.join(self.topobjdir, 'dist/bin')
options.testingModulesDir = os.path.join(self.topobjdir, '_tests/modules')
options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json')
options.manifest = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini')
options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols')
if local_apk:
options.localAPK = local_apk
else:
for file in os.listdir(os.path.join(options.objdir, "dist")):
if file.endswith(".apk") and file.startswith("fennec"):
options.localAPK = os.path.join(options.objdir, "dist")
options.localAPK = os.path.join(options.localAPK, file)
print ("using APK: " + options.localAPK)
log = kwargs.pop("log")
self.log_manager.enable_unstructured()
if kwargs["xpcshell"] is None:
kwargs["xpcshell"] = "xpcshell"
if not kwargs["objdir"]:
kwargs["objdir"] = self.topobjdir
if not kwargs["localLib"]:
kwargs["localLib"] = os.path.join(self.topobjdir, 'dist/fennec')
if not kwargs["localBin"]:
kwargs["localBin"] = os.path.join(self.topobjdir, 'dist/bin')
if not kwargs["testingModulesDir"]:
kwargs["testingModulesDir"] = os.path.join(self.topobjdir, '_tests/modules')
if not kwargs["mozInfo"]:
kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json')
if not kwargs["manifest"]:
kwargs["manifest"] = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini')
if not kwargs["symbolsPath"]:
kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols')
if not kwargs["localAPK"]:
for file_name in os.listdir(os.path.join(kwargs["objdir"], "dist")):
if file_name.endswith(".apk") and file_name.startswith("fennec"):
kwargs["localAPK"] = os.path.join(kwargs["objdir"], "dist", file_name)
print ("using APK: %s" % kwargs["localAPK"])
break
else:
raise Exception("You must specify an APK")
if test_paths == 'all':
testdirs = []
options.testPath = None
options.verbose = False
elif test_objects:
if len(test_objects) > 1:
print('Warning: only the first test will be used.')
testdirs = test_objects[0]['dir_relpath']
options.testPath = test_objects[0]['path']
options.verbose = True
else:
if len(test_paths) > 1:
print('Warning: only the first test path argument will be used.')
testdirs = test_paths[0]
options.testPath = test_paths[0]
options.verbose = True
options = argparse.Namespace(**kwargs)
xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, log)
xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, testdirs, log)
result = xpcshell.runTests(xpcshell='xpcshell',
testClass=remotexpcshelltests.RemoteXPCShellTestThread,
testdirs=testdirs,
result = xpcshell.runTests(testClass=remotexpcshelltests.RemoteXPCShellTestThread,
mobileArgs=xpcshell.mobileArgs,
**options.__dict__)
**vars(options))
self.log_manager.disable_unstructured()
return int(not result)
@ -349,56 +258,66 @@ class B2GXPCShellRunner(MozbuildObject):
f.write(data.read())
return busybox_path
def run_test(self, test_paths, b2g_home=None, busybox=None, device_name=None,
test_objects=None, log=None,
# ignore parameters from other platforms' options
**kwargs):
def run_test(self, **kwargs):
try:
import which
which.which('adb')
except which.WhichError:
# TODO Find adb automatically if it isn't on the path
print(ADB_NOT_FOUND % ('mochitest-remote', b2g_home))
print(ADB_NOT_FOUND % ('mochitest-remote', kwargs["b2g_home"]))
sys.exit(1)
test_path = None
if test_objects:
if len(test_objects) > 1:
print('Warning: Only the first test will be used.')
test_path = self._wrap_path_argument(test_objects[0]['path'])
elif test_paths:
if len(test_paths) > 1:
print('Warning: Only the first test path will be used.')
test_path = self._wrap_path_argument(test_paths[0]).relpath()
import runtestsb2g
parser = runtestsb2g.B2GOptions()
options, args = parser.parse_args([])
options.b2g_path = b2g_home
options.busybox = busybox or os.environ.get('BUSYBOX')
options.localLib = self.bin_dir
options.localBin = self.bin_dir
options.logdir = self.xpcshell_dir
options.manifest = os.path.join(self.xpcshell_dir, 'xpcshell.ini')
options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json')
options.objdir = self.topobjdir
options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols'),
options.testingModulesDir = os.path.join(self.tests_dir, 'modules')
options.testPath = test_path
options.use_device_libs = True
log = kwargs.pop("log")
self.log_manager.enable_unstructured()
options.emulator = 'arm'
if device_name.startswith('emulator'):
if 'x86' in device_name:
options.emulator = 'x86'
if kwargs["xpcshell"] is None:
kwargs["xpcshell"] = "xpcshell"
if kwargs["b2g_path"] is None:
kwargs["b2g_path"] = kwargs["b2g_home"]
if kwargs["busybox"] is None:
kwargs["busybox"] = os.environ.get('BUSYBOX')
if kwargs["busybox"] is None:
kwargs["busybox"] = self._download_busybox(kwargs["b2g_home"], kwargs["emulator"])
if not options.busybox:
options.busybox = self._download_busybox(b2g_home, options.emulator)
if kwargs["localLib"] is None:
kwargs["localLib"] = self.bin_dir
if kwargs["localBin"] is None:
kwargs["localBin"] = self.bin_dir
if kwargs["logdir"] is None:
kwargs["logdir"] = self.xpcshell_dir
if kwargs["manifest"] is None:
kwargs["manifest"] = os.path.join(self.xpcshell_dir, 'xpcshell.ini')
if kwargs["mozInfo"] is None:
kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json')
if kwargs["objdir"] is None:
kwargs["objdir"] = self.topobjdir
if kwargs["symbolsPath"] is None:
kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols')
if kwargs["testingModulesDir"] is None:
kwargs["testingModulesDir"] = os.path.join(self.tests_dir, 'modules')
if kwargs["use_device_libs"] is None:
kwargs["use_device_libs"] = True
return runtestsb2g.run_remote_xpcshell(parser, options, args, log)
if kwargs["device_name"].startswith('emulator') and 'x86' in kwargs["device_name"]:
kwargs["emulator"] = 'x86'
parser = parser_b2g()
options = argparse.Namespace(**kwargs)
rv = runtestsb2g.run_remote_xpcshell(parser, options, log)
self.log_manager.disable_unstructured()
return rv
def get_parser():
build_obj = MozbuildObject.from_environment(cwd=here)
if conditions.is_android(build_obj):
return parser_remote()
elif conditions.is_b2g(build_obj):
return parser_b2g()
else:
return parser_desktop()
@CommandProvider
class MachCommands(MachCommandBase):
@ -411,59 +330,8 @@ class MachCommands(MachCommandBase):
@Command('xpcshell-test', category='testing',
description='Run XPCOM Shell tests (API direct unit testing)',
conditions=[lambda *args: True],
parser=_parser)
@CommandArgument('test_paths', default='all', nargs='*', metavar='TEST',
help='Test to run. Can be specified as a single JS file, a directory, '
'or omitted. If omitted, the entire test suite is executed.')
@CommandArgument('--verbose', '-v', action='store_true',
help='Provide full output from each test process.')
@CommandArgument("--debugger", default=None, metavar='DEBUGGER',
help = "Run xpcshell under the given debugger.")
@CommandArgument("--debugger-args", default=None, metavar='ARGS', type=str,
dest = "debuggerArgs",
help = "pass the given args to the debugger _before_ "
"the application on the command line")
@CommandArgument("--debugger-interactive", action = "store_true",
dest = "debuggerInteractive",
help = "prevents the test harness from redirecting "
"stdout and stderr for interactive debuggers")
@CommandArgument("--jsdebugger", dest="jsDebugger", action="store_true",
help="Waits for a devtools JS debugger to connect before "
"starting the test.")
@CommandArgument("--jsdebugger-port", dest="jsDebuggerPort",
type=int, default=6000,
help="The port to listen on for a debugger connection if "
"--jsdebugger is specified (default=6000).")
@CommandArgument('--interactive', '-i', action='store_true',
help='Open an xpcshell prompt before running tests.')
@CommandArgument('--keep-going', '-k', action='store_true',
help='Continue running tests after a SIGINT is received.')
@CommandArgument('--sequential', action='store_true',
help='Run the tests sequentially.')
@CommandArgument('--shuffle', '-s', action='store_true',
help='Randomize the execution order of tests.')
@CommandArgument('--rerun-failures', action='store_true',
help='Reruns failures from last time.')
@CommandArgument('--tag', action='append', dest='test_tags',
help='Filter out tests that don\'t have the given tag. Can be used '
'multiple times in which case the test must contain at least one '
'of the given tags.')
@CommandArgument('--dump-tests', default=None, type=str, dest='dump_tests',
help='Specify path to a filename to dump all the tests that will be run')
@CommandArgument('--devicemanager', default='adb', type=str,
help='(Android) Type of devicemanager to use for communication: adb or sut')
@CommandArgument('--ip', type=str, default=None,
help='(Android) IP address of device')
@CommandArgument('--port', type=int, default=20701,
help='(Android) Port of device')
@CommandArgument('--remote_test_root', type=str, default=None,
help='(Android) Remote test root such as /mnt/sdcard or /data/local')
@CommandArgument('--no-setup', action='store_true',
help='(Android) Do not copy files to device')
@CommandArgument('--local-apk', type=str, default=None,
help='(Android) Use specified Fennec APK')
@CommandArgument('--busybox', type=str, default=None,
help='(B2G) Path to busybox binary (speeds up installation of tests).')
parser=get_parser)
def run_xpcshell_test(self, **params):
from mozbuild.controller.building import BuildDriver

View File

@ -16,6 +16,8 @@ import mozdevice
import mozfile
import mozinfo
from xpcshellcommandline import parser_remote
here = os.path.dirname(os.path.abspath(__file__))
def remoteJoin(path1, path2):
@ -105,7 +107,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
return (list(sanitize_list(test['head'], 'head')),
list(sanitize_list(test['tail'], 'tail')))
def buildXpcsCmd(self, testdir):
def buildXpcsCmd(self):
# change base class' paths to remote paths and use base class to build command
self.xpcshell = remoteJoin(self.remoteBinDir, "xpcw")
self.headJSPath = remoteJoin(self.remoteScriptsDir, 'head.js')
@ -113,7 +115,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
self.httpdManifest = remoteJoin(self.remoteComponentsDir, 'httpd.manifest')
self.testingModulesDir = self.remoteModulesDir
self.testharnessdir = self.remoteScriptsDir
xpcshell.XPCShellTestThread.buildXpcsCmd(self, testdir)
xpcshell.XPCShellTestThread.buildXpcsCmd(self)
# remove "-g <dir> -a <dir>" and add "--greomni <apk>"
del(self.xpcsCmd[1:5])
if self.options.localAPK:
@ -216,7 +218,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
# via devicemanager.
class XPCShellRemote(xpcshell.XPCShellTests, object):
def __init__(self, devmgr, options, args, log):
def __init__(self, devmgr, options, log):
xpcshell.XPCShellTests.__init__(self, log)
# Add Android version (SDK level) to mozinfo so that manifest entries
@ -517,8 +519,8 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
self.device.removeDir(self.remoteMinidumpDir)
self.device.mkDir(self.remoteMinidumpDir)
def buildTestList(self, test_tags=None):
xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags)
def buildTestList(self, test_tags=None, test_paths=None):
xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags, test_paths=test_paths)
uniqueTestPaths = set([])
for test in self.alltests:
uniqueTestPaths.add(test['here'])
@ -527,60 +529,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
remoteScriptDir = remoteJoin(self.remoteScriptsDir, abbrevTestDir)
self.pathMapping.append(PathMapping(testdir, remoteScriptDir))
class RemoteXPCShellOptions(xpcshell.XPCShellOptions):
def __init__(self):
xpcshell.XPCShellOptions.__init__(self)
defaults = {}
self.add_option("--deviceIP", action="store",
type = "string", dest = "deviceIP",
help = "ip address of remote device to test")
defaults["deviceIP"] = None
self.add_option("--devicePort", action="store",
type = "string", dest = "devicePort",
help = "port of remote device to test")
defaults["devicePort"] = 20701
self.add_option("--dm_trans", action="store",
type = "string", dest = "dm_trans",
help = "the transport to use to communicate with device: [adb|sut]; default=sut")
defaults["dm_trans"] = "sut"
self.add_option("--objdir", action="store",
type = "string", dest = "objdir",
help = "local objdir, containing xpcshell binaries")
defaults["objdir"] = None
self.add_option("--apk", action="store",
type = "string", dest = "localAPK",
help = "local path to Fennec APK")
defaults["localAPK"] = None
self.add_option("--noSetup", action="store_false",
dest = "setup",
help = "do not copy any files to device (to be used only if device is already setup)")
defaults["setup"] = True
self.add_option("--local-lib-dir", action="store",
type = "string", dest = "localLib",
help = "local path to library directory")
defaults["localLib"] = None
self.add_option("--local-bin-dir", action="store",
type = "string", dest = "localBin",
help = "local path to bin directory")
defaults["localBin"] = None
self.add_option("--remoteTestRoot", action = "store",
type = "string", dest = "remoteTestRoot",
help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)")
defaults["remoteTestRoot"] = None
self.set_defaults(**defaults)
def verifyRemoteOptions(self, options):
def verifyRemoteOptions(parser, options):
if options.localLib is None:
if options.localAPK and options.objdir:
for path in ['dist/fennec', 'fennec/lib']:
@ -588,14 +537,14 @@ class RemoteXPCShellOptions(xpcshell.XPCShellOptions):
if os.path.isdir(options.localLib):
break
else:
self.error("Couldn't find local library dir, specify --local-lib-dir")
parser.error("Couldn't find local library dir, specify --local-lib-dir")
elif options.objdir:
options.localLib = os.path.join(options.objdir, 'dist/bin')
elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')):
# assume tests are being run from a tests.zip
options.localLib = os.path.abspath(os.path.join(here, '..', 'bin'))
else:
self.error("Couldn't find local library dir, specify --local-lib-dir")
parser.error("Couldn't find local library dir, specify --local-lib-dir")
if options.localBin is None:
if options.objdir:
@ -604,12 +553,12 @@ class RemoteXPCShellOptions(xpcshell.XPCShellOptions):
if os.path.isdir(options.localBin):
break
else:
self.error("Couldn't find local binary dir, specify --local-bin-dir")
parser.error("Couldn't find local binary dir, specify --local-bin-dir")
elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')):
# assume tests are being run from a tests.zip
options.localBin = os.path.abspath(os.path.join(here, '..', 'bin'))
else:
self.error("Couldn't find local binary dir, specify --local-bin-dir")
parser.error("Couldn't find local binary dir, specify --local-bin-dir")
return options
class PathMapping:
@ -619,14 +568,13 @@ class PathMapping:
self.remote = remoteDir
def main():
if sys.version_info < (2,7):
print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0"
sys.exit(1)
parser = RemoteXPCShellOptions()
parser = parser_remote()
commandline.add_logging_group(parser)
options, args = parser.parse_args()
options = parser.parse_args()
if not options.localAPK:
for file in os.listdir(os.path.join(options.objdir, "dist")):
if (file.endswith(".apk") and file.startswith("fennec")):
@ -638,16 +586,11 @@ def main():
print >>sys.stderr, "Error: please specify an APK"
sys.exit(1)
options = parser.verifyRemoteOptions(options)
options = verifyRemoteOptions(parser, options)
log = commandline.setup_logging("Remote XPCShell",
options,
{"tbpl": sys.stdout})
if len(args) < 1 and options.manifest is None:
print >>sys.stderr, """Usage: %s <test dirs>
or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0])
sys.exit(1)
if options.dm_trans == "adb":
if options.deviceIP:
dm = mozdevice.DroidADB(options.deviceIP, options.devicePort, packageName=None, deviceRoot=options.remoteTestRoot)
@ -663,16 +606,17 @@ def main():
print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
sys.exit(1)
xpcsh = XPCShellRemote(dm, options, args, log)
if options.xpcshell is None:
options.xpcshell = "xpcshell"
xpcsh = XPCShellRemote(dm, options, log)
# we don't run concurrent tests on mobile
options.sequential = True
if not xpcsh.runTests(xpcshell='xpcshell',
testClass=RemoteXPCShellTestThread,
testdirs=args[0:],
if not xpcsh.runTests(testClass=RemoteXPCShellTestThread,
mobileArgs=xpcsh.mobileArgs,
**options.__dict__):
**vars(options)):
sys.exit(1)

View File

@ -9,14 +9,15 @@ import os
sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))))
import traceback
from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote, RemoteXPCShellOptions
import remotexpcshelltests
from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote
from mozdevice import devicemanagerADB, DMError
from mozlog import commandline
DEVICE_TEST_ROOT = '/data/local/tests'
from marionette import Marionette
from xpcshellcommandline import parser_b2g
class B2GXPCShellTestThread(RemoteXPCShellTestThread):
# Overridden
@ -75,87 +76,19 @@ class B2GXPCShellRemote(XPCShellRemote):
self.env['LD_LIBRARY_PATH'] = '/system/b2g'
self.options.use_device_libs = True
class B2GOptions(RemoteXPCShellOptions):
def __init__(self):
RemoteXPCShellOptions.__init__(self)
defaults = {}
self.add_option('--b2gpath', action='store',
type='string', dest='b2g_path',
help="Path to B2G repo or qemu dir")
defaults['b2g_path'] = None
self.add_option('--emupath', action='store',
type='string', dest='emu_path',
help="Path to emulator folder (if different "
"from b2gpath")
self.add_option('--no-clean', action='store_false',
dest='clean',
help="Do not clean TESTROOT. Saves [lots of] time")
defaults['clean'] = True
defaults['emu_path'] = None
self.add_option('--emulator', action='store',
type='string', dest='emulator',
help="Architecture of emulator to use: x86 or arm")
defaults['emulator'] = None
self.add_option('--no-window', action='store_true',
dest='no_window',
help="Pass --no-window to the emulator")
defaults['no_window'] = False
self.add_option('--adbpath', action='store',
type='string', dest='adb_path',
help="Path to adb")
defaults['adb_path'] = 'adb'
self.add_option('--address', action='store',
type='string', dest='address',
help="host:port of running Gecko instance to connect to")
defaults['address'] = None
self.add_option('--use-device-libs', action='store_true',
dest='use_device_libs',
help="Don't push .so's")
defaults['use_device_libs'] = False
self.add_option("--gecko-path", action="store",
type="string", dest="geckoPath",
help="the path to a gecko distribution that should "
"be installed on the emulator prior to test")
defaults["geckoPath"] = None
self.add_option("--logdir", action="store",
type="string", dest="logdir",
help="directory to store log files")
defaults["logdir"] = None
self.add_option('--busybox', action='store',
type='string', dest='busybox',
help="Path to busybox binary to install on device")
defaults['busybox'] = None
defaults["remoteTestRoot"] = DEVICE_TEST_ROOT
defaults['dm_trans'] = 'adb'
defaults['debugger'] = None
defaults['debuggerArgs'] = None
self.set_defaults(**defaults)
def verifyRemoteOptions(self, options):
def verifyRemoteOptions(parser, options):
if options.b2g_path is None:
self.error("Need to specify a --b2gpath")
parser.error("Need to specify a --b2gpath")
if options.geckoPath and not options.emulator:
self.error("You must specify --emulator if you specify --gecko-path")
parser.error("You must specify --emulator if you specify --gecko-path")
if options.logdir and not options.emulator:
self.error("You must specify --emulator if you specify --logdir")
return RemoteXPCShellOptions.verifyRemoteOptions(self, options)
parser.error("You must specify --emulator if you specify --logdir")
return remotexpcshelltests.verifyRemoteOptions(parser, options)
def run_remote_xpcshell(parser, options, args, log):
options = parser.verifyRemoteOptions(options)
def run_remote_xpcshell(parser, options, log):
options = verifyRemoteOptions(parser, options)
# Create the Marionette instance
kwargs = {}
@ -195,16 +128,18 @@ def run_remote_xpcshell(parser, options, args, log):
if not options.remoteTestRoot:
options.remoteTestRoot = dm.deviceRoot
xpcsh = B2GXPCShellRemote(dm, options, args, log)
xpcsh = B2GXPCShellRemote(dm, options, log)
# we don't run concurrent tests on mobile
options.sequential = True
if options.xpcshell is None:
options.xpcshell = "xpcshell"
try:
if not xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:],
testClass=B2GXPCShellTestThread,
if not xpcsh.runTests(testClass=B2GXPCShellTestThread,
mobileArgs=xpcsh.mobileArgs,
**options.__dict__):
**vars(options)):
sys.exit(1)
except:
print "Automation Error: Exception caught while running tests"
@ -212,13 +147,13 @@ def run_remote_xpcshell(parser, options, args, log):
sys.exit(1)
def main():
parser = B2GOptions()
parser = parser_b2g()
commandline.add_logging_group(parser)
options, args = parser.parse_args()
options = parser.parse_args()
log = commandline.setup_logging("Remote XPCShell",
options,
{"tbpl": sys.stdout})
run_remote_xpcshell(parser, options, args, log)
run_remote_xpcshell(parser, options, log)
# You usually run this like :
# python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN

View File

@ -23,7 +23,7 @@ import traceback
from collections import deque, namedtuple
from distutils import dir_util
from multiprocessing import cpu_count
from optparse import OptionParser
from argparse import ArgumentParser
from subprocess import Popen, PIPE, STDOUT
from tempfile import mkdtemp, gettempdir
from threading import (
@ -40,6 +40,9 @@ except Exception:
HAVE_PSUTIL = False
from automation import Automation
from xpcshellcommandline import parser_desktop
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
HARNESS_TIMEOUT = 5 * 60
@ -62,7 +65,7 @@ if os.path.isdir(mozbase):
sys.path.append(os.path.join(mozbase, package))
from manifestparser import TestManifest
from manifestparser.filters import chunk_by_slice, tags
from manifestparser.filters import chunk_by_slice, tags, pathprefix
from mozlog import commandline
import mozcrash
import mozinfo
@ -412,7 +415,7 @@ class XPCShellTestThread(Thread):
return (list(sanitize_list(headlist, 'head')),
list(sanitize_list(taillist, 'tail')))
def buildXpcsCmd(self, testdir):
def buildXpcsCmd(self):
"""
Load the root head.js file as the first file in our test path, before other head, test, and tail files.
On a remote system, we overload this to add additional command line arguments, so this gets overloaded.
@ -614,7 +617,7 @@ class XPCShellTestThread(Thread):
self.tempDir = self.setupTempDir()
self.mozInfoJSPath = self.setupMozinfoJS()
self.buildXpcsCmd(test_dir)
self.buildXpcsCmd()
head_files, tail_files = self.getHeadAndTailFiles(self.test_object)
cmdH = self.buildCmdHead(head_files, tail_files, self.xpcsCmd)
@ -767,30 +770,50 @@ class XPCShellTests(object):
self.harness_timeout = HARNESS_TIMEOUT
self.nodeProc = {}
def buildTestList(self, test_tags=None):
def getTestManifest(self, manifest):
if isinstance(manifest, TestManifest):
return manifest
elif manifest is not None:
manifest = os.path.normpath(os.path.abspath(manifest))
if os.path.isfile(manifest):
return TestManifest([manifest], strict=True)
else:
ini_path = os.path.join(manifest, "xpcshell.ini")
else:
ini_path = os.path.join(SCRIPT_DIR, "tests", "xpcshell.ini")
if os.path.exists(ini_path):
return TestManifest([ini_path], strict=True)
else:
print >> sys.stderr, ("Failed to find manifest at %s; use --manifest "
"to set path explicitly." % (ini_path,))
sys.exit(1)
def buildTestList(self, test_tags=None, test_paths=None):
"""
read the xpcshell.ini manifest and set self.alltests to be
an array of test objects.
if we are chunking tests, it will be done here as well
"""
if isinstance(self.manifest, TestManifest):
mp = self.manifest
else:
mp = TestManifest(strict=True)
if self.manifest is None:
for testdir in self.testdirs:
if testdir:
mp.read(os.path.join(testdir, 'xpcshell.ini'))
else:
mp.read(self.manifest)
self.buildTestPath()
if test_paths is None:
test_paths = []
if len(test_paths) == 1 and test_paths[0].endswith(".js"):
self.singleFile = os.path.basename(test_paths[0])
else:
self.singleFile = None
mp = self.getTestManifest(self.manifest)
filters = []
if test_tags:
filters.append(tags(test_tags))
if test_paths:
filters.append(pathprefix(test_paths))
if self.singleFile is None and self.totalChunks > 1:
filters.append(chunk_by_slice(self.thisChunk, self.totalChunks))
try:
@ -917,31 +940,6 @@ class XPCShellTests(object):
pStderr = STDOUT
return pStdout, pStderr
def buildTestPath(self):
"""
If we specifiy a testpath, set the self.testPath variable to be the given directory or file.
|testPath| will be the optional path only, or |None|.
|singleFile| will be the optional test only, or |None|.
"""
self.singleFile = None
if self.testPath is not None:
if self.testPath.endswith('.js'):
# Split into path and file.
if self.testPath.find('/') == -1:
# Test only.
self.singleFile = self.testPath
else:
# Both path and test.
# Reuse |testPath| temporarily.
self.testPath = self.testPath.rsplit('/', 1)
self.singleFile = self.testPath[1]
self.testPath = self.testPath[0]
else:
# Path only.
# Simply remove optional ending separator.
self.testPath = self.testPath.rstrip("/")
def verifyDirPath(self, dirname):
"""
Simple wrapper to get the absolute path for a given directory name.
@ -1044,7 +1042,7 @@ class XPCShellTests(object):
return path
def runTests(self, xpcshell=None, xrePath=None, appPath=None, symbolsPath=None,
manifest=None, testdirs=None, testPath=None, mobileArgs=None,
manifest=None, testPaths=None, mobileArgs=None,
interactive=False, verbose=False, keepGoing=False, logfiles=True,
thisChunk=1, totalChunks=1, debugger=None,
debuggerArgs=None, debuggerInteractive=False,
@ -1052,7 +1050,8 @@ class XPCShellTests(object):
testingModulesDir=None, pluginsPath=None,
testClass=XPCShellTestThread, failureManifest=None,
log=None, stream=None, jsDebugger=False, jsDebuggerPort=0,
test_tags=None, dump_tests=None, utility_path=None, **otherOptions):
test_tags=None, dump_tests=None, utility_path=None,
rerun_failures=False, failure_manifest=None, **otherOptions):
"""Run xpcshell tests.
|xpcshell|, is the xpcshell executable to use to run the tests.
@ -1062,9 +1061,8 @@ class XPCShellTests(object):
breakpad symbols for processing crashes in tests.
|manifest|, if provided, is a file containing a list of
test directories to run.
|testdirs|, if provided, is a list of absolute paths of test directories.
No-manifest only option.
|testPath|, if provided, indicates a single path and/or test to run.
|testPaths|, if provided, is a list of paths to files or directories containing
tests to run.
|pluginsPath|, if provided, custom plugins directory to be returned from
the xpcshell dir svc provider for NS_APP_PLUGINS_DIR_LIST.
|interactive|, if set to True, indicates to provide an xpcshell prompt
@ -1089,9 +1087,6 @@ class XPCShellTests(object):
global gotSIGINT
if testdirs is None:
testdirs = []
# Try to guess modules directory.
# This somewhat grotesque hack allows the buildbot machines to find the
# modules directory without having to configure the buildbot hosts. This
@ -1104,6 +1099,16 @@ class XPCShellTests(object):
if os.path.isdir(possible):
testingModulesDir = possible
if rerun_failures:
if os.path.exists(failure_manifest):
rerun_manifest = os.path.join(os.path.dirname(failure_manifest), "rerun.ini")
shutil.copyfile(failure_manifest, rerun_manifest)
os.remove(failure_manifest)
manifest = rerun_manifest
else:
print >> sys.stderr, "No failures were found to re-run."
sys.exit(1)
if testingModulesDir:
# The resource loader expects native paths. Depending on how we were
# invoked, a UNIX style path may sneak in on Windows. We try to
@ -1132,8 +1137,6 @@ class XPCShellTests(object):
self.appPath = appPath
self.symbolsPath = symbolsPath
self.manifest = manifest
self.testdirs = testdirs
self.testPath = testPath
self.dump_tests = dump_tests
self.interactive = interactive
self.verbose = verbose
@ -1146,11 +1149,7 @@ class XPCShellTests(object):
self.testingModulesDir = testingModulesDir
self.pluginsPath = pluginsPath
self.sequential = sequential
if not testdirs and not manifest:
# nothing to test!
self.log.error("Error: No test dirs or test manifest specified!")
return False
self.failure_manifest = failure_manifest
self.testCount = 0
self.passCount = 0
@ -1203,7 +1202,7 @@ class XPCShellTests(object):
pStdout, pStderr = self.getPipes()
self.buildTestList(test_tags)
self.buildTestList(test_tags, testPaths)
if self.singleFile:
self.sequential = True
@ -1231,7 +1230,7 @@ class XPCShellTests(object):
'logfiles': self.logfiles,
'xpcshell': self.xpcshell,
'xpcsRunArgs': self.xpcsRunArgs,
'failureManifest': failureManifest,
'failureManifest': self.failure_manifest,
'harness_timeout': self.harness_timeout,
'stack_fixer_function': self.stack_fixer_function,
}
@ -1424,119 +1423,16 @@ class XPCShellTests(object):
self.log.suite_end()
return self.failCount == 0
class XPCShellOptions(OptionParser):
def __init__(self):
"""Process command line arguments and call runTests() to do the real work."""
OptionParser.__init__(self)
self.add_option("--app-path",
type="string", dest="appPath", default=None,
help="application directory (as opposed to XRE directory)")
self.add_option("--interactive",
action="store_true", dest="interactive", default=False,
help="don't automatically run tests, drop to an xpcshell prompt")
self.add_option("--verbose",
action="store_true", dest="verbose", default=False,
help="always print stdout and stderr from tests")
self.add_option("--keep-going",
action="store_true", dest="keepGoing", default=False,
help="continue running tests after test killed with control-C (SIGINT)")
self.add_option("--logfiles",
action="store_true", dest="logfiles", default=True,
help="create log files (default, only used to override --no-logfiles)")
self.add_option("--dump-tests",
type="string", dest="dump_tests", default=None,
help="Specify path to a filename to dump all the tests that will be run")
self.add_option("--manifest",
type="string", dest="manifest", default=None,
help="Manifest of test directories to use")
self.add_option("--no-logfiles",
action="store_false", dest="logfiles",
help="don't create log files")
self.add_option("--sequential",
action="store_true", dest="sequential", default=False,
help="Run all tests sequentially")
self.add_option("--test-path",
type="string", dest="testPath", default=None,
help="single path and/or test filename to test")
self.add_option("--testing-modules-dir",
dest="testingModulesDir", default=None,
help="Directory where testing modules are located.")
self.add_option("--test-plugin-path",
type="string", dest="pluginsPath", default=None,
help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. "
"By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory "
"to return for NS_APP_PLUGINS_DIR_LIST when queried.")
self.add_option("--total-chunks",
type = "int", dest = "totalChunks", default=1,
help = "how many chunks to split the tests up into")
self.add_option("--this-chunk",
type = "int", dest = "thisChunk", default=1,
help = "which chunk to run between 1 and --total-chunks")
self.add_option("--profile-name",
type = "string", dest="profileName", default=None,
help="name of application profile being tested")
self.add_option("--build-info-json",
type = "string", dest="mozInfo", default=None,
help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.")
self.add_option("--shuffle",
action="store_true", dest="shuffle", default=False,
help="Execute tests in random order")
self.add_option("--failure-manifest", dest="failureManifest",
action="store",
help="path to file where failure manifest will be written.")
self.add_option("--xre-path",
action = "store", type = "string", dest = "xrePath",
# individual scripts will set a sane default
default = None,
help = "absolute path to directory containing XRE (probably xulrunner)")
self.add_option("--symbols-path",
action = "store", type = "string", dest = "symbolsPath",
default = None,
help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols")
self.add_option("--debugger",
action = "store", dest = "debugger",
help = "use the given debugger to launch the application")
self.add_option("--debugger-args",
action = "store", dest = "debuggerArgs",
help = "pass the given args to the debugger _before_ "
"the application on the command line")
self.add_option("--debugger-interactive",
action = "store_true", dest = "debuggerInteractive",
help = "prevents the test harness from redirecting "
"stdout and stderr for interactive debuggers")
self.add_option("--jsdebugger", dest="jsDebugger", action="store_true",
help="Waits for a devtools JS debugger to connect before "
"starting the test.")
self.add_option("--jsdebugger-port", type="int", dest="jsDebuggerPort",
default=6000,
help="The port to listen on for a debugger connection if "
"--jsdebugger is specified.")
self.add_option("--tag",
action="append", dest="test_tags",
default=None,
help="filter out tests that don't have the given tag. Can be "
"used multiple times in which case the test must contain "
"at least one of the given tags.")
self.add_option("--utility-path",
action="store", dest="utility_path",
default=None,
help="Path to a directory containing utility programs, such "
"as stack fixer scripts.")
def main():
parser = XPCShellOptions()
parser = parser_desktop()
commandline.add_logging_group(parser)
options, args = parser.parse_args()
options = parser.parse_args()
log = commandline.setup_logging("XPCShell", options, {"tbpl": sys.stdout})
if len(args) < 2 and options.manifest is None or \
(len(args) < 1 and options.manifest is not None):
print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
sys.argv[0])
sys.exit(1)
if options.xpcshell is None:
print >> sys.stderr, """Must provide path to xpcshell using --xpcshell"""
xpcsh = XPCShellTests(log)
@ -1544,7 +1440,7 @@ def main():
print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
sys.exit(1)
if not xpcsh.runTests(args[0], testdirs=args[1:], **options.__dict__):
if not xpcsh.runTests(**vars(options)):
sys.exit(1)
if __name__ == '__main__':

View File

@ -0,0 +1,202 @@
import argparse
def add_common_arguments(parser):
parser.add_argument("--app-path",
type=unicode, dest="appPath", default=None,
help="application directory (as opposed to XRE directory)")
parser.add_argument("--interactive",
action="store_true", dest="interactive", default=False,
help="don't automatically run tests, drop to an xpcshell prompt")
parser.add_argument("--verbose",
action="store_true", dest="verbose", default=False,
help="always print stdout and stderr from tests")
parser.add_argument("--keep-going",
action="store_true", dest="keepGoing", default=False,
help="continue running tests after test killed with control-C (SIGINT)")
parser.add_argument("--logfiles",
action="store_true", dest="logfiles", default=True,
help="create log files (default, only used to override --no-logfiles)")
parser.add_argument("--dump-tests", type=str, dest="dump_tests", default=None,
help="Specify path to a filename to dump all the tests that will be run")
parser.add_argument("--manifest",
type=unicode, dest="manifest", default=None,
help="Manifest of test directories to use")
parser.add_argument("--no-logfiles",
action="store_false", dest="logfiles",
help="don't create log files")
parser.add_argument("--sequential",
action="store_true", dest="sequential", default=False,
help="Run all tests sequentially")
parser.add_argument("--testing-modules-dir",
dest="testingModulesDir", default=None,
help="Directory where testing modules are located.")
parser.add_argument("--test-plugin-path",
type=str, dest="pluginsPath", default=None,
help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. "
"By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory "
"to return for NS_APP_PLUGINS_DIR_LIST when queried.")
parser.add_argument("--total-chunks",
type=int, dest="totalChunks", default=1,
help="how many chunks to split the tests up into")
parser.add_argument("--this-chunk",
type=int, dest="thisChunk", default=1,
help="which chunk to run between 1 and --total-chunks")
parser.add_argument("--profile-name",
type=str, dest="profileName", default=None,
help="name of application profile being tested")
parser.add_argument("--build-info-json",
type=str, dest="mozInfo", default=None,
help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.")
parser.add_argument("--shuffle",
action="store_true", dest="shuffle", default=False,
help="Execute tests in random order")
parser.add_argument("--xre-path",
action="store", type=str, dest="xrePath",
# individual scripts will set a sane default
default=None,
help="absolute path to directory containing XRE (probably xulrunner)")
parser.add_argument("--symbols-path",
action="store", type=str, dest="symbolsPath",
default=None,
help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols")
parser.add_argument("--debugger",
action="store", dest="debugger",
help="use the given debugger to launch the application")
parser.add_argument("--debugger-args",
action="store", dest="debuggerArgs",
help="pass the given args to the debugger _before_ "
"the application on the command line")
parser.add_argument("--debugger-interactive",
action="store_true", dest="debuggerInteractive",
help="prevents the test harness from redirecting "
"stdout and stderr for interactive debuggers")
parser.add_argument("--jsdebugger", dest="jsDebugger", action="store_true",
help="Waits for a devtools JS debugger to connect before "
"starting the test.")
parser.add_argument("--jsdebugger-port", type=int, dest="jsDebuggerPort",
default=6000,
help="The port to listen on for a debugger connection if "
"--jsdebugger is specified.")
parser.add_argument("--tag",
action="append", dest="test_tags",
default=None,
help="filter out tests that don't have the given tag. Can be "
"used multiple times in which case the test must contain "
"at least one of the given tags.")
parser.add_argument("--utility-path",
action="store", dest="utility_path",
default=None,
help="Path to a directory containing utility programs, such "
"as stack fixer scripts.")
parser.add_argument("--xpcshell",
action="store", dest="xpcshell",
default=None,
help="Path to xpcshell binary")
# This argument can be just present, or the path to a manifest file. The
# just-present case is usually used for mach which can provide a default
# path to the failure file from the previous run
parser.add_argument("--rerun-failures",
action="store_true",
help="Rerun failures from the previous run, if any")
parser.add_argument("--failure-manifest",
action="store",
help="Path to a manifest file from which to rerun failures "
"(with --rerun-failure) or in which to record failed tests")
parser.add_argument("testPaths", nargs="*", default=None,
help="Paths of tests to run.")
def add_remote_arguments(parser):
parser.add_argument("--deviceIP", action="store", type=str, dest="deviceIP",
help="ip address of remote device to test")
parser.add_argument("--devicePort", action="store", type=str, dest="devicePort",
default=20701, help="port of remote device to test")
parser.add_argument("--dm_trans", action="store", type=str, dest="dm_trans",
choices=["adb", "sut"], default="sut",
help="the transport to use to communicate with device: [adb|sut]; default=sut")
parser.add_argument("--objdir", action="store", type=str, dest="objdir",
help="local objdir, containing xpcshell binaries")
parser.add_argument("--apk", action="store", type=str, dest="localAPK",
help="local path to Fennec APK")
parser.add_argument("--noSetup", action="store_false", dest="setup", default=True,
help="do not copy any files to device (to be used only if device is already setup)")
parser.add_argument("--local-lib-dir", action="store", type=str, dest="localLib",
help="local path to library directory")
parser.add_argument("--local-bin-dir", action="store", type=str, dest="localBin",
help="local path to bin directory")
parser.add_argument("--remoteTestRoot", action="store", type=str, dest="remoteTestRoot",
help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)")
def add_b2g_arguments(parser):
parser.add_argument('--b2gpath', action='store', type=str, dest='b2g_path',
help="Path to B2G repo or qemu dir")
parser.add_argument('--emupath', action='store', type=str, dest='emu_path',
help="Path to emulator folder (if different "
"from b2gpath")
parser.add_argument('--no-clean', action='store_false', dest='clean', default=True,
help="Do not clean TESTROOT. Saves [lots of] time")
parser.add_argument('--emulator', action='store', type=str, dest='emulator',
default="arm", choices=["x86", "arm"],
help="Architecture of emulator to use: x86 or arm")
parser.add_argument('--no-window', action='store_true', dest='no_window', default=False,
help="Pass --no-window to the emulator")
parser.add_argument('--adbpath', action='store', type=str, dest='adb_path',
default="adb", help="Path to adb")
parser.add_argument('--address', action='store', type=str, dest='address',
help="host:port of running Gecko instance to connect to")
parser.add_argument('--use-device-libs', action='store_true', dest='use_device_libs',
default=None, help="Don't push .so's")
parser.add_argument("--gecko-path", action="store", type=str, dest="geckoPath",
help="the path to a gecko distribution that should "
"be installed on the emulator prior to test")
parser.add_argument("--logdir", action="store", type=str, dest="logdir",
help="directory to store log files")
parser.add_argument('--busybox', action='store', type=str, dest='busybox',
help="Path to busybox binary to install on device")
parser.set_defaults(remoteTestRoot="/data/local/tests",
dm_trans="adb")
def parser_desktop():
parser = argparse.ArgumentParser()
add_common_arguments(parser)
return parser
def parser_remote():
parser = argparse.ArgumentParser()
common = parser.add_argument_group("Common Options")
add_common_arguments(common)
remote = parser.add_argument_group("Remote Options")
add_remote_arguments(remote)
return parser
def parser_b2g():
parser = argparse.ArgumentParser()
common = parser.add_argument_group("Common Options")
add_common_arguments(common)
remote = parser.add_argument_group("Remote Options")
add_remote_arguments(remote)
b2g = parser.add_argument_group("B2G Options")
add_b2g_arguments(b2g)
return parser