Bug 1127376 - PEP8-ify all mochitest .py files (auto-generated), r=ted

This change was generated using the `autopep8` module [1]. To replicate:

    $ pip install --upgrade autopep8
    $ cd gecko
    $ autopep8 -i -a -a -r testing/mochitest --exclude 'testing/mochitest/pywebsocket/*'

[1] https://github.com/hhatto/autopep8
This commit is contained in:
Andrew Halberstadt
2015-02-13 14:42:02 -05:00
parent e51d78c17d
commit a729c1fa7d
6 changed files with 3299 additions and 2464 deletions

View File

@@ -1,7 +1,9 @@
import math import math
import mozinfo import mozinfo
class Bisect(object): class Bisect(object):
"Class for creating, bisecting and summarizing for --bisect-chunk option." "Class for creating, bisecting and summarizing for --bisect-chunk option."
def __init__(self, harness): def __init__(self, harness):
@@ -34,23 +36,28 @@ class Bisect(object):
if not options.totalChunks or not options.thisChunk: if not options.totalChunks or not options.thisChunk:
return tests return tests
# The logic here is same as chunkifyTests.js, we need this for bisecting tests. # The logic here is same as chunkifyTests.js, we need this for
# bisecting tests.
if options.chunkByDir: if options.chunkByDir:
tests_by_dir = {} tests_by_dir = {}
test_dirs = [] test_dirs = []
for test in tests: for test in tests:
directory = test.split("/") directory = test.split("/")
directory = directory[0:min(options.chunkByDir, len(directory)-1)] directory = directory[
0:min(
options.chunkByDir,
len(directory) -
1)]
directory = "/".join(directory) directory = "/".join(directory)
if not directory in tests_by_dir: if directory not in tests_by_dir:
tests_by_dir[directory] = [test] tests_by_dir[directory] = [test]
test_dirs.append(directory) test_dirs.append(directory)
else: else:
tests_by_dir[directory].append(test) tests_by_dir[directory].append(test)
tests_per_chunk = float(len(test_dirs)) / options.totalChunks tests_per_chunk = float(len(test_dirs)) / options.totalChunks
start = int(round((options.thisChunk-1) * tests_per_chunk)) start = int(round((options.thisChunk - 1) * tests_per_chunk))
end = int(round((options.thisChunk) * tests_per_chunk)) end = int(round((options.thisChunk) * tests_per_chunk))
test_dirs = test_dirs[start:end] test_dirs = test_dirs[start:end]
return_tests = [] return_tests = []
@@ -59,7 +66,7 @@ class Bisect(object):
else: else:
tests_per_chunk = float(len(tests)) / options.totalChunks tests_per_chunk = float(len(tests)) / options.totalChunks
start = int(round((options.thisChunk-1) * tests_per_chunk)) start = int(round((options.thisChunk - 1) * tests_per_chunk))
end = int(round(options.thisChunk * tests_per_chunk)) end = int(round(options.thisChunk * tests_per_chunk))
return_tests = tests[start:end] return_tests = tests[start:end]
@@ -83,7 +90,8 @@ class Bisect(object):
"This method is used to call other methods for setting up variables and getting the list of tests for bisection." "This method is used to call other methods for setting up variables and getting the list of tests for bisection."
if options.bisectChunk == "default": if options.bisectChunk == "default":
return tests return tests
# The second condition in 'if' is required to verify that the failing test is the last one. # The second condition in 'if' is required to verify that the failing
# test is the last one.
elif 'loop' not in self.contents or not self.contents['tests'][-1].endswith(options.bisectChunk): elif 'loop' not in self.contents or not self.contents['tests'][-1].endswith(options.bisectChunk):
tests = self.get_tests_for_bisection(options, tests) tests = self.get_tests_for_bisection(options, tests)
status = self.setup(tests) status = self.setup(tests)
@@ -97,14 +105,16 @@ class Bisect(object):
# Check whether sanity check has to be done. Also it is necessary to check whether options.bisectChunk is present # Check whether sanity check has to be done. Also it is necessary to check whether options.bisectChunk is present
# in self.expectedError as we do not want to run if it is "default". # in self.expectedError as we do not want to run if it is "default".
if status == -1 and options.bisectChunk in self.expectedError: if status == -1 and options.bisectChunk in self.expectedError:
# In case we have a debug build, we don't want to run a sanity check, will take too much time. # In case we have a debug build, we don't want to run a sanity
# check, will take too much time.
if mozinfo.info['debug']: if mozinfo.info['debug']:
return status return status
testBleedThrough = self.contents['testsToRun'][0] testBleedThrough = self.contents['testsToRun'][0]
tests = self.contents['totalTests'] tests = self.contents['totalTests']
tests.remove(testBleedThrough) tests.remove(testBleedThrough)
# To make sure that the failing test is dependent on some other test. # To make sure that the failing test is dependent on some other
# test.
if options.bisectChunk in testBleedThrough: if options.bisectChunk in testBleedThrough:
return status return status
@@ -133,7 +143,7 @@ class Bisect(object):
# self.contents['result'] will be expected error only if it fails. # self.contents['result'] will be expected error only if it fails.
elif self.contents['result'] == "FAIL": elif self.contents['result'] == "FAIL":
self.contents['tests'] = self.contents['testsToRun'] self.contents['tests'] = self.contents['testsToRun']
status = 1 # for initializing status = 1 # for initializing
# initialize # initialize
if status: if status:
@@ -189,22 +199,35 @@ class Bisect(object):
def summarize_chunk(self, options): def summarize_chunk(self, options):
"This method is used summarize the results after the list of tests is run." "This method is used summarize the results after the list of tests is run."
if options.bisectChunk == "default": if options.bisectChunk == "default":
# if no expectedError that means all the tests have successfully passed. # if no expectedError that means all the tests have successfully
# passed.
if len(self.expectedError) == 0: if len(self.expectedError) == 0:
return -1 return -1
options.bisectChunk = self.expectedError.keys()[0] options.bisectChunk = self.expectedError.keys()[0]
self.summary.append("\tFound Error in test: %s" % options.bisectChunk) self.summary.append(
"\tFound Error in test: %s" %
options.bisectChunk)
return 0 return 0
# If options.bisectChunk is not in self.result then we need to move to the next run. # If options.bisectChunk is not in self.result then we need to move to
# the next run.
if options.bisectChunk not in self.result: if options.bisectChunk not in self.result:
return -1 return -1
self.summary.append("\tPass %d:" % self.contents['loop']) self.summary.append("\tPass %d:" % self.contents['loop'])
if len(self.contents['testsToRun']) > 1: if len(self.contents['testsToRun']) > 1:
self.summary.append("\t\t%d test files(start,end,failing). [%s, %s, %s]" % (len(self.contents['testsToRun']), self.contents['testsToRun'][0], self.contents['testsToRun'][-2], self.contents['testsToRun'][-1])) self.summary.append(
"\t\t%d test files(start,end,failing). [%s, %s, %s]" % (len(
self.contents['testsToRun']),
self.contents['testsToRun'][0],
self.contents['testsToRun'][
-2],
self.contents['testsToRun'][
-1]))
else: else:
self.summary.append("\t\t1 test file [%s]" % self.contents['testsToRun'][0]) self.summary.append(
"\t\t1 test file [%s]" %
self.contents['testsToRun'][0])
return self.check_for_intermittent(options) return self.check_for_intermittent(options)
if self.result[options.bisectChunk] == "PASS": if self.result[options.bisectChunk] == "PASS":
@@ -217,23 +240,32 @@ class Bisect(object):
elif self.result[options.bisectChunk] == "FAIL": elif self.result[options.bisectChunk] == "FAIL":
if 'expectedError' not in self.contents: if 'expectedError' not in self.contents:
self.summary.append("\t\t%s failed." % self.contents['testsToRun'][-1]) self.summary.append("\t\t%s failed." %
self.contents['expectedError'] = self.expectedError[options.bisectChunk] self.contents['testsToRun'][-1])
self.contents['expectedError'] = self.expectedError[
options.bisectChunk]
status = 0 status = 0
elif self.expectedError[options.bisectChunk] == self.contents['expectedError']: elif self.expectedError[options.bisectChunk] == self.contents['expectedError']:
self.summary.append("\t\t%s failed with expected error." % self.contents['testsToRun'][-1]) self.summary.append(
"\t\t%s failed with expected error." % self.contents['testsToRun'][-1])
self.contents['result'] = "FAIL" self.contents['result'] = "FAIL"
status = 0 status = 0
# This code checks for test-bleedthrough. Should work for any algorithm. # This code checks for test-bleedthrough. Should work for any
# algorithm.
numberOfTests = len(self.contents['testsToRun']) numberOfTests = len(self.contents['testsToRun'])
if numberOfTests < 3: if numberOfTests < 3:
# This means that only 2 tests are run. Since the last test is the failing test itself therefore the bleedthrough test is the first test # This means that only 2 tests are run. Since the last test
self.summary.append("TEST-UNEXPECTED-FAIL | %s | Bleedthrough detected, this test is the root cause for many of the above failures" % self.contents['testsToRun'][0]) # is the failing test itself therefore the bleedthrough
# test is the first test
self.summary.append(
"TEST-UNEXPECTED-FAIL | %s | Bleedthrough detected, this test is the root cause for many of the above failures" %
self.contents['testsToRun'][0])
status = -1 status = -1
else: else:
self.summary.append("\t\t%s failed with different error." % self.contents['testsToRun'][-1]) self.summary.append(
"\t\t%s failed with different error." % self.contents['testsToRun'][-1])
status = -1 status = -1
return status return status
@@ -241,7 +273,9 @@ class Bisect(object):
def check_for_intermittent(self, options): def check_for_intermittent(self, options):
"This method is used to check whether a test is an intermittent." "This method is used to check whether a test is an intermittent."
if self.result[options.bisectChunk] == "PASS": if self.result[options.bisectChunk] == "PASS":
self.summary.append("\t\tThe test %s passed." % self.contents['testsToRun'][0]) self.summary.append(
"\t\tThe test %s passed." %
self.contents['testsToRun'][0])
if self.repeat > 0: if self.repeat > 0:
# loop is set to 1 to again run the single test. # loop is set to 1 to again run the single test.
self.contents['loop'] = 1 self.contents['loop'] = 1
@@ -256,7 +290,9 @@ class Bisect(object):
self.contents['loop'] = 2 self.contents['loop'] = 2
return 1 return 1
elif self.result[options.bisectChunk] == "FAIL": elif self.result[options.bisectChunk] == "FAIL":
self.summary.append("\t\tThe test %s failed." % self.contents['testsToRun'][0]) self.summary.append(
"\t\tThe test %s failed." %
self.contents['testsToRun'][0])
self.failcount += 1 self.failcount += 1
self.contents['loop'] = 1 self.contents['loop'] = 1
self.repeat -= 1 self.repeat -= 1
@@ -269,7 +305,9 @@ class Bisect(object):
return -1 return -1
return 0 return 0
else: else:
self.summary.append("TEST-UNEXPECTED-FAIL | %s | Bleedthrough detected, this test is the root cause for many of the above failures" % self.contents['testsToRun'][0]) self.summary.append(
"TEST-UNEXPECTED-FAIL | %s | Bleedthrough detected, this test is the root cause for many of the above failures" %
self.contents['testsToRun'][0])
return -1 return -1
def print_summary(self): def print_summary(self):

View File

@@ -81,6 +81,7 @@ FLAVORS = {
class MochitestRunner(MozbuildObject): class MochitestRunner(MozbuildObject):
"""Easily run mochitests. """Easily run mochitests.
This currently contains just the basics for running mochitests. We may want This currently contains just the basics for running mochitests. We may want
@@ -91,8 +92,12 @@ class MochitestRunner(MozbuildObject):
import mozinfo import mozinfo
appname = 'webapprt-stub' + mozinfo.info.get('bin_suffix', '') appname = 'webapprt-stub' + mozinfo.info.get('bin_suffix', '')
if sys.platform.startswith('darwin'): if sys.platform.startswith('darwin'):
appname = os.path.join(self.distdir, self.substs['MOZ_MACBUNDLE_NAME'], appname = os.path.join(
'Contents', 'Resources', appname) self.distdir,
self.substs['MOZ_MACBUNDLE_NAME'],
'Contents',
'Resources',
appname)
else: else:
appname = os.path.join(self.distdir, 'bin', appname) appname = os.path.join(self.distdir, 'bin', appname)
return appname return appname
@@ -106,12 +111,24 @@ class MochitestRunner(MozbuildObject):
sys.path.append(build_path) sys.path.append(build_path)
self.tests_dir = os.path.join(self.topobjdir, '_tests') self.tests_dir = os.path.join(self.topobjdir, '_tests')
self.mochitest_dir = os.path.join(self.tests_dir, 'testing', 'mochitest') self.mochitest_dir = os.path.join(
self.tests_dir,
'testing',
'mochitest')
self.bin_dir = os.path.join(self.topobjdir, 'dist', 'bin') self.bin_dir = os.path.join(self.topobjdir, 'dist', 'bin')
def run_b2g_test(self, test_paths=None, b2g_home=None, xre_path=None, def run_b2g_test(
total_chunks=None, this_chunk=None, no_window=None, self,
repeat=0, run_until_failure=False, chrome=False, **kwargs): test_paths=None,
b2g_home=None,
xre_path=None,
total_chunks=None,
this_chunk=None,
no_window=None,
repeat=0,
run_until_failure=False,
chrome=False,
**kwargs):
"""Runs a b2g mochitest. """Runs a b2g mochitest.
test_paths is an enumerable of paths to tests. It can be a relative path test_paths is an enumerable of paths to tests. It can be a relative path
@@ -137,7 +154,7 @@ class MochitestRunner(MozbuildObject):
path = os.path.join(self.mochitest_dir, 'runtestsb2g.py') path = os.path.join(self.mochitest_dir, 'runtestsb2g.py')
with open(path, 'r') as fh: with open(path, 'r') as fh:
imp.load_module('mochitest', fh, path, imp.load_module('mochitest', fh, path,
('.py', 'r', imp.PY_SOURCE)) ('.py', 'r', imp.PY_SOURCE))
import mochitest import mochitest
from mochitest_options import B2GOptions from mochitest_options import B2GOptions
@@ -147,11 +164,19 @@ class MochitestRunner(MozbuildObject):
if test_path: if test_path:
if chrome: if chrome:
test_root_file = mozpack.path.join(self.mochitest_dir, 'chrome', test_path) test_root_file = mozpack.path.join(
self.mochitest_dir,
'chrome',
test_path)
else: else:
test_root_file = mozpack.path.join(self.mochitest_dir, 'tests', test_path) test_root_file = mozpack.path.join(
self.mochitest_dir,
'tests',
test_path)
if not os.path.exists(test_root_file): if not os.path.exists(test_root_file):
print('Specified test path does not exist: %s' % test_root_file) print(
'Specified test path does not exist: %s' %
test_root_file)
return 1 return 1
options.testPath = test_path options.testPath = test_path
@@ -163,7 +188,9 @@ class MochitestRunner(MozbuildObject):
options.repeat = repeat options.repeat = repeat
options.runUntilFailure = run_until_failure options.runUntilFailure = run_until_failure
options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols') options.symbolsPath = os.path.join(
self.distdir,
'crashreporter-symbols')
options.consoleLevel = 'INFO' options.consoleLevel = 'INFO'
if conditions.is_b2g_desktop(self): if conditions.is_b2g_desktop(self):
@@ -190,15 +217,46 @@ class MochitestRunner(MozbuildObject):
options.chrome = chrome options.chrome = chrome
return mochitest.run_remote_mochitests(parser, options) return mochitest.run_remote_mochitests(parser, options)
def run_desktop_test(self, context, suite=None, test_paths=None, debugger=None, def run_desktop_test(
debugger_args=None, slowscript=False, screenshot_on_fail = False, shuffle=False, closure_behaviour='auto', self,
rerun_failures=False, no_autorun=False, repeat=0, run_until_failure=False, context,
slow=False, chunk_by_dir=0, total_chunks=None, this_chunk=None, extraPrefs=[], suite=None,
jsdebugger=False, debug_on_failure=False, start_at=None, end_at=None, test_paths=None,
e10s=False, strict_content_sandbox=False, nested_oop=False, dmd=False, dump_output_directory=None, debugger=None,
dump_about_memory_after_test=False, dump_dmd_after_test=False, debugger_args=None,
install_extension=None, quiet=False, environment=[], app_override=None, bisectChunk=None, runByDir=False, slowscript=False,
useTestMediaDevices=False, timeout=None, **kwargs): screenshot_on_fail=False,
shuffle=False,
closure_behaviour='auto',
rerun_failures=False,
no_autorun=False,
repeat=0,
run_until_failure=False,
slow=False,
chunk_by_dir=0,
total_chunks=None,
this_chunk=None,
extraPrefs=[],
jsdebugger=False,
debug_on_failure=False,
start_at=None,
end_at=None,
e10s=False,
strict_content_sandbox=False,
nested_oop=False,
dmd=False,
dump_output_directory=None,
dump_about_memory_after_test=False,
dump_dmd_after_test=False,
install_extension=None,
quiet=False,
environment=[],
app_override=None,
bisectChunk=None,
runByDir=False,
useTestMediaDevices=False,
timeout=None,
**kwargs):
"""Runs a mochitest. """Runs a mochitest.
test_paths are path to tests. They can be a relative path from the test_paths are path to tests. They can be a relative path from the
@@ -227,9 +285,12 @@ class MochitestRunner(MozbuildObject):
# Make absolute paths relative before calling os.chdir() below. # Make absolute paths relative before calling os.chdir() below.
if test_paths: if test_paths:
test_paths = [self._wrap_path_argument(p).relpath() if os.path.isabs(p) else p for p in test_paths] test_paths = [self._wrap_path_argument(
p).relpath() if os.path.isabs(p) else p for p in test_paths]
failure_file_path = os.path.join(self.statedir, 'mochitest_failures.json') failure_file_path = os.path.join(
self.statedir,
'mochitest_failures.json')
if rerun_failures and not os.path.exists(failure_file_path): if rerun_failures and not os.path.exists(failure_file_path):
print('No failure file present. Did you run mochitests before?') print('No failure file present. Did you run mochitests before?')
@@ -241,7 +302,7 @@ class MochitestRunner(MozbuildObject):
path = os.path.join(self.mochitest_dir, 'runtests.py') path = os.path.join(self.mochitest_dir, 'runtests.py')
with open(path, 'r') as fh: with open(path, 'r') as fh:
imp.load_module('mochitest', fh, path, imp.load_module('mochitest', fh, path,
('.py', 'r', imp.PY_SOURCE)) ('.py', 'r', imp.PY_SOURCE))
import mochitest import mochitest
from manifestparser import TestManifest from manifestparser import TestManifest
@@ -253,7 +314,7 @@ class MochitestRunner(MozbuildObject):
# Automation installs its own stream handler to stdout. Since we want # Automation installs its own stream handler to stdout. Since we want
# all logging to go through us, we just remove their handler. # all logging to go through us, we just remove their handler.
remove_handlers = [l for l in logging.getLogger().handlers remove_handlers = [l for l in logging.getLogger().handlers
if isinstance(l, logging.StreamHandler)] if isinstance(l, logging.StreamHandler)]
for handler in remove_handlers: for handler in remove_handlers:
logging.getLogger().removeHandler(handler) logging.getLogger().removeHandler(handler)
@@ -308,7 +369,9 @@ class MochitestRunner(MozbuildObject):
options.runSlower = slow options.runSlower = slow
options.testingModulesDir = os.path.join(self.tests_dir, 'modules') options.testingModulesDir = os.path.join(self.tests_dir, 'modules')
options.extraProfileFiles.append(os.path.join(self.distdir, 'plugins')) options.extraProfileFiles.append(os.path.join(self.distdir, 'plugins'))
options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols') options.symbolsPath = os.path.join(
self.distdir,
'crashreporter-symbols')
options.chunkByDir = chunk_by_dir options.chunkByDir = chunk_by_dir
options.totalChunks = total_chunks options.totalChunks = total_chunks
options.thisChunk = this_chunk options.thisChunk = this_chunk
@@ -329,11 +392,14 @@ class MochitestRunner(MozbuildObject):
options.runByDir = runByDir options.runByDir = runByDir
options.useTestMediaDevices = useTestMediaDevices options.useTestMediaDevices = useTestMediaDevices
if timeout: if timeout:
options.timeout = int(timeout) options.timeout = int(timeout)
options.failureFile = failure_file_path options.failureFile = failure_file_path
if install_extension != None: if install_extension is not None:
options.extensionsToInstall = [os.path.join(self.topsrcdir,install_extension)] options.extensionsToInstall = [
os.path.join(
self.topsrcdir,
install_extension)]
for k, v in kwargs.iteritems(): for k, v in kwargs.iteritems():
setattr(options, k, v) setattr(options, k, v)
@@ -341,18 +407,22 @@ class MochitestRunner(MozbuildObject):
if test_paths: if test_paths:
resolver = self._spawn(TestResolver) resolver = self._spawn(TestResolver)
tests = list(resolver.resolve_tests(paths=test_paths, flavor=flavor)) tests = list(
resolver.resolve_tests(
paths=test_paths,
flavor=flavor))
if not tests: if not tests:
print('No tests could be found in the path specified. Please ' print('No tests could be found in the path specified. Please '
'specify a path that is a test file or is a directory ' 'specify a path that is a test file or is a directory '
'containing tests.') 'containing tests.')
return 1 return 1
manifest = TestManifest() manifest = TestManifest()
manifest.tests.extend(tests) manifest.tests.extend(tests)
if len(tests) == 1 and closure_behaviour == 'auto' and suite == 'plain': if len(
tests) == 1 and closure_behaviour == 'auto' and suite == 'plain':
options.closeWhenDone = False options.closeWhenDone = False
options.manifestFile = manifest options.manifestFile = manifest
@@ -364,7 +434,7 @@ class MochitestRunner(MozbuildObject):
options.debugger = debugger options.debugger = debugger
if debugger_args: if debugger_args:
if options.debugger == None: if options.debugger is None:
print("--debugger-args passed, but no debugger specified.") print("--debugger-args passed, but no debugger specified.")
return 1 return 1
options.debuggerArgs = debugger_args options.debuggerArgs = debugger_args
@@ -375,14 +445,22 @@ class MochitestRunner(MozbuildObject):
elif app_override: elif app_override:
options.app = app_override options.app = app_override
if options.gmp_path is None: if options.gmp_path is None:
# Need to fix the location of gmp_fake which might not be shipped in the binary # Need to fix the location of gmp_fake which might not be
# shipped in the binary
bin_path = self.get_binary_path() bin_path = self.get_binary_path()
options.gmp_path = os.path.join(os.path.dirname(bin_path), 'gmp-fake', '1.0') options.gmp_path = os.path.join(
os.path.dirname(bin_path),
'gmp-fake',
'1.0')
options.gmp_path += os.pathsep options.gmp_path += os.pathsep
options.gmp_path += os.path.join(os.path.dirname(bin_path), 'gmp-clearkey', '0.1') options.gmp_path += os.path.join(
os.path.dirname(bin_path),
'gmp-clearkey',
'0.1')
logger_options = {
logger_options = {key: value for key, value in vars(options).iteritems() if key.startswith('log')} key: value for key,
value in vars(options).iteritems() if key.startswith('log')}
runner = mochitest.Mochitest(logger_options) runner = mochitest.Mochitest(logger_options)
options = opts.verifyOptions(options, runner) options = opts.verifyOptions(options, runner)
@@ -414,12 +492,17 @@ def MochitestCommand(func):
# (modified) function. Here, we chain decorators onto the passed in # (modified) function. Here, we chain decorators onto the passed in
# function. # function.
debugger = CommandArgument('--debugger', '-d', metavar='DEBUGGER', debugger = CommandArgument(
'--debugger',
'-d',
metavar='DEBUGGER',
help='Debugger binary to run test in. Program name or path.') help='Debugger binary to run test in. Program name or path.')
func = debugger(func) func = debugger(func)
debugger_args = CommandArgument('--debugger-args', debugger_args = CommandArgument(
metavar='DEBUGGER_ARGS', help='Arguments to pass to the debugger.') '--debugger-args',
metavar='DEBUGGER_ARGS',
help='Arguments to pass to the debugger.')
func = debugger_args(func) func = debugger_args(func)
# Bug 933807 introduced JS_DISABLE_SLOW_SCRIPT_SIGNALS to avoid clever # Bug 933807 introduced JS_DISABLE_SLOW_SCRIPT_SIGNALS to avoid clever
@@ -427,219 +510,300 @@ def MochitestCommand(func):
# code. If we don't pass this, the user will need to periodically type # code. If we don't pass this, the user will need to periodically type
# "continue" to (safely) resume execution. There are ways to implement # "continue" to (safely) resume execution. There are ways to implement
# automatic resuming; see the bug. # automatic resuming; see the bug.
slowscript = CommandArgument('--slowscript', action='store_true', slowscript = CommandArgument(
'--slowscript',
action='store_true',
help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code') help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code')
func = slowscript(func) func = slowscript(func)
screenshot_on_fail = CommandArgument('--screenshot-on-fail', action='store_true', screenshot_on_fail = CommandArgument(
'--screenshot-on-fail',
action='store_true',
help='Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots.') help='Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots.')
func = screenshot_on_fail(func) func = screenshot_on_fail(func)
shuffle = CommandArgument('--shuffle', action='store_true', shuffle = CommandArgument('--shuffle', action='store_true',
help='Shuffle execution order.') help='Shuffle execution order.')
func = shuffle(func) func = shuffle(func)
keep_open = CommandArgument('--keep-open', action='store_const', keep_open = CommandArgument(
dest='closure_behaviour', const='open', default='auto', '--keep-open',
action='store_const',
dest='closure_behaviour',
const='open',
default='auto',
help='Always keep the browser open after tests complete.') help='Always keep the browser open after tests complete.')
func = keep_open(func) func = keep_open(func)
autoclose = CommandArgument('--auto-close', action='store_const', autoclose = CommandArgument(
dest='closure_behaviour', const='close', default='auto', '--auto-close',
action='store_const',
dest='closure_behaviour',
const='close',
default='auto',
help='Always close the browser after tests complete.') help='Always close the browser after tests complete.')
func = autoclose(func) func = autoclose(func)
rerun = CommandArgument('--rerun-failures', action='store_true', rerun = CommandArgument(
'--rerun-failures',
action='store_true',
help='Run only the tests that failed during the last test run.') help='Run only the tests that failed during the last test run.')
func = rerun(func) func = rerun(func)
autorun = CommandArgument('--no-autorun', action='store_true', autorun = CommandArgument(
'--no-autorun',
action='store_true',
help='Do not starting running tests automatically.') help='Do not starting running tests automatically.')
func = autorun(func) func = autorun(func)
repeat = CommandArgument('--repeat', type=int, default=0, repeat = CommandArgument('--repeat', type=int, default=0,
help='Repeat the test the given number of times.') help='Repeat the test the given number of times.')
func = repeat(func) func = repeat(func)
runUntilFailure = CommandArgument("--run-until-failure", action='store_true', runUntilFailure = CommandArgument(
help='Run tests repeatedly and stops on the first time a test fails. ' \ "--run-until-failure",
'Default cap is 30 runs, which can be overwritten ' \ action='store_true',
'with the --repeat parameter.') help='Run tests repeatedly and stops on the first time a test fails. '
'Default cap is 30 runs, which can be overwritten '
'with the --repeat parameter.')
func = runUntilFailure(func) func = runUntilFailure(func)
slow = CommandArgument('--slow', action='store_true', slow = CommandArgument('--slow', action='store_true',
help='Delay execution between tests.') help='Delay execution between tests.')
func = slow(func) func = slow(func)
end_at = CommandArgument('--end-at', type=str, end_at = CommandArgument(
'--end-at',
type=str,
help='Stop running the test sequence at this test.') help='Stop running the test sequence at this test.')
func = end_at(func) func = end_at(func)
start_at = CommandArgument('--start-at', type=str, start_at = CommandArgument(
'--start-at',
type=str,
help='Start running the test sequence at this test.') help='Start running the test sequence at this test.')
func = start_at(func) func = start_at(func)
chunk_dir = CommandArgument('--chunk-by-dir', type=int, chunk_dir = CommandArgument(
'--chunk-by-dir',
type=int,
help='Group tests together in chunks by this many top directories.') help='Group tests together in chunks by this many top directories.')
func = chunk_dir(func) func = chunk_dir(func)
chunk_total = CommandArgument('--total-chunks', type=int, chunk_total = CommandArgument(
'--total-chunks',
type=int,
help='Total number of chunks to split tests into.') help='Total number of chunks to split tests into.')
func = chunk_total(func) func = chunk_total(func)
this_chunk = CommandArgument('--this-chunk', type=int, this_chunk = CommandArgument(
'--this-chunk',
type=int,
help='If running tests by chunks, the number of the chunk to run.') help='If running tests by chunks, the number of the chunk to run.')
func = this_chunk(func) func = this_chunk(func)
debug_on_failure = CommandArgument('--debug-on-failure', action='store_true', debug_on_failure = CommandArgument(
help='Breaks execution and enters the JS debugger on a test failure. ' \ '--debug-on-failure',
'Should be used together with --jsdebugger.') action='store_true',
help='Breaks execution and enters the JS debugger on a test failure. '
'Should be used together with --jsdebugger.')
func = debug_on_failure(func) func = debug_on_failure(func)
setpref = CommandArgument('--setpref', default=[], action='append', setpref = CommandArgument('--setpref', default=[], action='append',
metavar='PREF=VALUE', dest='extraPrefs', metavar='PREF=VALUE', dest='extraPrefs',
help='defines an extra user preference') help='defines an extra user preference')
func = setpref(func) func = setpref(func)
jsdebugger = CommandArgument('--jsdebugger', action='store_true', jsdebugger = CommandArgument(
'--jsdebugger',
action='store_true',
help='Start the browser JS debugger before running the test. Implies --no-autorun.') help='Start the browser JS debugger before running the test. Implies --no-autorun.')
func = jsdebugger(func) func = jsdebugger(func)
e10s = CommandArgument('--e10s', action='store_true', e10s = CommandArgument(
'--e10s',
action='store_true',
help='Run tests with electrolysis preferences and test filtering enabled.') help='Run tests with electrolysis preferences and test filtering enabled.')
func = e10s(func) func = e10s(func)
strict_content_sandbox = CommandArgument('--strict-content-sandbox', action='store_true', strict_content_sandbox = CommandArgument(
'--strict-content-sandbox',
action='store_true',
help='Run tests with a more strict content sandbox (Windows only).') help='Run tests with a more strict content sandbox (Windows only).')
func = strict_content_sandbox(func) func = strict_content_sandbox(func)
this_chunk = CommandArgument('--nested_oop', action='store_true', this_chunk = CommandArgument(
'--nested_oop',
action='store_true',
help='Run tests with nested oop preferences and test filtering enabled.') help='Run tests with nested oop preferences and test filtering enabled.')
func = this_chunk(func) func = this_chunk(func)
dmd = CommandArgument('--dmd', action='store_true', dmd = CommandArgument('--dmd', action='store_true',
help='Run tests with DMD active.') help='Run tests with DMD active.')
func = dmd(func) func = dmd(func)
dumpAboutMemory = CommandArgument('--dump-about-memory-after-test', action='store_true', dumpAboutMemory = CommandArgument(
'--dump-about-memory-after-test',
action='store_true',
help='Dump an about:memory log after every test.') help='Dump an about:memory log after every test.')
func = dumpAboutMemory(func) func = dumpAboutMemory(func)
dumpDMD = CommandArgument('--dump-dmd-after-test', action='store_true', dumpDMD = CommandArgument('--dump-dmd-after-test', action='store_true',
help='Dump a DMD log after every test.') help='Dump a DMD log after every test.')
func = dumpDMD(func) func = dumpDMD(func)
dumpOutputDirectory = CommandArgument('--dump-output-directory', action='store', dumpOutputDirectory = CommandArgument(
'--dump-output-directory',
action='store',
help='Specifies the directory in which to place dumped memory reports.') help='Specifies the directory in which to place dumped memory reports.')
func = dumpOutputDirectory(func) func = dumpOutputDirectory(func)
path = CommandArgument('test_paths', default=None, nargs='*', path = CommandArgument(
'test_paths',
default=None,
nargs='*',
metavar='TEST', metavar='TEST',
help='Test to run. Can be specified as a single file, a ' \ help='Test to run. Can be specified as a single file, a '
'directory, or omitted. If omitted, the entire test suite is ' \ 'directory, or omitted. If omitted, the entire test suite is '
'executed.') 'executed.')
func = path(func) func = path(func)
install_extension = CommandArgument('--install-extension', install_extension = CommandArgument(
help='Install given extension before running selected tests. ' \ '--install-extension',
'Parameter is a path to xpi file.') help='Install given extension before running selected tests. '
'Parameter is a path to xpi file.')
func = install_extension(func) func = install_extension(func)
quiet = CommandArgument('--quiet', default=False, action='store_true', quiet = CommandArgument(
'--quiet',
default=False,
action='store_true',
help='Do not print test log lines unless a failure occurs.') help='Do not print test log lines unless a failure occurs.')
func = quiet(func) func = quiet(func)
setenv = CommandArgument('--setenv', default=[], action='append', setenv = CommandArgument(
metavar='NAME=VALUE', dest='environment', '--setenv',
help="Sets the given variable in the application's environment") default=[],
action='append',
metavar='NAME=VALUE',
dest='environment',
help="Sets the given variable in the application's environment")
func = setenv(func) func = setenv(func)
runbydir = CommandArgument('--run-by-dir', default=False, runbydir = CommandArgument(
action='store_true', '--run-by-dir',
dest='runByDir', default=False,
action='store_true',
dest='runByDir',
help='Run each directory in a single browser instance with a fresh profile.') help='Run each directory in a single browser instance with a fresh profile.')
func = runbydir(func) func = runbydir(func)
bisect_chunk = CommandArgument('--bisect-chunk', type=str, bisect_chunk = CommandArgument(
dest='bisectChunk', '--bisect-chunk',
type=str,
dest='bisectChunk',
help='Specify the failing test name to find the previous tests that may be causing the failure.') help='Specify the failing test name to find the previous tests that may be causing the failure.')
func = bisect_chunk(func) func = bisect_chunk(func)
test_media = CommandArgument('--use-test-media-devices', default=False, test_media = CommandArgument(
action='store_true', '--use-test-media-devices',
dest='useTestMediaDevices', default=False,
action='store_true',
dest='useTestMediaDevices',
help='Use test media device drivers for media testing.') help='Use test media device drivers for media testing.')
func = test_media(func) func = test_media(func)
app_override = CommandArgument('--app-override', default=None, action='store', app_override = CommandArgument(
help="Override the default binary used to run tests with the path you provide, e.g. " \ '--app-override',
" --app-override /usr/bin/firefox . " \ default=None,
"If you have run ./mach package beforehand, you can specify 'dist' to " \ action='store',
"run tests against the distribution bundle's binary."); help="Override the default binary used to run tests with the path you provide, e.g. "
" --app-override /usr/bin/firefox . "
"If you have run ./mach package beforehand, you can specify 'dist' to "
"run tests against the distribution bundle's binary.")
func = app_override(func) func = app_override(func)
timeout = CommandArgument('--timeout', default=None, timeout = CommandArgument(
help='The per-test timeout time in seconds (default: 60 seconds)'); '--timeout',
default=None,
help='The per-test timeout time in seconds (default: 60 seconds)')
func = timeout(func) func = timeout(func)
return func return func
def B2GCommand(func): def B2GCommand(func):
"""Decorator that adds shared command arguments to b2g mochitest commands.""" """Decorator that adds shared command arguments to b2g mochitest commands."""
busybox = CommandArgument('--busybox', default=None, busybox = CommandArgument(
'--busybox',
default=None,
help='Path to busybox binary to install on device') help='Path to busybox binary to install on device')
func = busybox(func) func = busybox(func)
logdir = CommandArgument('--logdir', default=None, logdir = CommandArgument('--logdir', default=None,
help='directory to store log files') help='directory to store log files')
func = logdir(func) func = logdir(func)
profile = CommandArgument('--profile', default=None, profile = CommandArgument('--profile', default=None,
help='for desktop testing, the path to the \ help='for desktop testing, the path to the \
gaia profile to use') gaia profile to use')
func = profile(func) func = profile(func)
geckopath = CommandArgument('--gecko-path', default=None, geckopath = CommandArgument('--gecko-path', default=None,
help='the path to a gecko distribution that should \ help='the path to a gecko distribution that should \
be installed on the emulator prior to test') be installed on the emulator prior to test')
func = geckopath(func) func = geckopath(func)
nowindow = CommandArgument('--no-window', action='store_true', default=False, nowindow = CommandArgument(
'--no-window',
action='store_true',
default=False,
help='Pass --no-window to the emulator') help='Pass --no-window to the emulator')
func = nowindow(func) func = nowindow(func)
sdcard = CommandArgument('--sdcard', default="10MB", sdcard = CommandArgument('--sdcard', default="10MB",
help='Define size of sdcard: 1MB, 50MB...etc') help='Define size of sdcard: 1MB, 50MB...etc')
func = sdcard(func) func = sdcard(func)
marionette = CommandArgument('--marionette', default=None, marionette = CommandArgument(
'--marionette',
default=None,
help='host:port to use when connecting to Marionette') help='host:port to use when connecting to Marionette')
func = marionette(func) func = marionette(func)
chunk_total = CommandArgument('--total-chunks', type=int, chunk_total = CommandArgument(
'--total-chunks',
type=int,
help='Total number of chunks to split tests into.') help='Total number of chunks to split tests into.')
func = chunk_total(func) func = chunk_total(func)
this_chunk = CommandArgument('--this-chunk', type=int, this_chunk = CommandArgument(
'--this-chunk',
type=int,
help='If running tests by chunks, the number of the chunk to run.') help='If running tests by chunks, the number of the chunk to run.')
func = this_chunk(func) func = this_chunk(func)
path = CommandArgument('test_paths', default=None, nargs='*', path = CommandArgument(
'test_paths',
default=None,
nargs='*',
metavar='TEST', metavar='TEST',
help='Test to run. Can be specified as a single file, a ' \ help='Test to run. Can be specified as a single file, a '
'directory, or omitted. If omitted, the entire test suite is ' \ 'directory, or omitted. If omitted, the entire test suite is '
'executed.') 'executed.')
func = path(func) func = path(func)
repeat = CommandArgument('--repeat', type=int, default=0, repeat = CommandArgument('--repeat', type=int, default=0,
help='Repeat the test the given number of times.') help='Repeat the test the given number of times.')
func = repeat(func) func = repeat(func)
runUntilFailure = CommandArgument("--run-until-failure", action='store_true', runUntilFailure = CommandArgument(
help='Run tests repeatedly and stops on the first time a test fails. ' \ "--run-until-failure",
'Default cap is 30 runs, which can be overwritten ' \ action='store_true',
'with the --repeat parameter.') help='Run tests repeatedly and stops on the first time a test fails. '
'Default cap is 30 runs, which can be overwritten '
'with the --repeat parameter.')
func = runUntilFailure(func) func = runUntilFailure(func)
return func return func
@@ -648,34 +812,48 @@ def B2GCommand(func):
_st_parser = argparse.ArgumentParser() _st_parser = argparse.ArgumentParser()
structured.commandline.add_logging_group(_st_parser) structured.commandline.add_logging_group(_st_parser)
@CommandProvider @CommandProvider
class MachCommands(MachCommandBase): class MachCommands(MachCommandBase):
@Command('mochitest-plain', category='testing',
conditions=[conditions.is_firefox_or_mulet], @Command(
'mochitest-plain',
category='testing',
conditions=[
conditions.is_firefox_or_mulet],
description='Run a plain mochitest (integration test, plain web page).', description='Run a plain mochitest (integration test, plain web page).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
def run_mochitest_plain(self, test_paths, **kwargs): def run_mochitest_plain(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'plain', **kwargs) return self.run_mochitest(test_paths, 'plain', **kwargs)
@Command('mochitest-chrome', category='testing', @Command(
conditions=[conditions.is_firefox], 'mochitest-chrome',
category='testing',
conditions=[
conditions.is_firefox],
description='Run a chrome mochitest (integration test with some XUL).', description='Run a chrome mochitest (integration test with some XUL).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
def run_mochitest_chrome(self, test_paths, **kwargs): def run_mochitest_chrome(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'chrome', **kwargs) return self.run_mochitest(test_paths, 'chrome', **kwargs)
@Command('mochitest-browser', category='testing', @Command(
conditions=[conditions.is_firefox], 'mochitest-browser',
category='testing',
conditions=[
conditions.is_firefox],
description='Run a mochitest with browser chrome (integration test with a standard browser).', description='Run a mochitest with browser chrome (integration test with a standard browser).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
def run_mochitest_browser(self, test_paths, **kwargs): def run_mochitest_browser(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'browser', **kwargs) return self.run_mochitest(test_paths, 'browser', **kwargs)
@Command('mochitest-devtools', category='testing', @Command(
conditions=[conditions.is_firefox], 'mochitest-devtools',
category='testing',
conditions=[
conditions.is_firefox],
description='Run a devtools mochitest with browser chrome (integration test with a standard browser with the devtools frame).', description='Run a devtools mochitest with browser chrome (integration test with a standard browser with the devtools frame).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
@@ -683,21 +861,24 @@ class MachCommands(MachCommandBase):
return self.run_mochitest(test_paths, 'devtools', **kwargs) return self.run_mochitest(test_paths, 'devtools', **kwargs)
@Command('jetpack-package', category='testing', @Command('jetpack-package', category='testing',
conditions=[conditions.is_firefox], conditions=[conditions.is_firefox],
description='Run a jetpack package test.') description='Run a jetpack package test.')
@MochitestCommand @MochitestCommand
def run_mochitest_jetpack_package(self, test_paths, **kwargs): def run_mochitest_jetpack_package(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'jetpack-package', **kwargs) return self.run_mochitest(test_paths, 'jetpack-package', **kwargs)
@Command('jetpack-addon', category='testing', @Command('jetpack-addon', category='testing',
conditions=[conditions.is_firefox], conditions=[conditions.is_firefox],
description='Run a jetpack addon test.') description='Run a jetpack addon test.')
@MochitestCommand @MochitestCommand
def run_mochitest_jetpack_addon(self, test_paths, **kwargs): def run_mochitest_jetpack_addon(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'jetpack-addon', **kwargs) return self.run_mochitest(test_paths, 'jetpack-addon', **kwargs)
@Command('mochitest-metro', category='testing', @Command(
conditions=[conditions.is_firefox], 'mochitest-metro',
category='testing',
conditions=[
conditions.is_firefox],
description='Run a mochitest with metro browser chrome (tests for Windows touch interface).', description='Run a mochitest with metro browser chrome (tests for Windows touch interface).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
@@ -705,23 +886,29 @@ class MachCommands(MachCommandBase):
return self.run_mochitest(test_paths, 'metro', **kwargs) return self.run_mochitest(test_paths, 'metro', **kwargs)
@Command('mochitest-a11y', category='testing', @Command('mochitest-a11y', category='testing',
conditions=[conditions.is_firefox], conditions=[conditions.is_firefox],
description='Run an a11y mochitest (accessibility tests).', description='Run an a11y mochitest (accessibility tests).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
def run_mochitest_a11y(self, test_paths, **kwargs): def run_mochitest_a11y(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'a11y', **kwargs) return self.run_mochitest(test_paths, 'a11y', **kwargs)
@Command('webapprt-test-chrome', category='testing', @Command(
conditions=[conditions.is_firefox], 'webapprt-test-chrome',
category='testing',
conditions=[
conditions.is_firefox],
description='Run a webapprt chrome mochitest (Web App Runtime with the browser chrome).', description='Run a webapprt chrome mochitest (Web App Runtime with the browser chrome).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
def run_mochitest_webapprt_chrome(self, test_paths, **kwargs): def run_mochitest_webapprt_chrome(self, test_paths, **kwargs):
return self.run_mochitest(test_paths, 'webapprt-chrome', **kwargs) return self.run_mochitest(test_paths, 'webapprt-chrome', **kwargs)
@Command('webapprt-test-content', category='testing', @Command(
conditions=[conditions.is_firefox], 'webapprt-test-content',
category='testing',
conditions=[
conditions.is_firefox],
description='Run a webapprt content mochitest (Content rendering of the Web App Runtime).', description='Run a webapprt content mochitest (Content rendering of the Web App Runtime).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
@@ -729,14 +916,14 @@ class MachCommands(MachCommandBase):
return self.run_mochitest(test_paths, 'webapprt-content', **kwargs) return self.run_mochitest(test_paths, 'webapprt-content', **kwargs)
@Command('mochitest', category='testing', @Command('mochitest', category='testing',
conditions=[conditions.is_firefox], conditions=[conditions.is_firefox],
description='Run any flavor of mochitest (integration test).', description='Run any flavor of mochitest (integration test).',
parser=_st_parser) parser=_st_parser)
@MochitestCommand @MochitestCommand
@CommandArgument('-f', '--flavor', choices=FLAVORS.keys(), @CommandArgument('-f', '--flavor', choices=FLAVORS.keys(),
help='Only run tests of this flavor.') help='Only run tests of this flavor.')
def run_mochitest_general(self, test_paths, flavor=None, test_objects=None, def run_mochitest_general(self, test_paths, flavor=None, test_objects=None,
**kwargs): **kwargs):
self._preruntest() self._preruntest()
from mozbuild.testing import TestResolver from mozbuild.testing import TestResolver
@@ -746,7 +933,7 @@ class MachCommands(MachCommandBase):
else: else:
resolver = self._spawn(TestResolver) resolver = self._spawn(TestResolver)
tests = list(resolver.resolve_tests(paths=test_paths, tests = list(resolver.resolve_tests(paths=test_paths,
cwd=self._mach_context.cwd)) cwd=self._mach_context.cwd))
# Our current approach is to group the tests by suite and then perform # Our current approach is to group the tests by suite and then perform
# an invocation for each suite. Ideally, this would be done # an invocation for each suite. Ideally, this would be done
@@ -773,8 +960,11 @@ class MachCommands(MachCommandBase):
mochitest = self._spawn(MochitestRunner) mochitest = self._spawn(MochitestRunner)
overall = None overall = None
for suite, tests in sorted(suites.items()): for suite, tests in sorted(suites.items()):
result = mochitest.run_desktop_test(self._mach_context, result = mochitest.run_desktop_test(
test_paths=[test['file_relpath'] for test in tests], suite=suite, self._mach_context,
test_paths=[
test['file_relpath'] for test in tests],
suite=suite,
**kwargs) **kwargs)
if result: if result:
overall = result overall = result
@@ -794,8 +984,11 @@ class MachCommands(MachCommandBase):
mochitest = self._spawn(MochitestRunner) mochitest = self._spawn(MochitestRunner)
return mochitest.run_desktop_test(self._mach_context, return mochitest.run_desktop_test(
test_paths=test_paths, suite=flavor, **kwargs) self._mach_context,
test_paths=test_paths,
suite=flavor,
**kwargs)
# TODO For now b2g commands will only work with the emulator, # TODO For now b2g commands will only work with the emulator,
@@ -810,27 +1003,39 @@ def is_emulator(cls):
@CommandProvider @CommandProvider
class B2GCommands(MachCommandBase): class B2GCommands(MachCommandBase):
"""So far these are only mochitest plain. They are """So far these are only mochitest plain. They are
implemented separately because their command lines implemented separately because their command lines
are completely different. are completely different.
""" """
def __init__(self, context): def __init__(self, context):
MachCommandBase.__init__(self, context) MachCommandBase.__init__(self, context)
for attr in ('b2g_home', 'xre_path', 'device_name', 'get_build_var'): for attr in ('b2g_home', 'xre_path', 'device_name', 'get_build_var'):
setattr(self, attr, getattr(context, attr, None)) setattr(self, attr, getattr(context, attr, None))
@Command('mochitest-remote', category='testing', @Command(
'mochitest-remote',
category='testing',
description='Run a remote mochitest (integration test for fennec/android).', description='Run a remote mochitest (integration test for fennec/android).',
conditions=[conditions.is_b2g, is_emulator]) conditions=[
conditions.is_b2g,
is_emulator])
@B2GCommand @B2GCommand
def run_mochitest_remote(self, test_paths, **kwargs): def run_mochitest_remote(self, test_paths, **kwargs):
if self.get_build_var: if self.get_build_var:
host_webapps_dir = os.path.join(self.get_build_var('TARGET_OUT_DATA'), host_webapps_dir = os.path.join(
'local', 'webapps') self.get_build_var('TARGET_OUT_DATA'),
if not os.path.isdir(os.path.join(host_webapps_dir, 'local',
'test-container.gaiamobile.org')): 'webapps')
print(ENG_BUILD_REQUIRED % ('mochitest-remote', host_webapps_dir)) if not os.path.isdir(
os.path.join(
host_webapps_dir,
'test-container.gaiamobile.org')):
print(
ENG_BUILD_REQUIRED %
('mochitest-remote', host_webapps_dir))
return 1 return 1
from mozbuild.controller.building import BuildDriver from mozbuild.controller.building import BuildDriver
@@ -847,22 +1052,29 @@ class B2GCommands(MachCommandBase):
driver.install_tests(remove=False) driver.install_tests(remove=False)
mochitest = self._spawn(MochitestRunner) mochitest = self._spawn(MochitestRunner)
return mochitest.run_b2g_test(b2g_home=self.b2g_home, return mochitest.run_b2g_test(
xre_path=self.xre_path, test_paths=test_paths, **kwargs) b2g_home=self.b2g_home,
xre_path=self.xre_path,
test_paths=test_paths,
**kwargs)
@Command('mochitest-chrome-remote', category='testing', @Command('mochitest-chrome-remote', category='testing',
description='Run a remote mochitest-chrome.', description='Run a remote mochitest-chrome.',
conditions=[conditions.is_b2g, is_emulator]) conditions=[conditions.is_b2g, is_emulator])
@B2GCommand @B2GCommand
def run_mochitest_chrome_remote(self, test_paths, **kwargs): def run_mochitest_chrome_remote(self, test_paths, **kwargs):
return self.run_mochitest_remote(test_paths, chrome=True, **kwargs) return self.run_mochitest_remote(test_paths, chrome=True, **kwargs)
@Command('mochitest-b2g-desktop', category='testing', @Command(
conditions=[conditions.is_b2g_desktop], 'mochitest-b2g-desktop',
category='testing',
conditions=[
conditions.is_b2g_desktop],
description='Run a b2g desktop mochitest (same as mochitest-plain but for b2g desktop).') description='Run a b2g desktop mochitest (same as mochitest-plain but for b2g desktop).')
@B2GCommand @B2GCommand
def run_mochitest_b2g_desktop(self, test_paths, **kwargs): def run_mochitest_b2g_desktop(self, test_paths, **kwargs):
kwargs['profile'] = kwargs.get('profile') or os.environ.get('GAIA_PROFILE') kwargs['profile'] = kwargs.get(
'profile') or os.environ.get('GAIA_PROFILE')
if not kwargs['profile'] or not os.path.isdir(kwargs['profile']): if not kwargs['profile'] or not os.path.isdir(kwargs['profile']):
print(GAIA_PROFILE_NOT_FOUND % 'mochitest-b2g-desktop') print(GAIA_PROFILE_NOT_FOUND % 'mochitest-b2g-desktop')
return 1 return 1
@@ -886,31 +1098,52 @@ class B2GCommands(MachCommandBase):
@CommandProvider @CommandProvider
class AndroidCommands(MachCommandBase): class AndroidCommands(MachCommandBase):
@Command('robocop', category='testing', @Command('robocop', category='testing',
conditions=[conditions.is_android], conditions=[conditions.is_android],
description='Run a Robocop test.') description='Run a Robocop test.')
@CommandArgument('test_path', default=None, nargs='?', @CommandArgument(
'test_path',
default=None,
nargs='?',
metavar='TEST', metavar='TEST',
help='Test to run. Can be specified as a Robocop test name (like "testLoad"), ' \ help='Test to run. Can be specified as a Robocop test name (like "testLoad"), '
'or omitted. If omitted, the entire test suite is executed.') 'or omitted. If omitted, the entire test suite is executed.')
def run_robocop(self, test_path): def run_robocop(self, test_path):
self.tests_dir = os.path.join(self.topobjdir, '_tests') self.tests_dir = os.path.join(self.topobjdir, '_tests')
self.mochitest_dir = os.path.join(self.tests_dir, 'testing', 'mochitest') self.mochitest_dir = os.path.join(
self.tests_dir,
'testing',
'mochitest')
import imp import imp
path = os.path.join(self.mochitest_dir, 'runtestsremote.py') path = os.path.join(self.mochitest_dir, 'runtestsremote.py')
with open(path, 'r') as fh: with open(path, 'r') as fh:
imp.load_module('runtestsremote', fh, path, imp.load_module('runtestsremote', fh, path,
('.py', 'r', imp.PY_SOURCE)) ('.py', 'r', imp.PY_SOURCE))
import runtestsremote import runtestsremote
args = [ args = [
'--xre-path=' + os.environ.get('MOZ_HOST_BIN'), '--xre-path=' +
os.environ.get('MOZ_HOST_BIN'),
'--dm_trans=adb', '--dm_trans=adb',
'--deviceIP=', '--deviceIP=',
'--console-level=INFO', '--console-level=INFO',
'--app=' + self.substs['ANDROID_PACKAGE_NAME'], '--app=' +
'--robocop-apk=' + os.path.join(self.topobjdir, 'build', 'mobile', 'robocop', 'robocop-debug.apk'), self.substs['ANDROID_PACKAGE_NAME'],
'--robocop-ini=' + os.path.join(self.topobjdir, 'build', 'mobile', 'robocop', 'robocop.ini'), '--robocop-apk=' +
os.path.join(
self.topobjdir,
'build',
'mobile',
'robocop',
'robocop-debug.apk'),
'--robocop-ini=' +
os.path.join(
self.topobjdir,
'build',
'mobile',
'robocop',
'robocop.ini'),
'--log-mach=-', '--log-mach=-',
] ]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -23,14 +23,15 @@ from mozprofile import Profile, Preferences
from mozlog import structured from mozlog import structured
import mozinfo import mozinfo
class B2GMochitest(MochitestUtilsMixin): class B2GMochitest(MochitestUtilsMixin):
marionette = None marionette = None
def __init__(self, marionette_args, def __init__(self, marionette_args,
logger_options, logger_options,
out_of_process=True, out_of_process=True,
profile_data_dir=None, profile_data_dir=None,
locations=os.path.join(here, 'server-locations.txt')): locations=os.path.join(here, 'server-locations.txt')):
super(B2GMochitest, self).__init__(logger_options) super(B2GMochitest, self).__init__(logger_options)
self.marionette_args = marionette_args self.marionette_args = marionette_args
self.out_of_process = out_of_process self.out_of_process = out_of_process
@@ -43,10 +44,14 @@ class B2GMochitest(MochitestUtilsMixin):
self.remote_chrome_test_dir = None self.remote_chrome_test_dir = None
if profile_data_dir: if profile_data_dir:
self.preferences = [os.path.join(profile_data_dir, f) self.preferences = [
for f in os.listdir(profile_data_dir) if f.startswith('pref')] os.path.join(
self.webapps = [os.path.join(profile_data_dir, f) profile_data_dir,
for f in os.listdir(profile_data_dir) if f.startswith('webapp')] f) for f in os.listdir(profile_data_dir) if f.startswith('pref')]
self.webapps = [
os.path.join(
profile_data_dir,
f) for f in os.listdir(profile_data_dir) if f.startswith('webapp')]
# mozinfo is populated by the parent class # mozinfo is populated by the parent class
if mozinfo.info['debug']: if mozinfo.info['debug']:
@@ -68,7 +73,12 @@ class B2GMochitest(MochitestUtilsMixin):
def buildTestPath(self, options, testsToFilter=None): def buildTestPath(self, options, testsToFilter=None):
if options.manifestFile != 'tests.json': if options.manifestFile != 'tests.json':
super(B2GMochitest, self).buildTestPath(options, testsToFilter, disabled=False) super(
B2GMochitest,
self).buildTestPath(
options,
testsToFilter,
disabled=False)
return self.buildTestURL(options) return self.buildTestURL(options)
def build_profile(self, options): def build_profile(self, options):
@@ -85,8 +95,11 @@ class B2GMochitest(MochitestUtilsMixin):
prefs[thispref[0]] = thispref[1] prefs[thispref[0]] = thispref[1]
# interpolate the preferences # interpolate the preferences
interpolation = { "server": "%s:%s" % (options.webServer, options.httpPort), interpolation = {
"OOP": "true" if self.out_of_process else "false" } "server": "%s:%s" %
(options.webServer,
options.httpPort),
"OOP": "true" if self.out_of_process else "false"}
prefs = json.loads(json.dumps(prefs) % interpolation) prefs = json.loads(json.dumps(prefs) % interpolation)
for pref in prefs: for pref in prefs:
prefs[pref] = Preferences.cast(prefs[pref]) prefs[pref] = Preferences.cast(prefs[pref])
@@ -138,7 +151,8 @@ class B2GMochitest(MochitestUtilsMixin):
if message['action'] == 'test_start': if message['action'] == 'test_start':
self.runner.last_test = message['test'] self.runner.last_test = message['test']
# The logging will be handled by on_output, so we set the stream to None # The logging will be handled by on_output, so we set the stream to
# None
process_args = {'processOutputLine': on_output, process_args = {'processOutputLine': on_output,
'stream': None} 'stream': None}
self.marionette_args['process_args'] = process_args self.marionette_args['process_args'] = process_args
@@ -150,23 +164,29 @@ class B2GMochitest(MochitestUtilsMixin):
self.remote_log = posixpath.join(self.app_ctx.remote_test_root, self.remote_log = posixpath.join(self.app_ctx.remote_test_root,
'log', 'mochitest.log') 'log', 'mochitest.log')
if not self.app_ctx.dm.dirExists(posixpath.dirname(self.remote_log)): if not self.app_ctx.dm.dirExists(
posixpath.dirname(
self.remote_log)):
self.app_ctx.dm.mkDirs(self.remote_log) self.app_ctx.dm.mkDirs(self.remote_log)
if options.chrome: if options.chrome:
# Update chrome manifest file in profile with correct path. # Update chrome manifest file in profile with correct path.
self.writeChromeManifest(options) self.writeChromeManifest(options)
self.leak_report_file = posixpath.join(self.app_ctx.remote_test_root, self.leak_report_file = posixpath.join(
'log', 'runtests_leaks.log') self.app_ctx.remote_test_root,
'log',
'runtests_leaks.log')
# We don't want to copy the host env onto the device, so pass in an # We don't want to copy the host env onto the device, so pass in an
# empty env. # empty env.
self.browserEnv = self.buildBrowserEnv(options, env={}) self.browserEnv = self.buildBrowserEnv(options, env={})
# B2G emulator debug tests still make external connections, so don't # B2G emulator debug tests still make external connections, so don't
# pass MOZ_DISABLE_NONLOCAL_CONNECTIONS to them for now (bug 1039019). # pass MOZ_DISABLE_NONLOCAL_CONNECTIONS to them for now (bug
if mozinfo.info['debug'] and 'MOZ_DISABLE_NONLOCAL_CONNECTIONS' in self.browserEnv: # 1039019).
if mozinfo.info[
'debug'] and 'MOZ_DISABLE_NONLOCAL_CONNECTIONS' in self.browserEnv:
del self.browserEnv['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] del self.browserEnv['MOZ_DISABLE_NONLOCAL_CONNECTIONS']
self.runner.env.update(self.browserEnv) self.runner.env.update(self.browserEnv)
@@ -176,7 +196,6 @@ class B2GMochitest(MochitestUtilsMixin):
self.test_script_args.append(options.wifi) self.test_script_args.append(options.wifi)
self.test_script_args.append(options.chrome) self.test_script_args.append(options.chrome)
self.runner.start(outputTimeout=timeout) self.runner.start(outputTimeout=timeout)
self.marionette.wait_for_port() self.marionette.wait_for_port()
@@ -185,7 +204,8 @@ class B2GMochitest(MochitestUtilsMixin):
# Disable offline status management (bug 777145), otherwise the network # Disable offline status management (bug 777145), otherwise the network
# will be 'offline' when the mochitests start. Presumably, the network # will be 'offline' when the mochitests start. Presumably, the network
# won't be offline on a real device, so we only do this for emulators. # won't be offline on a real device, so we only do this for
# emulators.
self.marionette.execute_script(""" self.marionette.execute_script("""
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
Services.io.manageOfflineStatus = false; Services.io.manageOfflineStatus = false;
@@ -198,16 +218,20 @@ class B2GMochitest(MochitestUtilsMixin):
local = super(B2GMochitest, self).getChromeTestDir(options) local = super(B2GMochitest, self).getChromeTestDir(options)
local = os.path.join(local, "chrome") local = os.path.join(local, "chrome")
remote = self.remote_chrome_test_dir remote = self.remote_chrome_test_dir
self.log.info("pushing %s to %s on device..." % (local, remote)) self.log.info(
"pushing %s to %s on device..." %
(local, remote))
self.app_ctx.dm.pushDir(local, remote) self.app_ctx.dm.pushDir(local, remote)
if os.path.isfile(self.test_script): if os.path.isfile(self.test_script):
with open(self.test_script, 'r') as script: with open(self.test_script, 'r') as script:
self.marionette.execute_script(script.read(), self.marionette.execute_script(
script_args=self.test_script_args) script.read(),
script_args=self.test_script_args)
else: else:
self.marionette.execute_script(self.test_script, self.marionette.execute_script(
script_args=self.test_script_args) self.test_script,
script_args=self.test_script_args)
status = self.runner.wait() status = self.runner.wait()
if status is None: if status is None:
@@ -215,16 +239,19 @@ class B2GMochitest(MochitestUtilsMixin):
status = 124 status = 124
local_leak_file = tempfile.NamedTemporaryFile() local_leak_file = tempfile.NamedTemporaryFile()
self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name) self.app_ctx.dm.getFile(
self.leak_report_file,
local_leak_file.name)
self.app_ctx.dm.removeFile(self.leak_report_file) self.app_ctx.dm.removeFile(self.leak_report_file)
processLeakLog(local_leak_file.name, options) processLeakLog(local_leak_file.name, options)
except KeyboardInterrupt: except KeyboardInterrupt:
self.log.info("runtests.py | Received keyboard interrupt.\n"); self.log.info("runtests.py | Received keyboard interrupt.\n")
status = -1 status = -1
except: except:
traceback.print_exc() traceback.print_exc()
self.log.error("Automation Error: Received unexpected exception while running application\n") self.log.error(
"Automation Error: Received unexpected exception while running application\n")
if hasattr(self, 'runner'): if hasattr(self, 'runner'):
self.runner.check_for_crashes() self.runner.check_for_crashes()
status = 1 status = 1
@@ -249,7 +276,9 @@ class B2GMochitest(MochitestUtilsMixin):
# is defined; the correct directory will be returned later, over- # is defined; the correct directory will be returned later, over-
# writing the dummy. # writing the dummy.
if hasattr(self, 'app_ctx'): if hasattr(self, 'app_ctx'):
self.remote_chrome_test_dir = posixpath.join(self.app_ctx.remote_test_root, 'chrome'); self.remote_chrome_test_dir = posixpath.join(
self.app_ctx.remote_test_root,
'chrome')
return self.remote_chrome_test_dir return self.remote_chrome_test_dir
return 'dummy-chrome-test-dir' return 'dummy-chrome-test-dir'
@@ -257,9 +286,20 @@ class B2GMochitest(MochitestUtilsMixin):
class B2GDeviceMochitest(B2GMochitest, Mochitest): class B2GDeviceMochitest(B2GMochitest, Mochitest):
remote_log = None remote_log = None
def __init__(self, marionette_args, logger_options, profile_data_dir, def __init__(
local_binary_dir, remote_test_root=None, remote_log_file=None): self,
B2GMochitest.__init__(self, marionette_args, logger_options, out_of_process=True, profile_data_dir=profile_data_dir) marionette_args,
logger_options,
profile_data_dir,
local_binary_dir,
remote_test_root=None,
remote_log_file=None):
B2GMochitest.__init__(
self,
marionette_args,
logger_options,
out_of_process=True,
profile_data_dir=profile_data_dir)
self.local_log = None self.local_log = None
self.local_binary_dir = local_binary_dir self.local_binary_dir = local_binary_dir
@@ -314,7 +354,12 @@ class B2GDeviceMochitest(B2GMochitest, Mochitest):
class B2GDesktopMochitest(B2GMochitest, Mochitest): class B2GDesktopMochitest(B2GMochitest, Mochitest):
def __init__(self, marionette_args, logger_options, profile_data_dir): def __init__(self, marionette_args, logger_options, profile_data_dir):
B2GMochitest.__init__(self, marionette_args, logger_options, out_of_process=False, profile_data_dir=profile_data_dir) B2GMochitest.__init__(
self,
marionette_args,
logger_options,
out_of_process=False,
profile_data_dir=profile_data_dir)
Mochitest.__init__(self, logger_options) Mochitest.__init__(self, logger_options)
self.certdbNew = True self.certdbNew = True
@@ -347,7 +392,10 @@ class B2GDesktopMochitest(B2GMochitest, Mochitest):
self.setup_common_options(options) self.setup_common_options(options)
# Copy the extensions to the B2G bundles dir. # Copy the extensions to the B2G bundles dir.
extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') extensionDir = os.path.join(
options.profilePath,
'extensions',
'staged')
bundlesDir = os.path.join(os.path.dirname(options.app), bundlesDir = os.path.join(os.path.dirname(options.app),
'distribution', 'bundles') 'distribution', 'bundles')
@@ -378,15 +426,19 @@ def run_remote_mochitests(parser, options):
marionette_args['port'] = int(port) marionette_args['port'] = int(port)
options = parser.verifyRemoteOptions(options) options = parser.verifyRemoteOptions(options)
if (options == None): if (options is None):
print "ERROR: Invalid options specified, use --help for a list of valid options" print "ERROR: Invalid options specified, use --help for a list of valid options"
sys.exit(1) sys.exit(1)
mochitest = B2GDeviceMochitest(marionette_args, options, options.profile_data_dir, mochitest = B2GDeviceMochitest(
options.xrePath, remote_log_file=options.remoteLogFile) marionette_args,
options,
options.profile_data_dir,
options.xrePath,
remote_log_file=options.remoteLogFile)
options = parser.verifyOptions(options, mochitest) options = parser.verifyOptions(options, mochitest)
if (options == None): if (options is None):
sys.exit(1) sys.exit(1)
retVal = 1 retVal = 1
@@ -407,6 +459,7 @@ def run_remote_mochitests(parser, options):
sys.exit(retVal) sys.exit(retVal)
def run_desktop_mochitests(parser, options): def run_desktop_mochitests(parser, options):
# create our Marionette instance # create our Marionette instance
marionette_args = {} marionette_args = {}
@@ -420,9 +473,12 @@ def run_desktop_mochitests(parser, options):
if os.path.isfile("%s-bin" % options.app): if os.path.isfile("%s-bin" % options.app):
options.app = "%s-bin" % options.app options.app = "%s-bin" % options.app
mochitest = B2GDesktopMochitest(marionette_args, options, options.profile_data_dir) mochitest = B2GDesktopMochitest(
marionette_args,
options,
options.profile_data_dir)
options = MochitestOptions.verifyOptions(parser, options, mochitest) options = MochitestOptions.verifyOptions(parser, options, mochitest)
if options == None: if options is None:
sys.exit(1) sys.exit(1)
if options.desktop and not options.profile: if options.desktop and not options.profile:
@@ -435,6 +491,7 @@ def run_desktop_mochitests(parser, options):
sys.exit(retVal) sys.exit(retVal)
def main(): def main():
parser = B2GOptions() parser = B2GOptions()
structured.commandline.add_logging_group(parser) structured.commandline.add_logging_group(parser)

View File

@@ -13,7 +13,10 @@ import sys
import tempfile import tempfile
import traceback import traceback
sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(__file__)))) sys.path.insert(
0, os.path.abspath(
os.path.realpath(
os.path.dirname(__file__))))
from automation import Automation from automation import Automation
from remoteautomation import RemoteAutomation, fennecLogcatFilters from remoteautomation import RemoteAutomation, fennecLogcatFilters
@@ -29,6 +32,7 @@ import moznetwork
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
class RemoteOptions(MochitestOptions): class RemoteOptions(MochitestOptions):
def __init__(self, automation, **kwargs): def __init__(self, automation, **kwargs):
@@ -36,84 +40,117 @@ class RemoteOptions(MochitestOptions):
self._automation = automation or Automation() self._automation = automation or Automation()
MochitestOptions.__init__(self) MochitestOptions.__init__(self)
self.add_option("--remote-app-path", action="store", self.add_option(
type = "string", dest = "remoteAppPath", "--remote-app-path",
help = "Path to remote executable relative to device root using only forward slashes. Either this or app must be specified but not both") action="store",
type="string",
dest="remoteAppPath",
help="Path to remote executable relative to device root using only forward slashes. Either this or app must be specified but not both")
defaults["remoteAppPath"] = None defaults["remoteAppPath"] = None
self.add_option("--deviceIP", action="store", self.add_option("--deviceIP", action="store",
type = "string", dest = "deviceIP", type="string", dest="deviceIP",
help = "ip address of remote device to test") help="ip address of remote device to test")
defaults["deviceIP"] = None defaults["deviceIP"] = None
self.add_option("--deviceSerial", action="store", self.add_option("--deviceSerial", action="store",
type = "string", dest = "deviceSerial", type="string", dest="deviceSerial",
help = "ip address of remote device to test") help="ip address of remote device to test")
defaults["deviceSerial"] = None defaults["deviceSerial"] = None
self.add_option("--dm_trans", action="store", self.add_option(
type = "string", dest = "dm_trans", "--dm_trans",
help = "the transport to use to communicate with device: [adb|sut]; default=sut") action="store",
type="string",
dest="dm_trans",
help="the transport to use to communicate with device: [adb|sut]; default=sut")
defaults["dm_trans"] = "sut" defaults["dm_trans"] = "sut"
self.add_option("--devicePort", action="store", self.add_option("--devicePort", action="store",
type = "string", dest = "devicePort", type="string", dest="devicePort",
help = "port of remote device to test") help="port of remote device to test")
defaults["devicePort"] = 20701 defaults["devicePort"] = 20701
self.add_option("--remote-product-name", action="store", self.add_option(
type = "string", dest = "remoteProductName", "--remote-product-name",
help = "The executable's name of remote product to test - either fennec or firefox, defaults to fennec") action="store",
type="string",
dest="remoteProductName",
help="The executable's name of remote product to test - either fennec or firefox, defaults to fennec")
defaults["remoteProductName"] = "fennec" defaults["remoteProductName"] = "fennec"
self.add_option("--remote-logfile", action="store", self.add_option(
type = "string", dest = "remoteLogFile", "--remote-logfile",
help = "Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") action="store",
type="string",
dest="remoteLogFile",
help="Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.")
defaults["remoteLogFile"] = None defaults["remoteLogFile"] = None
self.add_option("--remote-webserver", action = "store", self.add_option(
type = "string", dest = "remoteWebServer", "--remote-webserver",
help = "ip address where the remote web server is hosted at") action="store",
type="string",
dest="remoteWebServer",
help="ip address where the remote web server is hosted at")
defaults["remoteWebServer"] = None defaults["remoteWebServer"] = None
self.add_option("--http-port", action = "store", self.add_option("--http-port", action="store",
type = "string", dest = "httpPort", type="string", dest="httpPort",
help = "http port of the remote web server") help="http port of the remote web server")
defaults["httpPort"] = automation.DEFAULT_HTTP_PORT defaults["httpPort"] = automation.DEFAULT_HTTP_PORT
self.add_option("--ssl-port", action = "store", self.add_option("--ssl-port", action="store",
type = "string", dest = "sslPort", type="string", dest="sslPort",
help = "ssl port of the remote web server") help="ssl port of the remote web server")
defaults["sslPort"] = automation.DEFAULT_SSL_PORT defaults["sslPort"] = automation.DEFAULT_SSL_PORT
self.add_option("--robocop-ini", action = "store", self.add_option(
type = "string", dest = "robocopIni", "--robocop-ini",
help = "name of the .ini file containing the list of tests to run") action="store",
type="string",
dest="robocopIni",
help="name of the .ini file containing the list of tests to run")
defaults["robocopIni"] = "" defaults["robocopIni"] = ""
self.add_option("--robocop", action = "store", self.add_option(
type = "string", dest = "robocop", "--robocop",
help = "name of the .ini file containing the list of tests to run. [DEPRECATED- please use --robocop-ini") action="store",
type="string",
dest="robocop",
help="name of the .ini file containing the list of tests to run. [DEPRECATED- please use --robocop-ini")
defaults["robocop"] = "" defaults["robocop"] = ""
self.add_option("--robocop-apk", action = "store", self.add_option(
type = "string", dest = "robocopApk", "--robocop-apk",
help = "name of the Robocop APK to use for ADB test running") action="store",
type="string",
dest="robocopApk",
help="name of the Robocop APK to use for ADB test running")
defaults["robocopApk"] = "" defaults["robocopApk"] = ""
self.add_option("--robocop-path", action = "store", self.add_option(
type = "string", dest = "robocopPath", "--robocop-path",
help = "Path to the folder where robocop.apk is located at. Primarily used for ADB test running. [DEPRECATED- please use --robocop-apk]") action="store",
type="string",
dest="robocopPath",
help="Path to the folder where robocop.apk is located at. Primarily used for ADB test running. [DEPRECATED- please use --robocop-apk]")
defaults["robocopPath"] = "" defaults["robocopPath"] = ""
self.add_option("--robocop-ids", action = "store", self.add_option(
type = "string", dest = "robocopIds", "--robocop-ids",
help = "name of the file containing the view ID map (fennec_ids.txt)") action="store",
type="string",
dest="robocopIds",
help="name of the file containing the view ID map (fennec_ids.txt)")
defaults["robocopIds"] = "" defaults["robocopIds"] = ""
self.add_option("--remoteTestRoot", action = "store", self.add_option(
type = "string", dest = "remoteTestRoot", "--remoteTestRoot",
help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") 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 defaults["remoteTestRoot"] = None
defaults["logFile"] = "mochitest.log" defaults["logFile"] = "mochitest.log"
@@ -131,38 +168,43 @@ class RemoteOptions(MochitestOptions):
if not options.remoteTestRoot: if not options.remoteTestRoot:
options.remoteTestRoot = automation._devicemanager.deviceRoot options.remoteTestRoot = automation._devicemanager.deviceRoot
if options.remoteWebServer == None: if options.remoteWebServer is None:
if os.name != "nt": if os.name != "nt":
options.remoteWebServer = moznetwork.get_ip() options.remoteWebServer = moznetwork.get_ip()
else: else:
options_logger.error("you must specify a --remote-webserver=<ip address>") options_logger.error(
"you must specify a --remote-webserver=<ip address>")
return None return None
options.webServer = options.remoteWebServer options.webServer = options.remoteWebServer
if (options.dm_trans == 'sut' and options.deviceIP == None): if (options.dm_trans == 'sut' and options.deviceIP is None):
options_logger.error("If --dm_trans = sut, you must provide a device IP") options_logger.error(
"If --dm_trans = sut, you must provide a device IP")
return None return None
if (options.remoteLogFile == None): if (options.remoteLogFile is None):
options.remoteLogFile = options.remoteTestRoot + '/logs/mochitest.log' options.remoteLogFile = options.remoteTestRoot + \
'/logs/mochitest.log'
if (options.remoteLogFile.count('/') < 1): if (options.remoteLogFile.count('/') < 1):
options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile options.remoteLogFile = options.remoteTestRoot + \
'/' + options.remoteLogFile
# remoteAppPath or app must be specified to find the product to launch # remoteAppPath or app must be specified to find the product to launch
if (options.remoteAppPath and options.app): if (options.remoteAppPath and options.app):
options_logger.error("You cannot specify both the remoteAppPath and the app setting") options_logger.error(
"You cannot specify both the remoteAppPath and the app setting")
return None return None
elif (options.remoteAppPath): elif (options.remoteAppPath):
options.app = options.remoteTestRoot + "/" + options.remoteAppPath options.app = options.remoteTestRoot + "/" + options.remoteAppPath
elif (options.app == None): elif (options.app is None):
# Neither remoteAppPath nor app are set -- error # Neither remoteAppPath nor app are set -- error
options_logger.error("You must specify either appPath or app") options_logger.error("You must specify either appPath or app")
return None return None
# Only reset the xrePath if it wasn't provided # Only reset the xrePath if it wasn't provided
if (options.xrePath == None): if (options.xrePath is None):
options.xrePath = options.utilityPath options.xrePath = options.utilityPath
if (options.pidFile != ""): if (options.pidFile != ""):
@@ -173,38 +215,49 @@ class RemoteOptions(MochitestOptions):
# Robocop specific deprecated options. # Robocop specific deprecated options.
if options.robocop: if options.robocop:
if options.robocopIni: if options.robocopIni:
options_logger.error("can not use deprecated --robocop and replacement --robocop-ini together") options_logger.error(
"can not use deprecated --robocop and replacement --robocop-ini together")
return None return None
options.robocopIni = options.robocop options.robocopIni = options.robocop
del options.robocop del options.robocop
if options.robocopPath: if options.robocopPath:
if options.robocopApk: if options.robocopApk:
options_logger.error("can not use deprecated --robocop-path and replacement --robocop-apk together") options_logger.error(
"can not use deprecated --robocop-path and replacement --robocop-apk together")
return None return None
options.robocopApk = os.path.join(options.robocopPath, 'robocop.apk') options.robocopApk = os.path.join(
options.robocopPath,
'robocop.apk')
del options.robocopPath del options.robocopPath
# Robocop specific options # Robocop specific options
if options.robocopIni != "": if options.robocopIni != "":
if not os.path.exists(options.robocopIni): if not os.path.exists(options.robocopIni):
options_logger.error("Unable to find specified robocop .ini manifest '%s'" % options.robocopIni) options_logger.error(
"Unable to find specified robocop .ini manifest '%s'" %
options.robocopIni)
return None return None
options.robocopIni = os.path.abspath(options.robocopIni) options.robocopIni = os.path.abspath(options.robocopIni)
if options.robocopApk != "": if options.robocopApk != "":
if not os.path.exists(options.robocopApk): if not os.path.exists(options.robocopApk):
options_logger.error("Unable to find robocop APK '%s'" % options.robocopApk) options_logger.error(
"Unable to find robocop APK '%s'" %
options.robocopApk)
return None return None
options.robocopApk = os.path.abspath(options.robocopApk) options.robocopApk = os.path.abspath(options.robocopApk)
if options.robocopIds != "": if options.robocopIds != "":
if not os.path.exists(options.robocopIds): if not os.path.exists(options.robocopIds):
options_logger.error("Unable to find specified robocop IDs file '%s'" % options.robocopIds) options_logger.error(
"Unable to find specified robocop IDs file '%s'" %
options.robocopIds)
return None return None
options.robocopIds = os.path.abspath(options.robocopIds) options.robocopIds = os.path.abspath(options.robocopIds)
# allow us to keep original application around for cleanup while running robocop via 'am' # allow us to keep original application around for cleanup while
# running robocop via 'am'
options.remoteappname = options.app options.remoteappname = options.app
return options return options
@@ -226,6 +279,7 @@ class RemoteOptions(MochitestOptions):
return options return options
class MochiRemote(Mochitest): class MochiRemote(Mochitest):
_automation = None _automation = None
@@ -247,20 +301,24 @@ class MochiRemote(Mochitest):
self._automation.deleteTombstones() self._automation.deleteTombstones()
self.certdbNew = True self.certdbNew = True
self.remoteNSPR = os.path.join(options.remoteTestRoot, "nspr") self.remoteNSPR = os.path.join(options.remoteTestRoot, "nspr")
self._dm.removeDir(self.remoteNSPR); self._dm.removeDir(self.remoteNSPR)
self._dm.mkDir(self.remoteNSPR); self._dm.mkDir(self.remoteNSPR)
self.remoteChromeTestDir = os.path.join(options.remoteTestRoot, "chrome") self.remoteChromeTestDir = os.path.join(
self._dm.removeDir(self.remoteChromeTestDir); options.remoteTestRoot,
self._dm.mkDir(self.remoteChromeTestDir); "chrome")
self._dm.removeDir(self.remoteChromeTestDir)
self._dm.mkDir(self.remoteChromeTestDir)
def cleanup(self, options): def cleanup(self, options):
if self._dm.fileExists(self.remoteLog): if self._dm.fileExists(self.remoteLog):
self._dm.getFile(self.remoteLog, self.localLog) self._dm.getFile(self.remoteLog, self.localLog)
self._dm.removeFile(self.remoteLog) self._dm.removeFile(self.remoteLog)
else: else:
self.log.warning("Unable to retrieve log file (%s) from remote device" % self.remoteLog) self.log.warning(
"Unable to retrieve log file (%s) from remote device" %
self.remoteLog)
self._dm.removeDir(self.remoteProfile) self._dm.removeDir(self.remoteProfile)
self._dm.removeDir(self.remoteChromeTestDir); self._dm.removeDir(self.remoteChromeTestDir)
# Don't leave an old robotium.config hanging around; the # Don't leave an old robotium.config hanging around; the
# profile it references was just deleted! # profile it references was just deleted!
deviceRoot = self._dm.getDeviceRoot() deviceRoot = self._dm.getDeviceRoot()
@@ -270,7 +328,7 @@ class MochiRemote(Mochitest):
self._dm.getDirectory(self.remoteNSPR, blobberUploadDir) self._dm.getDirectory(self.remoteNSPR, blobberUploadDir)
Mochitest.cleanup(self, options) Mochitest.cleanup(self, options)
def findPath(self, paths, filename = None): def findPath(self, paths, filename=None):
for path in paths: for path in paths:
p = path p = path
if filename: if filename:
@@ -286,7 +344,7 @@ class MochiRemote(Mochitest):
localAutomation.IS_MAC = False localAutomation.IS_MAC = False
localAutomation.UNIXISH = False localAutomation.UNIXISH = False
hostos = sys.platform hostos = sys.platform
if (hostos == 'mac' or hostos == 'darwin'): if (hostos == 'mac' or hostos == 'darwin'):
localAutomation.IS_MAC = True localAutomation.IS_MAC = True
elif (hostos == 'linux' or hostos == 'linux2'): elif (hostos == 'linux' or hostos == 'linux2'):
localAutomation.IS_LINUX = True localAutomation.IS_LINUX = True
@@ -315,8 +373,10 @@ class MochiRemote(Mochitest):
os.path.join('..', self._automation._product) os.path.join('..', self._automation._product)
] ]
options.xrePath = self.findPath(paths) options.xrePath = self.findPath(paths)
if options.xrePath == None: if options.xrePath is None:
self.log.error("unable to find xulrunner path for %s, please specify with --xre-path" % os.name) self.log.error(
"unable to find xulrunner path for %s, please specify with --xre-path" %
os.name)
sys.exit(1) sys.exit(1)
xpcshell = "xpcshell" xpcshell = "xpcshell"
@@ -329,15 +389,17 @@ class MochiRemote(Mochitest):
paths = [options.xrePath] paths = [options.xrePath]
options.utilityPath = self.findPath(paths, xpcshell) options.utilityPath = self.findPath(paths, xpcshell)
if options.utilityPath == None: if options.utilityPath is None:
self.log.error("unable to find utility path for %s, please specify with --utility-path" % os.name) self.log.error(
"unable to find utility path for %s, please specify with --utility-path" %
os.name)
sys.exit(1) sys.exit(1)
xpcshell_path = os.path.join(options.utilityPath, xpcshell) xpcshell_path = os.path.join(options.utilityPath, xpcshell)
if localAutomation.elf_arm(xpcshell_path): if localAutomation.elf_arm(xpcshell_path):
self.log.error('xpcshell at %s is an ARM binary; please use ' self.log.error('xpcshell at %s is an ARM binary; please use '
'the --utility-path argument to specify the path ' 'the --utility-path argument to specify the path '
'to a desktop version.' % xpcshell_path) 'to a desktop version.' % xpcshell_path)
sys.exit(1) sys.exit(1)
if self.localProfile: if self.localProfile:
@@ -356,7 +418,11 @@ class MochiRemote(Mochitest):
""" Create the servers on the host and start them up """ """ Create the servers on the host and start them up """
restoreRemotePaths = self.switchToLocalPaths(options) restoreRemotePaths = self.switchToLocalPaths(options)
# ignoreSSLTunnelExts is a workaround for bug 1109310 # ignoreSSLTunnelExts is a workaround for bug 1109310
Mochitest.startServers(self, options, debuggerInfo, ignoreSSLTunnelExts = True) Mochitest.startServers(
self,
options,
debuggerInfo,
ignoreSSLTunnelExts=True)
restoreRemotePaths() restoreRemotePaths()
def buildProfile(self, options): def buildProfile(self, options):
@@ -368,15 +434,31 @@ class MochiRemote(Mochitest):
# we do not need this for robotium based tests, lets save a LOT of time # we do not need this for robotium based tests, lets save a LOT of time
if options.robocopIni: if options.robocopIni:
shutil.rmtree(os.path.join(options.profilePath, 'webapps')) shutil.rmtree(os.path.join(options.profilePath, 'webapps'))
shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', 'mochikit@mozilla.org')) shutil.rmtree(
shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', 'worker-test@mozilla.org')) os.path.join(
shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', 'workerbootstrap-test@mozilla.org')) options.profilePath,
'extensions',
'staged',
'mochikit@mozilla.org'))
shutil.rmtree(
os.path.join(
options.profilePath,
'extensions',
'staged',
'worker-test@mozilla.org'))
shutil.rmtree(
os.path.join(
options.profilePath,
'extensions',
'staged',
'workerbootstrap-test@mozilla.org'))
os.remove(os.path.join(options.profilePath, 'userChrome.css')) os.remove(os.path.join(options.profilePath, 'userChrome.css'))
try: try:
self._dm.pushDir(options.profilePath, self.remoteProfile) self._dm.pushDir(options.profilePath, self.remoteProfile)
except devicemanager.DMError: except devicemanager.DMError:
self.log.error("Automation Error: Unable to copy profile to device.") self.log.error(
"Automation Error: Unable to copy profile to device.")
raise raise
restoreRemotePaths() restoreRemotePaths()
@@ -392,11 +474,12 @@ class MochiRemote(Mochitest):
retVal = Mochitest.buildURLOptions(self, options, env) retVal = Mochitest.buildURLOptions(self, options, env)
if not options.robocopIni: if not options.robocopIni:
#we really need testConfig.js (for browser chrome) # we really need testConfig.js (for browser chrome)
try: try:
self._dm.pushDir(options.profilePath, self.remoteProfile) self._dm.pushDir(options.profilePath, self.remoteProfile)
except devicemanager.DMError: except devicemanager.DMError:
self.log.error("Automation Error: Unable to copy profile to device.") self.log.error(
"Automation Error: Unable to copy profile to device.")
raise raise
options.profilePath = self.remoteProfile options.profilePath = self.remoteProfile
@@ -416,7 +499,11 @@ class MochiRemote(Mochitest):
# robocop tests. # robocop tests.
return self.buildTestURL(options) return self.buildTestURL(options)
else: else:
return super(MochiRemote, self).buildTestPath(options, testsToFilter) return super(
MochiRemote,
self).buildTestPath(
options,
testsToFilter)
def getChromeTestDir(self, options): def getChromeTestDir(self, options):
local = super(MochiRemote, self).getChromeTestDir(options) local = super(MochiRemote, self).getChromeTestDir(options)
@@ -430,7 +517,8 @@ class MochiRemote(Mochitest):
def getLogFilePath(self, logFile): def getLogFilePath(self, logFile):
return logFile return logFile
# In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ # In the future we could use LogParser:
# http://hg.mozilla.org/automation/logparser/
def addLogData(self): def addLogData(self):
with open(self.localLog) as currentLog: with open(self.localLog) as currentLog:
data = currentLog.readlines() data = currentLog.readlines()
@@ -461,7 +549,8 @@ class MochiRemote(Mochitest):
if fail_found: if fail_found:
result = 1 result = 1
if not end_found: if not end_found:
self.log.info("PROCESS-CRASH | Automation Error: Missing end of test marker (process crashed?)") self.log.info(
"PROCESS-CRASH | Automation Error: Missing end of test marker (process crashed?)")
result = 1 result = 1
return result return result
@@ -494,7 +583,8 @@ class MochiRemote(Mochitest):
incr += 1 incr += 1
logFile.append("%s INFO SimpleTest FINISHED" % incr) logFile.append("%s INFO SimpleTest FINISHED" % incr)
# TODO: Consider not printing to stdout because we might be duplicating output # TODO: Consider not printing to stdout because we might be duplicating
# output
print '\n'.join(logFile) print '\n'.join(logFile)
with open(self.localLog, 'w') as localLog: with open(self.localLog, 'w') as localLog:
localLog.write('\n'.join(logFile)) localLog.write('\n'.join(logFile))
@@ -506,7 +596,9 @@ class MochiRemote(Mochitest):
def printScreenshots(self, screenShotDir): def printScreenshots(self, screenShotDir):
# TODO: This can be re-written after completion of bug 749421 # TODO: This can be re-written after completion of bug 749421
if not self._dm.dirExists(screenShotDir): if not self._dm.dirExists(screenShotDir):
self.log.info("SCREENSHOT: No ScreenShots directory available: " + screenShotDir) self.log.info(
"SCREENSHOT: No ScreenShots directory available: " +
screenShotDir)
return return
printed = 0 printed = 0
@@ -527,8 +619,13 @@ class MochiRemote(Mochitest):
def printDeviceInfo(self, printLogcat=False): def printDeviceInfo(self, printLogcat=False):
try: try:
if printLogcat: if printLogcat:
logcat = self._dm.getLogcat(filterOutRegexps=fennecLogcatFilters) logcat = self._dm.getLogcat(
self.log.info('\n' + ''.join(logcat).decode('utf-8', 'replace')) filterOutRegexps=fennecLogcatFilters)
self.log.info(
'\n' +
''.join(logcat).decode(
'utf-8',
'replace'))
self.log.info("Device info: %s" % self._dm.getInfo()) self.log.info("Device info: %s" % self._dm.getInfo())
self.log.info("Test root: %s" % self._dm.deviceRoot) self.log.info("Test root: %s" % self._dm.deviceRoot)
except devicemanager.DMError: except devicemanager.DMError:
@@ -543,7 +640,9 @@ class MochiRemote(Mochitest):
fHandle.write("profile=%s\n" % (self.remoteProfile)) fHandle.write("profile=%s\n" % (self.remoteProfile))
fHandle.write("logfile=%s\n" % (options.remoteLogFile)) fHandle.write("logfile=%s\n" % (options.remoteLogFile))
fHandle.write("host=http://mochi.test:8888/tests\n") fHandle.write("host=http://mochi.test:8888/tests\n")
fHandle.write("rawhost=http://%s:%s/tests\n" % (options.remoteWebServer, options.httpPort)) fHandle.write(
"rawhost=http://%s:%s/tests\n" %
(options.remoteWebServer, options.httpPort))
if browserEnv: if browserEnv:
envstr = "" envstr = ""
@@ -551,7 +650,9 @@ class MochiRemote(Mochitest):
for key, value in browserEnv.items(): for key, value in browserEnv.items():
try: try:
value.index(',') value.index(',')
self.log.error("buildRobotiumConfig: browserEnv - Found a ',' in our value, unable to process value. key=%s,value=%s" % (key, value)) self.log.error(
"buildRobotiumConfig: browserEnv - Found a ',' in our value, unable to process value. key=%s,value=%s" %
(key, value))
self.log.error("browserEnv=%s" % browserEnv) self.log.error("browserEnv=%s" % browserEnv)
except ValueError: except ValueError:
envstr += "%s%s=%s" % (delim, key, value) envstr += "%s%s=%s" % (delim, key, value)
@@ -561,7 +662,11 @@ class MochiRemote(Mochitest):
fHandle.close() fHandle.close()
self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) self._dm.removeFile(os.path.join(deviceRoot, "robotium.config"))
self._dm.pushFile(fHandle.name, os.path.join(deviceRoot, "robotium.config")) self._dm.pushFile(
fHandle.name,
os.path.join(
deviceRoot,
"robotium.config"))
os.unlink(fHandle.name) os.unlink(fHandle.name)
def getGMPPluginPath(self, options): def getGMPPluginPath(self, options):
@@ -569,10 +674,15 @@ class MochiRemote(Mochitest):
return None return None
def buildBrowserEnv(self, options, debugger=False): def buildBrowserEnv(self, options, debugger=False):
browserEnv = Mochitest.buildBrowserEnv(self, options, debugger=debugger) browserEnv = Mochitest.buildBrowserEnv(
self,
options,
debugger=debugger)
# override nsprLogs to avoid processing in Mochitest base class # override nsprLogs to avoid processing in Mochitest base class
self.nsprLogs = None self.nsprLogs = None
browserEnv["NSPR_LOG_FILE"] = os.path.join(self.remoteNSPR, self.nsprLogName) browserEnv["NSPR_LOG_FILE"] = os.path.join(
self.remoteNSPR,
self.nsprLogName)
self.buildRobotiumConfig(options, browserEnv) self.buildRobotiumConfig(options, browserEnv)
return browserEnv return browserEnv
@@ -593,6 +703,7 @@ class MochiRemote(Mochitest):
return self._automation.runApp(*args, **kwargs) return self._automation.runApp(*args, **kwargs)
def main(args): def main(args):
message_logger = MessageLogger(logger=None) message_logger = MessageLogger(logger=None)
process_args = {'messageLogger': message_logger} process_args = {'messageLogger': message_logger}
@@ -604,13 +715,23 @@ def main(args):
if (options.dm_trans == "adb"): if (options.dm_trans == "adb"):
if (options.deviceIP): if (options.deviceIP):
dm = droid.DroidADB(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot) dm = droid.DroidADB(
options.deviceIP,
options.devicePort,
deviceRoot=options.remoteTestRoot)
elif (options.deviceSerial): elif (options.deviceSerial):
dm = droid.DroidADB(None, None, deviceSerial=options.deviceSerial, deviceRoot=options.remoteTestRoot) dm = droid.DroidADB(
None,
None,
deviceSerial=options.deviceSerial,
deviceRoot=options.remoteTestRoot)
else: else:
dm = droid.DroidADB(deviceRoot=options.remoteTestRoot) dm = droid.DroidADB(deviceRoot=options.remoteTestRoot)
else: else:
dm = droid.DroidSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot) dm = droid.DroidSUT(
options.deviceIP,
options.devicePort,
deviceRoot=options.remoteTestRoot)
auto.setDeviceManager(dm) auto.setDeviceManager(dm)
options = parser.verifyRemoteOptions(options, auto) options = parser.verifyRemoteOptions(options, auto)
@@ -620,23 +741,24 @@ def main(args):
message_logger.logger = log message_logger.logger = log
mochitest.message_logger = message_logger mochitest.message_logger = message_logger
if (options == None): if (options is None):
log.error("Invalid options specified, use --help for a list of valid options") log.error(
"Invalid options specified, use --help for a list of valid options")
return 1 return 1
productPieces = options.remoteProductName.split('.') productPieces = options.remoteProductName.split('.')
if (productPieces != None): if (productPieces is not None):
auto.setProduct(productPieces[0]) auto.setProduct(productPieces[0])
else: else:
auto.setProduct(options.remoteProductName) auto.setProduct(options.remoteProductName)
auto.setAppName(options.remoteappname) auto.setAppName(options.remoteappname)
options = parser.verifyOptions(options, mochitest) options = parser.verifyOptions(options, mochitest)
if (options == None): if (options is None):
return 1 return 1
logParent = os.path.dirname(options.remoteLogFile) logParent = os.path.dirname(options.remoteLogFile)
dm.mkDir(logParent); dm.mkDir(logParent)
auto.setRemoteLog(options.remoteLogFile) auto.setRemoteLog(options.remoteLogFile)
auto.setServerInfo(options.webServer, options.httpPort, options.sslPort) auto.setServerInfo(options.webServer, options.httpPort, options.sslPort)
@@ -645,7 +767,9 @@ def main(args):
# Add Android version (SDK level) to mozinfo so that manifest entries # Add Android version (SDK level) to mozinfo so that manifest entries
# can be conditional on android_version. # can be conditional on android_version.
androidVersion = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk']) androidVersion = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk'])
log.info("Android sdk version '%s'; will use this to filter manifests" % str(androidVersion)) log.info(
"Android sdk version '%s'; will use this to filter manifests" %
str(androidVersion))
mozinfo.info['android_version'] = androidVersion mozinfo.info['android_version'] = androidVersion
deviceRoot = dm.deviceRoot deviceRoot = dm.deviceRoot
@@ -677,13 +801,14 @@ def main(args):
tests.append(test['name']) tests.append(test['name'])
if options.totalChunks: if options.totalChunks:
tests_per_chunk = math.ceil(len(tests) / (options.totalChunks * 1.0)) tests_per_chunk = math.ceil(
start = int(round((options.thisChunk-1) * tests_per_chunk)) len(tests) / (options.totalChunks * 1.0))
start = int(round((options.thisChunk - 1) * tests_per_chunk))
end = int(round(options.thisChunk * tests_per_chunk)) end = int(round(options.thisChunk * tests_per_chunk))
if end > len(tests): if end > len(tests):
end = len(tests) end = len(tests)
my_tests = tests[start:end] my_tests = tests[start:end]
log.info("Running tests %d-%d/%d" % (start+1, end, len(tests))) log.info("Running tests %d-%d/%d" % (start + 1, end, len(tests)))
options.extraPrefs.append('browser.search.suggest.enabled=true') options.extraPrefs.append('browser.search.suggest.enabled=true')
options.extraPrefs.append('browser.search.suggest.prompted=true') options.extraPrefs.append('browser.search.suggest.prompted=true')
@@ -706,7 +831,9 @@ def main(args):
continue continue
if 'disabled' in test: if 'disabled' in test:
log.info('TEST-INFO | skipping %s | %s' % (test['name'], test['disabled'])) log.info(
'TEST-INFO | skipping %s | %s' %
(test['name'], test['disabled']))
continue continue
active_tests.append(test) active_tests.append(test)
@@ -714,7 +841,8 @@ def main(args):
log.suite_start([t['name'] for t in active_tests]) log.suite_start([t['name'] for t in active_tests])
for test in active_tests: for test in active_tests:
# When running in a loop, we need to create a fresh profile for each cycle # When running in a loop, we need to create a fresh profile for
# each cycle
if mochitest.localProfile: if mochitest.localProfile:
options.profilePath = mochitest.localProfile options.profilePath = mochitest.localProfile
os.system("rm -Rf %s" % options.profilePath) os.system("rm -Rf %s" % options.profilePath)
@@ -722,34 +850,75 @@ def main(args):
mochitest.localProfile = options.profilePath mochitest.localProfile = options.profilePath
options.app = "am" options.app = "am"
options.browserArgs = ["instrument", "-w", "-e", "deviceroot", deviceRoot, "-e", "class"] options.browserArgs = [
options.browserArgs.append("org.mozilla.gecko.tests.%s" % test['name']) "instrument",
options.browserArgs.append("org.mozilla.roboexample.test/org.mozilla.gecko.FennecInstrumentationTestRunner") "-w",
"-e",
"deviceroot",
deviceRoot,
"-e",
"class"]
options.browserArgs.append(
"org.mozilla.gecko.tests.%s" %
test['name'])
options.browserArgs.append(
"org.mozilla.roboexample.test/org.mozilla.gecko.FennecInstrumentationTestRunner")
mochitest.nsprLogName = "nspr-%s.log" % test['name'] mochitest.nsprLogName = "nspr-%s.log" % test['name']
# If the test is for checking the import from bookmarks then make sure there is data to import # If the test is for checking the import from bookmarks then make
# sure there is data to import
if test['name'] == "testImportFromAndroid": if test['name'] == "testImportFromAndroid":
# Get the OS so we can run the insert in the apropriate database and following the correct table schema # Get the OS so we can run the insert in the apropriate
# database and following the correct table schema
osInfo = dm.getInfo("os") osInfo = dm.getInfo("os")
devOS = " ".join(osInfo['os']) devOS = " ".join(osInfo['os'])
if ("pandaboard" in devOS): if ("pandaboard" in devOS):
delete = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"] delete = [
'execsu',
'sqlite3',
"/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"]
else: else:
delete = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"] delete = [
'execsu',
'sqlite3',
"/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"]
if (options.dm_trans == "sut"): if (options.dm_trans == "sut"):
dm._runCmds([{"cmd": " ".join(delete)}]) dm._runCmds([{"cmd": " ".join(delete)}])
# Insert the bookmarks # Insert the bookmarks
log.info("Insert bookmarks in the default android browser database") log.info(
"Insert bookmarks in the default android browser database")
for i in range(20): for i in range(20):
if ("pandaboard" in devOS): if ("pandaboard" in devOS):
cmd = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser2.db 'insert or replace into bookmarks(_id,title,url,folder,parent,position) values (" + str(30 + i) + ",\"Bookmark"+ str(i) + "\",\"http://www.bookmark" + str(i) + ".com\",0,1," + str(100 + i) + ");'"] cmd = [
else: 'execsu',
cmd = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser.db 'insert into bookmarks(title,url,bookmark) values (\"Bookmark"+ str(i) + "\",\"http://www.bookmark" + str(i) + ".com\",1);'"] 'sqlite3',
if (options.dm_trans == "sut"): "/data/data/com.android.browser/databases/browser2.db 'insert or replace into bookmarks(_id,title,url,folder,parent,position) values (" +
dm._runCmds([{"cmd": " ".join(cmd)}]) str(
30 +
i) +
",\"Bookmark" +
str(i) +
"\",\"http://www.bookmark" +
str(i) +
".com\",0,1," +
str(
100 +
i) +
");'"]
else:
cmd = [
'execsu',
'sqlite3',
"/data/data/com.android.browser/databases/browser.db 'insert into bookmarks(title,url,bookmark) values (\"Bookmark" +
str(i) +
"\",\"http://www.bookmark" +
str(i) +
".com\",1);'"]
if (options.dm_trans == "sut"):
dm._runCmds([{"cmd": " ".join(cmd)}])
try: try:
screenShotDir = "/mnt/sdcard/Robotium-Screenshots" screenShotDir = "/mnt/sdcard/Robotium-Screenshots"
dm.removeDir(screenShotDir) dm.removeDir(screenShotDir)
@@ -761,11 +930,13 @@ def main(args):
if result != 0 or log_result != 0: if result != 0 or log_result != 0:
mochitest.printDeviceInfo(printLogcat=True) mochitest.printDeviceInfo(printLogcat=True)
mochitest.printScreenshots(screenShotDir) mochitest.printScreenshots(screenShotDir)
# Ensure earlier failures aren't overwritten by success on this run # Ensure earlier failures aren't overwritten by success on this
# run
if retVal is None or retVal == 0: if retVal is None or retVal == 0:
retVal = result retVal = result
except: except:
log.error("Automation Error: Exception caught while running tests") log.error(
"Automation Error: Exception caught while running tests")
traceback.print_exc() traceback.print_exc()
mochitest.stopServers() mochitest.stopServers()
try: try:
@@ -779,9 +950,15 @@ def main(args):
# Clean-up added bookmarks # Clean-up added bookmarks
if test['name'] == "testImportFromAndroid": if test['name'] == "testImportFromAndroid":
if ("pandaboard" in devOS): if ("pandaboard" in devOS):
cmd_del = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"] cmd_del = [
'execsu',
'sqlite3',
"/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"]
else: else:
cmd_del = ['execsu', 'sqlite3', "/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"] cmd_del = [
'execsu',
'sqlite3',
"/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"]
if (options.dm_trans == "sut"): if (options.dm_trans == "sut"):
dm._runCmds([{"cmd": " ".join(cmd_del)}]) dm._runCmds([{"cmd": " ".join(cmd_del)}])
if retVal is None: if retVal is None: