Bug 842633 - Allow subclasses of MarionetteTestRunner to add their own command line options. r=jgriffin

This commit is contained in:
Dave Hunt 2013-04-25 09:04:21 +01:00
parent 3ceff3f3da
commit 56c8bfcc02
3 changed files with 173 additions and 153 deletions

View File

@ -7,4 +7,4 @@ from marionette_test import MarionetteTestCase, CommonTestCase
from marionette_touch import MarionetteTouchMixin
from emulator import Emulator
from runtests import MarionetteTestRunner
from runtests import MarionetteTestOptions

View File

@ -112,7 +112,7 @@ class MarionetteTestCase(CommonTestCase):
CommonTestCase.__init__(self, methodName, **kwargs)
@classmethod
def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars):
def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
test_mod = imp.load_source(mod_name, filepath)
for name in dir(test_mod):
@ -124,7 +124,8 @@ class MarionetteTestCase(CommonTestCase):
suite.addTest(obj(weakref.ref(marionette),
methodName=testname,
filepath=filepath,
testvars=testvars))
testvars=testvars,
**kwargs))
def setUp(self):
CommonTestCase.setUp(self)

View File

@ -187,8 +187,8 @@ class MarionetteTestRunner(object):
es_server=None, rest_server=None, logger=None,
testgroup="marionette", noWindow=False, logcat_dir=None,
xml_output=None, repeat=0, perf=False, perfserv=None,
gecko_path=None, testvars=None, tree=None, device=None,
symbols_path=None):
gecko_path=None, testvars=None, tree=None, type=None,
device=None, symbols_path=None, **kwargs):
self.address = address
self.emulator = emulator
self.emulatorBinary = emulatorBinary
@ -216,7 +216,9 @@ class MarionetteTestRunner(object):
self.perfserv = perfserv
self.gecko_path = gecko_path
self.testvars = {}
self.test_kwargs = kwargs
self.tree = tree
self.type = type
self.device = device
self.symbols_path = symbols_path
@ -353,12 +355,12 @@ class MarionetteTestRunner(object):
testgroup.submit()
def run_tests(self, tests, testtype=None):
def run_tests(self, tests):
self.reset_test_stats()
starttime = datetime.utcnow()
while self.repeat >=0:
for test in tests:
self.run_test(test, testtype)
self.run_test(test)
self.repeat -= 1
self.logger.info('\nSUMMARY\n-------')
self.logger.info('passed: %d' % self.passed)
@ -391,7 +393,7 @@ class MarionetteTestRunner(object):
self.marionette.instance = None
del self.marionette
def run_test(self, test, testtype):
def run_test(self, test):
if not self.httpd:
print "starting httpd"
self.start_httpd()
@ -407,7 +409,7 @@ class MarionetteTestRunner(object):
if ((filename.startswith('test_') or filename.startswith('browser_')) and
(filename.endswith('.py') or filename.endswith('.js'))):
filepath = os.path.join(root, filename)
self.run_test(filepath, testtype)
self.run_test(filepath)
if self.marionette.check_for_crash():
return
return
@ -419,8 +421,8 @@ class MarionetteTestRunner(object):
if file_ext == '.ini':
testargs = {}
if testtype is not None:
testtypes = testtype.replace('+', ' +').replace('-', ' -').split()
if self.type is not None:
testtypes = self.type.replace('+', ' +').replace('-', ' -').split()
for atype in testtypes:
if atype.startswith('+'):
testargs.update({ atype[1:]: 'true' })
@ -459,7 +461,7 @@ class MarionetteTestRunner(object):
manifest_tests = manifest.active_tests(disabled=False)
for i in manifest.get(tests=manifest_tests, **testargs):
self.run_test(i["path"], testtype)
self.run_test(i["path"])
if self.marionette.check_for_crash():
return
return
@ -468,7 +470,13 @@ class MarionetteTestRunner(object):
for handler in self.test_handlers:
if handler.match(os.path.basename(test)):
handler.add_tests_to_suite(mod_name, filepath, suite, testloader, self.marionette, self.testvars)
handler.add_tests_to_suite(mod_name,
filepath,
suite,
testloader,
self.marionette,
self.testvars,
**self.test_kwargs)
break
if suite.countTestCases():
@ -568,157 +576,168 @@ class MarionetteTestRunner(object):
return doc.toprettyxml(encoding='utf-8')
def parse_options():
parser = OptionParser(usage='%prog [options] test_file_or_dir <test_file_or_dir> ...')
parser.add_option("--autolog",
action = "store_true", dest = "autolog",
default = False,
help = "send test results to autolog")
parser.add_option("--revision",
action = "store", dest = "revision",
help = "git revision for autolog/perfdata submissions")
parser.add_option("--testgroup",
action = "store", dest = "testgroup",
help = "testgroup names for autolog submissions")
parser.add_option("--emulator",
action = "store", dest = "emulator",
default = None, choices = ["x86", "arm"],
help = "If no --address is given, then the harness will launch a B2G emulator "
"on which to run emulator tests. If --address is given, then the harness assumes you are "
"running an emulator already, and will run the emulator tests using that emulator. "
"You need to specify which architecture to emulate for both cases.")
parser.add_option("--emulator-binary",
action = "store", dest = "emulatorBinary",
default = None,
help = "Launch a specific emulator binary rather than "
"launching from the B2G built emulator")
parser.add_option('--emulator-img',
action = 'store', dest = 'emulatorImg',
default = None,
help = "Use a specific image file instead of a fresh one")
parser.add_option('--emulator-res',
action = 'store', dest = 'emulator_res',
default = None, type= 'str',
help = 'Set a custom resolution for the emulator. '
'Example: "480x800"')
parser.add_option("--no-window",
action = "store_true", dest = "noWindow",
default = False,
help = "when Marionette launches an emulator, start it "
"with the -no-window argument")
parser.add_option('--logcat-dir', dest='logcat_dir', action='store',
help='directory to store logcat dump files')
parser.add_option('--address', dest='address', action='store',
help='host:port of running Gecko instance to connect to')
parser.add_option('--device', dest='device', action='store',
help='serial ID of a device to use for adb / fastboot')
parser.add_option('--type', dest='type', action='store',
default='browser+b2g',
help = "The type of test to run, can be a combination "
"of values defined in unit-tests.ini; individual values "
"are combined with '+' or '-' chars. Ex: 'browser+b2g' "
"means the set of tests which are compatible with both "
"browser and b2g; 'b2g-qemu' means the set of tests "
"which are compatible with b2g but do not require an "
"emulator. This argument is only used when loading "
"tests from .ini files.")
parser.add_option('--homedir', dest='homedir', action='store',
help='home directory of emulator files')
parser.add_option('--app', dest='app', action='store',
default=None,
help='application to use')
parser.add_option('--binary', dest='bin', action='store',
help='gecko executable to launch before running the test')
parser.add_option('--profile', dest='profile', action='store',
help='profile to use when launching the gecko process. If not '
'passed, then a profile will be constructed and used.')
parser.add_option('--perf', dest='perf', action='store_true',
default = False,
help='send performance data to perf data server')
parser.add_option('--perf-server', dest='perfserv', action='store',
default=None,
help='dataserver for perf data submission. Entering this value '
'will overwrite the perfserv value in any passed .ini files.')
parser.add_option('--repeat', dest='repeat', action='store', type=int,
default=0, help='number of times to repeat the test(s).')
parser.add_option('-x', '--xml-output', action='store', dest='xml_output',
help='XML output.')
parser.add_option('--gecko-path', dest='gecko_path', action='store',
default=None,
help='path to B2G gecko binaries that should be '
'installed on the device or emulator')
parser.add_option('--testvars', dest='testvars', action='store',
default=None,
help='path to a JSON file with any test data required')
parser.add_option('--tree', dest='tree', action='store',
default='b2g',
help='the tree that the revsion parameter refers to')
parser.add_option('--symbols-path', dest='symbols_path', action='store',
default=None,
help='absolute path to directory containing breakpad '
'symbols, or the URL of a zip file containing symbols')
class MarionetteTestOptions(OptionParser):
options, tests = parser.parse_args()
def __init__(self, **kwargs):
OptionParser.__init__(self, **kwargs)
if not tests:
parser.print_usage()
parser.exit()
self.add_option('--autolog',
action='store_true',
dest='autolog',
default=False,
help='send test results to autolog')
self.add_option('--revision',
action='store',
dest='revision',
help='git revision for autolog/perfdata submissions')
self.add_option('--testgroup',
action='store',
dest='testgroup',
help='testgroup names for autolog submissions')
self.add_option('--emulator',
action='store',
dest='emulator',
choices=['x86', 'arm'],
help='if no --address is given, then the harness will launch a B2G emulator on which to run '
'emulator tests. if --address is given, then the harness assumes you are running an '
'emulator already, and will run the emulator tests using that emulator. you need to '
'specify which architecture to emulate for both cases')
self.add_option('--emulator-binary',
action='store',
dest='emulatorBinary',
help='launch a specific emulator binary rather than launching from the B2G built emulator')
self.add_option('--emulator-img',
action='store',
dest='emulatorImg',
help='use a specific image file instead of a fresh one')
self.add_option('--emulator-res',
action='store',
dest='emulator_res',
type='str',
help='set a custom resolution for the emulator'
'Example: "480x800"')
self.add_option('--no-window',
action='store_true',
dest='noWindow',
default=False,
help='when Marionette launches an emulator, start it with the -no-window argument')
self.add_option('--logcat-dir',
dest='logcat_dir',
action='store',
help='directory to store logcat dump files')
self.add_option('--address',
dest='address',
action='store',
help='host:port of running Gecko instance to connect to')
self.add_option('--device',
dest='device',
action='store',
help='serial ID of a device to use for adb / fastboot')
self.add_option('--type',
dest='type',
action='store',
default='browser+b2g',
help="the type of test to run, can be a combination of values defined in the manifest file; "
"individual values are combined with '+' or '-' characters. for example: 'browser+b2g' "
"means the set of tests which are compatible with both browser and b2g; 'b2g-qemu' means "
"the set of tests which are compatible with b2g but do not require an emulator. this "
"argument is only used when loading tests from manifest files")
self.add_option('--homedir',
dest='homedir',
action='store',
help='home directory of emulator files')
self.add_option('--app',
dest='app',
action='store',
help='application to use')
self.add_option('--binary',
dest='bin',
action='store',
help='gecko executable to launch before running the test')
self.add_option('--profile',
dest='profile',
action='store',
help='profile to use when launching the gecko process. if not passed, then a profile will be '
'constructed and used')
self.add_option('--perf',
dest='perf',
action='store_true',
default=False,
help='send performance data to perf data server')
self.add_option('--perf-server',
dest='perfserv',
action='store',
help='dataserver for perf data submission. entering this value will overwrite the perfserv '
'value in any passed manifest files')
self.add_option('--repeat',
dest='repeat',
action='store',
type=int,
default=0,
help='number of times to repeat the test(s)')
self.add_option('-x', '--xml-output',
action='store',
dest='xml_output',
help='xml output')
self.add_option('--gecko-path',
dest='gecko_path',
action='store',
help='path to b2g gecko binaries that should be installed on the device or emulator')
self.add_option('--testvars',
dest='testvars',
action='store',
help='path to a json file with any test data required')
self.add_option('--tree',
dest='tree',
action='store',
default='b2g',
help='the tree that the revision parameter refers to')
self.add_option('--symbols-path',
dest='symbols_path',
action='store',
help='absolute path to directory containing breakpad symbols, or the url of a zip file containing symbols')
if not options.emulator and not options.address and not options.bin:
parser.print_usage()
print "must specify --binary, --emulator or --address"
parser.exit()
def verify_usage(self):
options, tests = self.parse_args()
# default to storing logcat output for emulator runs
if options.emulator and not options.logcat_dir:
options.logcat_dir = 'logcat'
if not tests:
print 'must specify one or more test files, manifests, or directories'
sys.exit(1)
if options.perf:
import datazilla
if not options.emulator and not options.address and not options.bin:
print 'must specify --binary, --emulator or --address'
sys.exit(1)
# check for valid resolution string, strip whitespaces
try:
if options.emulator_res:
dims = options.emulator_res.split('x')
assert len(dims) == 2
width = str(int(dims[0]))
height = str(int(dims[1]))
options.emulator_res = 'x'.join([width, height])
except:
raise ValueError('Invalid emulator resolution format. '
'Should be like "480x800".')
# default to storing logcat output for emulator runs
if options.emulator and not options.logcat_dir:
options.logcat_dir = 'logcat'
if options.perf:
import datazilla
# check for valid resolution string, strip whitespaces
try:
if options.emulator_res:
dims = options.emulator_res.split('x')
assert len(dims) == 2
width = str(int(dims[0]))
height = str(int(dims[1]))
options.emulator_res = 'x'.join([width, height])
except:
raise ValueError('Invalid emulator resolution format. '
'Should be like "480x800".')
return (options, tests)
def startTestRunner(runner_class, options, tests):
runner = runner_class(address=options.address,
emulator=options.emulator,
emulatorBinary=options.emulatorBinary,
emulatorImg=options.emulatorImg,
emulator_res=options.emulator_res,
homedir=options.homedir,
logcat_dir=options.logcat_dir,
app=options.app,
bin=options.bin,
profile=options.profile,
noWindow=options.noWindow,
revision=options.revision,
testgroup=options.testgroup,
tree=options.tree,
autolog=options.autolog,
xml_output=options.xml_output,
repeat=options.repeat,
perf=options.perf,
perfserv=options.perfserv,
gecko_path=options.gecko_path,
testvars=options.testvars,
device=options.device,
symbols_path=options.symbols_path)
runner.run_tests(tests, testtype=options.type)
runner = runner_class(**vars(options))
runner.run_tests(tests)
return runner
def cli(runner_class=MarionetteTestRunner):
options, tests = parse_options()
def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteTestOptions):
parser = parser_class(usage='%prog [options] test_file_or_dir <test_file_or_dir> ...')
parser.verify_usage()
options, tests = parser.parse_args()
runner = startTestRunner(runner_class, options, tests)
if runner.failed > 0:
sys.exit(10)