Bug 1199588 - Add --workspace option to Marionette runner; r=automatedtester

The default behaviour is unchanged: gecko.log and logcat are saved to the
cwd, a temporary Firefox profile is cloned or created in TMP.

When a path is specified via --workspace, gecko.log, logcat and the Firefox
profile directory are all saved there instead. A profile saved in the
workspace does not get deleted at the end of a session unless it's a clone.
This commit is contained in:
Maja Frydrychowicz 2015-11-02 11:55:29 -05:00
parent 3c7870b2c4
commit 01f5f95436
3 changed files with 59 additions and 16 deletions

View File

@ -250,6 +250,13 @@ class BaseMarionetteArguments(ArgumentParser):
def __init__(self, **kwargs):
ArgumentParser.__init__(self, **kwargs)
def dir_path(path):
path = os.path.abspath(os.path.expanduser(path))
if not os.access(path, os.F_OK):
os.makedirs(path)
return path
self.argument_containers = []
self.add_argument('tests',
nargs='*',
@ -276,7 +283,8 @@ class BaseMarionetteArguments(ArgumentParser):
help='when Marionette launches an emulator, start it with the -no-window argument')
self.add_argument('--logcat-dir',
dest='logdir',
help='directory to store logcat dump files')
help='directory to store logcat dump files',
type=dir_path)
self.add_argument('--logcat-stdout',
action='store_true',
default=False,
@ -309,7 +317,8 @@ class BaseMarionetteArguments(ArgumentParser):
help='gecko executable to launch before running the test')
self.add_argument('--profile',
help='profile to use when launching the gecko process. if not passed, then a profile will be '
'constructed and used')
'constructed and used',
type=dir_path)
self.add_argument('--pref',
action='append',
dest='prefs_args',
@ -394,6 +403,12 @@ class BaseMarionetteArguments(ArgumentParser):
help="Filter out tests that don't have the given tag. Can be "
"used multiple times in which case the test must contain "
"at least one of the given tags.")
self.add_argument('--workspace',
action='store',
default=None,
help="Path to directory for Marionette output. "
"(Default: .) (Default profile dest: TMP)",
type=dir_path)
def register_argument_container(self, container):
group = self.add_argument_group(container.name)
@ -448,10 +463,6 @@ class BaseMarionetteArguments(ArgumentParser):
print 'can\'t specify both --emulator and --binary'
sys.exit(1)
# default to storing logcat output for emulator runs
if args.emulator and not args.logdir:
args.logdir = 'logcat'
# check for valid resolution string, strip whitespaces
try:
if args.emulator_res:
@ -510,7 +521,7 @@ class BaseMarionetteTestRunner(object):
server_root=None, gecko_log=None, result_callbacks=None,
adb_host=None, adb_port=None, prefs=None, test_tags=None,
socket_timeout=BaseMarionetteArguments.socket_timeout_default,
startup_timeout=None, addons=None, **kwargs):
startup_timeout=None, addons=None, workspace=None, **kwargs):
self.address = address
self.emulator = emulator
self.emulator_binary = emulator_binary
@ -547,7 +558,6 @@ class BaseMarionetteTestRunner(object):
self.server_root = server_root
self.this_chunk = this_chunk
self.total_chunks = total_chunks
self.gecko_log = gecko_log
self.mixin_run_tests = []
self.manifest_skipped_tests = []
self.tests = []
@ -557,6 +567,10 @@ class BaseMarionetteTestRunner(object):
self.prefs = prefs or {}
self.test_tags = test_tags
self.startup_timeout = startup_timeout
self.workspace = workspace
# If no workspace is set, default location for logcat and gecko.log is .
# and default location for profile is TMP
self.workspace_path = workspace or os.getcwd()
def gather_debug(test, status):
rv = {}
@ -605,10 +619,21 @@ class BaseMarionetteTestRunner(object):
self.reset_test_stats()
if self.logdir:
if not os.access(self.logdir, os.F_OK):
self.logger.info('Using workspace for temporary data: '
'"{}"'.format(self.workspace_path))
if not self.workspace:
self.logger.info('Profile destination is TMP')
if self.emulator and not self.logdir:
self.logdir = os.path.join(self.workspace_path or '', 'logcat')
if self.logdir and not os.access(self.logdir, os.F_OK):
os.mkdir(self.logdir)
if not gecko_log:
self.gecko_log = os.path.join(self.workspace_path or '', 'gecko.log')
else:
self.gecko_log = gecko_log
# for XML output
self.testvars['xml_output'] = self.xml_output
self.results = []
@ -721,6 +746,8 @@ class BaseMarionetteTestRunner(object):
'no_window': self.no_window,
'sdcard': self.sdcard,
})
if self.workspace:
kwargs['workspace'] = self.workspace_path
return kwargs
def start_marionette(self):

View File

@ -3,10 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/
from copy import deepcopy
import errno
import platform
import os
import sys
import tempfile
import time
from mozprofile import Profile
@ -44,10 +43,13 @@ class GeckoInstance(object):
}
def __init__(self, host, port, bin, profile=None, addons=None,
app_args=None, symbols_path=None, gecko_log=None, prefs=None):
app_args=None, symbols_path=None, gecko_log=None, prefs=None,
workspace=None):
self.marionette_host = host
self.marionette_port = port
self.bin = bin
# Alternative to default temporary directory
self.workspace = workspace
# Check if it is a Profile object or a path to profile
self.profile = None
self.addons = addons
@ -94,9 +96,20 @@ class GeckoInstance(object):
if hasattr(self, "profile_path") and self.profile is None:
if not self.profile_path:
if self.workspace:
profile_args['profile'] = tempfile.mkdtemp(
suffix='.mozrunner-{:.0f}'.format(time.time()),
dir=self.workspace)
self.profile = Profile(**profile_args)
else:
profile_args["path_from"] = self.profile_path
profile_name = '{}-{:.0f}'.format(
os.path.basename(self.profile_path),
time.time()
)
if self.workspace:
profile_args["path_to"] = os.path.join(self.workspace,
profile_name)
self.profile = Profile.clone(**profile_args)
process_args = {

View File

@ -541,7 +541,8 @@ class Marionette(object):
gecko_log=None, homedir=None, baseurl=None, no_window=False, logdir=None,
busybox=None, symbols_path=None, timeout=None, socket_timeout=360,
device_serial=None, adb_path=None, process_args=None,
adb_host=None, adb_port=None, prefs=None, startup_timeout=None):
adb_host=None, adb_port=None, prefs=None, startup_timeout=None,
workspace=None):
self.host = host
self.port = self.local_port = port
self.bin = bin
@ -590,9 +591,11 @@ class Marionette(object):
instance_class = geckoinstance.GeckoInstance
self.instance = instance_class(host=self.host, port=self.port,
bin=self.bin, profile=self.profile,
app_args=app_args, symbols_path=symbols_path,
app_args=app_args,
symbols_path=symbols_path,
gecko_log=gecko_log, prefs=prefs,
addons=self.addons)
addons=self.addons,
workspace=workspace)
self.instance.start()
assert(self.wait_for_port(timeout=startup_timeout)), "Timed out waiting for port!"