mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1193257
- Make xpcshell harness command line arguments path filters for tests, r=ahal
This commit is contained in:
parent
2dda4d11ae
commit
5301bd7761
@ -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']
|
||||
|
@ -10,6 +10,7 @@ TEST_HARNESS_FILES := \
|
||||
runxpcshelltests.py \
|
||||
remotexpcshelltests.py \
|
||||
runtestsb2g.py \
|
||||
xpcshellcommandline.py \
|
||||
head.js \
|
||||
node-spdy \
|
||||
moz-spdy \
|
||||
|
@ -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,
|
||||
mobileArgs=xpcshell.mobileArgs,
|
||||
**options.__dict__)
|
||||
result = xpcshell.runTests(testClass=remotexpcshelltests.RemoteXPCShellTestThread,
|
||||
mobileArgs=xpcshell.mobileArgs,
|
||||
**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):
|
||||
@ -409,61 +328,10 @@ class MachCommands(MachCommandBase):
|
||||
setattr(self, attr, getattr(context, attr, None))
|
||||
|
||||
@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).')
|
||||
description='Run XPCOM Shell tests (API direct unit testing)',
|
||||
conditions=[lambda *args: True],
|
||||
parser=get_parser)
|
||||
|
||||
def run_xpcshell_test(self, **params):
|
||||
from mozbuild.controller.building import BuildDriver
|
||||
|
||||
|
@ -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,90 +529,37 @@ 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):
|
||||
if options.localLib is None:
|
||||
if options.localAPK and options.objdir:
|
||||
for path in ['dist/fennec', 'fennec/lib']:
|
||||
options.localLib = os.path.join(options.objdir, path)
|
||||
if os.path.isdir(options.localLib):
|
||||
break
|
||||
else:
|
||||
self.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'))
|
||||
def verifyRemoteOptions(parser, options):
|
||||
if options.localLib is None:
|
||||
if options.localAPK and options.objdir:
|
||||
for path in ['dist/fennec', 'fennec/lib']:
|
||||
options.localLib = os.path.join(options.objdir, path)
|
||||
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:
|
||||
parser.error("Couldn't find local library dir, specify --local-lib-dir")
|
||||
|
||||
if options.localBin is None:
|
||||
if options.objdir:
|
||||
for path in ['dist/bin', 'bin']:
|
||||
options.localBin = os.path.join(options.objdir, path)
|
||||
if os.path.isdir(options.localBin):
|
||||
break
|
||||
else:
|
||||
self.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'))
|
||||
if options.localBin is None:
|
||||
if options.objdir:
|
||||
for path in ['dist/bin', 'bin']:
|
||||
options.localBin = os.path.join(options.objdir, path)
|
||||
if os.path.isdir(options.localBin):
|
||||
break
|
||||
else:
|
||||
self.error("Couldn't find local binary dir, specify --local-bin-dir")
|
||||
return options
|
||||
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:
|
||||
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)
|
||||
|
||||
|
||||
|
@ -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 verifyRemoteOptions(parser, options):
|
||||
if options.b2g_path is None:
|
||||
parser.error("Need to specify a --b2gpath")
|
||||
|
||||
def __init__(self):
|
||||
RemoteXPCShellOptions.__init__(self)
|
||||
defaults = {}
|
||||
if options.geckoPath and not options.emulator:
|
||||
parser.error("You must specify --emulator if you specify --gecko-path")
|
||||
|
||||
self.add_option('--b2gpath', action='store',
|
||||
type='string', dest='b2g_path',
|
||||
help="Path to B2G repo or qemu dir")
|
||||
defaults['b2g_path'] = None
|
||||
if options.logdir and not options.emulator:
|
||||
parser.error("You must specify --emulator if you specify --logdir")
|
||||
return remotexpcshelltests.verifyRemoteOptions(parser, options)
|
||||
|
||||
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):
|
||||
if options.b2g_path is None:
|
||||
self.error("Need to specify a --b2gpath")
|
||||
|
||||
if options.geckoPath and not options.emulator:
|
||||
self.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)
|
||||
|
||||
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,
|
||||
mobileArgs=xpcsh.mobileArgs,
|
||||
**options.__dict__):
|
||||
if not xpcsh.runTests(testClass=B2GXPCShellTestThread,
|
||||
mobileArgs=xpcsh.mobileArgs,
|
||||
**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
|
||||
|
@ -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__':
|
||||
|
202
testing/xpcshell/xpcshellcommandline.py
Normal file
202
testing/xpcshell/xpcshellcommandline.py
Normal 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
|
Loading…
Reference in New Issue
Block a user