def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons 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 = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1'}) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args) self.runner.start()
def start(self): profile_args = {"preferences": self.required_prefs} if not self.profile_path: profile_args["restore"] = False profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path profile = Profile.clone(**profile_args) if self.gecko_log is None: self.gecko_log = 'gecko.log' elif os.path.isdir(self.gecko_log): fname = "gecko-%d.log" % time.time() self.gecko_log = os.path.join(self.gecko_log, fname) self.gecko_log = os.path.realpath(self.gecko_log) if os.access(self.gecko_log, os.F_OK): os.remove(self.gecko_log) env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner( binary=self.bin, profile=profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args={ 'processOutputLine': [NullOutput()], 'logfile': self.gecko_log}) self.runner.start()
def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons 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 = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args) self.runner.start()
def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} if self.prefs: profile_args["preferences"].update(self.prefs) if not self.profile_path: profile_args["restore"] = False profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path profile = Profile.clone(**profile_args) if self.gecko_log is None: self.gecko_log = 'gecko.log' elif os.path.isdir(self.gecko_log): fname = "gecko-%d.log" % time.time() self.gecko_log = os.path.join(self.gecko_log, fname) self.gecko_log = os.path.realpath(self.gecko_log) if os.access(self.gecko_log, os.F_OK): if platform.system() is 'Windows': # NOTE: windows has a weird filesystem where it happily 'closes' # the file, but complains if you try to delete it. You get a # 'file still in use' error. Sometimes you can wait a bit and # a retry will succeed. # If all retries fail, we'll just continue without removing # the file. In this case, if we are restarting the instance, # then the new logs just get appended to the old file. tries = 0 while tries < 10: try: os.remove(self.gecko_log) break except WindowsError as e: if e.errno == errno.EACCES: tries += 1 time.sleep(0.5) else: raise e else: os.remove(self.gecko_log) env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner( binary=self.bin, profile=profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args={ 'processOutputLine': [NullOutput()], 'logfile': self.gecko_log}) self.runner.start()
def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"][ "marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons if hasattr(self, "profile_path") and self.profile is None: if not self.profile_path: self.profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path self.profile = Profile.clone(**profile_args) process_args = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner(binary=self.bin, profile=self.profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args) self.runner.start()
def _update_profile(self, profile=None, profile_name=None): """Check if the profile has to be created, or replaced. :param profile: A Profile instance to be used. :param name: Profile name to be used in the path. """ if self.runner and self.runner.is_running(): raise errors.MarionetteException( "The current profile can only be updated " "when the instance is not running" ) if isinstance(profile, Profile): # Only replace the profile if it is not the current one if hasattr(self, "_profile") and profile is self._profile: return else: profile_args = self.profile_args profile_path = profile # If a path to a profile is given then clone it if isinstance(profile_path, six.string_types): profile_args["path_from"] = profile_path profile_args["path_to"] = tempfile.mkdtemp( suffix=u".{}".format( profile_name or os.path.basename(profile_path) ), dir=self.workspace, ) # The target must not exist yet os.rmdir(profile_args["path_to"]) profile = Profile.clone(**profile_args) # Otherwise create a new profile else: profile_args["profile"] = tempfile.mkdtemp( suffix=u".{}".format(profile_name or "mozrunner"), dir=self.workspace, ) profile = Profile(**profile_args) profile.create_new = True if isinstance(self.profile, Profile): self.profile.cleanup() self._profile = profile
def test_with_profile_should_cleanup_even_on_exception(self): with self.assertRaises(ZeroDivisionError): with Profile() as profile: self.assertTrue(os.path.exists(profile.profile)) 1 / 0 # will raise ZeroDivisionError # profile is cleaned self.assertFalse(os.path.exists(profile.profile))
def start_runner(self, binary, options): profile = Profile(profile=options.get('profile')) cmdargs = options.get('argv', []) if 'screen' in options and \ 'width' in options['screen'] and \ 'height' in options['screen']: screen = '--screen=%sx%s' % (options['screen']['width'], \ options['screen']['height']) if 'dpi' in options['screen']: screen = '%s@%s' % (screen, options['screen']['dpi']) cmdargs.append(screen) if options.get('noRemote', True): cmdargs.append('-no-remote') if options.get('url'): cmdargs.append(options['url']) if options.get('chrome'): cmdargs.extend(['-chrome', options['chrome']]) if options.get('startDebugger'): cmdargs.extend( ['-start-debugger-server', options['startDebugger']]) self.runner = B2GDesktopRunner(binary, cmdargs=cmdargs, profile=profile, **self.common_runner_args) self.runner.start()
def start_runner(self, data): binary = os.path.join(data.get('target'), 'b2g-bin') options = data.get('options', {}) profile = Profile(profile=options.get('profile')) cmdargs = options.get('argv', []) if options.get('screen') and \ hasattr(options.screen, 'width') and \ hasattr(options.screen, 'height'): screen = '--screen=%sx%s' % (options.screen.width, options.screen.height) if hasattr(options.screen, 'dpi'): screen = '%s@%s' % (screen, options.screen.dpi) cmdargs.append(screen) if options.get('noRemote', True): cmdargs.append('-no-remote') if options.get('url'): cmdargs.append(options['url']) if options.get('chrome'): cmdargs.extend(['-chrome', options['chrome']]) if options.get('startDebugger'): cmdargs.extend( ['-start-debugger-server', options['startDebugger']]) self.runner = B2GDesktopRunner(binary, cmdargs=cmdargs, profile=profile, **self.common_runner_args) self.runner.start()
def install_profile(self, profile=None, root=True): if not profile: profile = Profile() profile_path_parent = os.path.split(self.profile_path)[0] success = False for attempt in range(1, self.options.phone_retry_limit+1): try: self.loggerdeco.debug('Attempt %d installing profile', attempt) if self.dm.exists(self.profile_path, root=root): # If the profile already exists, chmod it to make sure # we have permission to delete it. self.dm.chmod(self.profile_path, recursive=True, root=root) self.dm.rm(self.profile_path, recursive=True, force=True, root=root) self.dm.chmod(profile_path_parent, root=root) self.dm.mkdir(self.profile_path, root=root) self.dm.chmod(self.profile_path, root=root) self.dm.push(profile.profile, self.profile_path) self.dm.chmod(self.profile_path, recursive=True, root=root) success = True break except ADBError: self.loggerdeco.exception('Attempt %d Exception installing ' 'profile to %s' % ( attempt, self.profile_path)) sleep(self.options.phone_retry_wait) if not success: self.add_failure(self.name, TestStatus.TEST_UNEXPECTED_FAIL, 'Failure installing profile to %s' % self.profile_path, TreeherderStatus.TESTFAILED) return success
def tps_profile(pytestconfig, tps_addon, tps_config, tps_log, fxa_urls): preferences = { 'browser.onboarding.enabled': False, 'browser.startup.homepage_override.mstone': 'ignore', 'browser.startup.page': 0, 'datareporting.policy.dataSubmissionEnabled': False, # 'devtools.chrome.enabled': True, # 'devtools.debugger.remote-enabled': True, 'extensions.autoDisableScopes': 10, 'extensions.legacy.enabled': True, 'identity.fxaccounts.autoconfig.uri': fxa_urls['content'], 'testing.tps.skipPingValidation': True, 'services.sync.log.appender.console': 'Trace', 'services.sync.log.appender.dump': 'Trace', 'services.sync.log.appender.file.level': 'Trace', 'services.sync.log.appender.file.logOnSuccess': True, 'services.sync.log.logger': 'Trace', 'services.sync.log.logger.engine': 'Trace', 'tps.config': json.dumps(tps_config), 'tps.logfile': tps_log, 'tps.seconds_since_epoch': int(time.time()), 'xpinstall.signatures.required': False } profile = Profile(addons=[tps_addon], preferences=preferences) pytestconfig._profile = profile.profile yield profile
def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None): """Runs the given FirefoxRunner with the given Profile, waits for completion, then returns the process exit code """ if profile is None: profile = Profile() self.profile = profile if self.binary is None and self.url: self.binary = self.download_build() if self.runner is None: self.runner = FirefoxRunner(self.profile, binary=self.binary) self.runner.profile = self.profile if env is not None: self.runner.env.update(env) if args is not None: self.runner.cmdargs = copy.copy(args) self.runner.start() returncode = self.runner.wait(timeout) return returncode
def test_with_profile_should_cleanup_even_on_exception(): with pytest.raises(ZeroDivisionError): with Profile() as profile: assert os.path.exists(profile.profile) 1 / 0 # will raise ZeroDivisionError # profile is cleaned assert not os.path.exists(profile.profile)
def build_profile(self): test_root = self.dm.deviceRoot self.remote_profile = posixpath.join(test_root, 'gv-profile') self.dm.mkDirs(posixpath.join(self.remote_profile, "x")) profile = Profile() self.dm.pushDir(profile.profile, self.remote_profile) self.log.debug("profile %s -> %s" % (str(profile.profile), str(self.remote_profile)))
def build_profile(self): test_root = self.device.test_root self.remote_profile = posixpath.join(test_root, 'gv-profile') self.device.mkdir(self.remote_profile, parents=True) profile = Profile() self.device.push(profile.profile, self.remote_profile) self.log.debug("profile %s -> %s" % (str(profile.profile), str(self.remote_profile)))
def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if hasattr(self, "profile_path") and self.profile is None: if not self.profile_path: self.profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path self.profile = Profile.clone(**profile_args) process_args = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args) self.runner.start()
def _update_profile(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"][ "marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if "-jsdebugger" in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args["addons"] = self.addons 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) # nekonbu72 + profile_args["ignore"] = lambda src, names: "parent.lock" self.profile = Profile.clone(**profile_args)
def start_runner(self, binary, options): port = options.get('port') profile = Profile(profile=options.get('profile')) self.runner.device.setup_port_forwarding(local_port=port, remote_port=port) self.runner.profile = profile self.runner.start() if not self.runner.device.wait_for_port(port): raise Exception("Wait for port timed out")
def build_profile(self, options): # preferences prefs = {} for path in self.preferences: prefs.update(Preferences.read_prefs(path)) for v in options.extraPrefs: thispref = v.split("=", 1) if len(thispref) < 2: print "Error: syntax error in --setpref=" + v sys.exit(1) prefs[thispref[0]] = thispref[1] # interpolate the preferences interpolation = { "server": "%s:%s" % (options.webServer, options.httpPort), "OOP": "true" if self.out_of_process else "false" } prefs = json.loads(json.dumps(prefs) % interpolation) for pref in prefs: prefs[pref] = Preferences.cast(prefs[pref]) kwargs = { 'addons': self.getExtensionsToInstall(options), 'apps': self.webapps, 'locations': self.locations_file, 'preferences': prefs, 'proxy': { "remote": options.webServer } } if options.profile: self.profile = Profile.clone(options.profile, **kwargs) else: self.profile = Profile(**kwargs) options.profilePath = self.profile.profile # TODO bug 839108 - mozprofile should probably handle this manifest = self.addChromeToProfile(options) self.copyExtraFilesToProfile(options) return manifest
def _update_profile(self, profile=None, profile_name=None): """Check if the profile has to be created, or replaced :param profile: A Profile instance to be used. :param name: Profile name to be used in the path. """ if self.runner and self.runner.is_running(): raise errors.MarionetteException("The current profile can only be updated " "when the instance is not running") if isinstance(profile, Profile): # Only replace the profile if it is not the current one if hasattr(self, "_profile") and profile is self._profile: return else: profile_args = self.profile_args profile_path = profile # If a path to a profile is given then clone it if isinstance(profile_path, basestring): profile_args["path_from"] = profile_path profile_args["path_to"] = tempfile.mkdtemp( suffix=".{}".format(profile_name or os.path.basename(profile_path)), dir=self.workspace) # The target must not exist yet os.rmdir(profile_args["path_to"]) profile = Profile.clone(**profile_args) # Otherwise create a new profile else: profile_args["profile"] = tempfile.mkdtemp( suffix=".{}".format(profile_name or "mozrunner"), dir=self.workspace) profile = Profile(**profile_args) profile.create_new = True if isinstance(self.profile, Profile): self.profile.cleanup() self._profile = profile
def build_profile(self): """ Create a local profile with test prefs and proxy definitions and push it to the remote device. """ self.profile = Profile(locations=self.locations, proxy=self.proxy(self.options)) self.options.profilePath = self.profile.profile # Set preferences self.merge_base_profiles(self.options, 'geckoview-junit') prefs = parse_preferences(self.options.extra_prefs) self.profile.set_preferences(prefs) if self.fillCertificateDB(self.options): self.log.error("Certificate integration failed") self.device.push(self.profile.profile, self.remote_profile) self.log.debug("profile %s -> %s" % (str(self.profile.profile), str(self.remote_profile)))
def create_mozprofile(profile_dir, application=None, test_type=None, env=None): # Ensure that the base `_temp/profiles/` directory exists before trying to # create a nested directory. if not os.path.exists(BASE_PROFILE_DIR): os.mkdir(BASE_PROFILE_DIR) if not profile_dir: full_profile_dir = mkdtemp( dir=BASE_PROFILE_DIR, prefix="fftool.", suffix="" ) else: full_profile_dir = os.path.join(BASE_PROFILE_DIR, profile_dir) if os.path.exists(full_profile_dir): msg = "WARNING: Profile '{0}' already exists. Merging configs." Log.header(msg.format(full_profile_dir), 'XL', '-') prefs = Preferences() for path in prefs_paths(application, test_type, env): prefs.add_file(path) # Add the `fftool.profile.name` pref so we can go to about:config and see # what our current profile is. prefs.add([("fftool.profile.name", full_profile_dir)]) profile = Profile( profile=full_profile_dir, restore=False, preferences=prefs()) Log.header("Launching browser with the following user configs:") print(profile.summary()) # this is the path to the created profile return full_profile_dir
def _update_profile(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons 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)
def create_mozprofile(profile_dir, application=None, test_type=None, env=None): # Ensure that the base `_temp/profiles/` directory exists before trying to # create a nested directory. if not os.path.exists(BASE_PROFILE_DIR): os.mkdir(BASE_PROFILE_DIR) if not profile_dir: full_profile_dir = mkdtemp(dir=BASE_PROFILE_DIR, prefix="fftool.", suffix="") else: full_profile_dir = os.path.join(BASE_PROFILE_DIR, profile_dir) if os.path.exists(full_profile_dir): msg = "WARNING: Profile '{0}' already exists. Merging configs." Log.header(msg.format(full_profile_dir), 'XL', '-') prefs = Preferences() for path in prefs_paths(application, test_type, env): prefs.add_file(path) # Add the `fftool.profile.name` pref so we can go to about:config and see # what our current profile is. prefs.add([("fftool.profile.name", full_profile_dir)]) profile = Profile(profile=full_profile_dir, restore=False, preferences=prefs()) Log.header("Launching browser with the following user configs:") print(profile.summary()) # this is the path to the created profile return full_profile_dir
def run(self): self.profile_dir = os.path.join(tempfile.mkdtemp(suffix='.gaiaunittest'), 'profile') shutil.copytree(self.profile, self.profile_dir) cmdargs = ['--runapp', 'Test Agent'] if self.browser_arg: cmdargs += list(self.browser_arg) profile = Profile(profile=self.profile_dir) self.runner = Runner(binary=self.binary, profile=profile, clean_profile=False, cmdargs=cmdargs, symbols_path=self.symbols_path) self.runner.start()
def run(self, profile=None, timeout=PROCESS_TIMEOUT, env=None, args=None): """Runs the given FirefoxRunner with the given Profile, waits for completion, then returns the process exit code """ if profile is None: profile = Profile() self.profile = profile if self.binary is None and self.url: self.binary = self.download_build() runner = FirefoxRunner(profile=self.profile, binary=self.binary, env=env, cmdargs=args) runner.start(timeout=timeout) return runner.wait()
def start_runner(self, target, options): du = DeviceUtils(self.runner.device.dm) device = self.runner.device port = options.get('port') profile = Profile(profile=options.get('profile')) device.setup_port_forwarding(local_port=port, remote_port=port) du._stop_b2g() du._purge_data() du._purge_wifi_networks() du._purge_storage_data() self.runner.profile = profile self.runner.start() if not device.wait_for_port(port=port, timeout=600): raise Exception("Wait for port timed out")
def build_profile(self, options): # preferences prefs = {} for path in self.preferences: prefs.update(Preferences.read_prefs(path)) for v in options.extraPrefs: thispref = v.split("=", 1) if len(thispref) < 2: print "Error: syntax error in --setpref=" + v sys.exit(1) prefs[thispref[0]] = thispref[1] # interpolate the preferences interpolation = { "server": "%s:%s" % (options.webServer, options.httpPort), "OOP": "true" if self.out_of_process else "false"} prefs = json.loads(json.dumps(prefs) % interpolation) for pref in prefs: prefs[pref] = Preferences.cast(prefs[pref]) kwargs = { 'addons': self.getExtensionsToInstall(options), 'apps': self.webapps, 'locations': self.locations_file, 'preferences': prefs, 'proxy': {"remote": options.webServer} } if options.profile: self.profile = Profile.clone(options.profile, **kwargs) else: self.profile = Profile(**kwargs) options.profilePath = self.profile.profile # TODO bug 839108 - mozprofile should probably handle this manifest = self.addChromeToProfile(options) self.copyExtraFilesToProfile(options) return manifest
def tps_profile(pytestconfig, tps_addon, tps_config, tps_log, fxa_urls): preferences = { 'app.update.enabled': False, 'browser.dom.window.dump.enabled': True, 'browser.onboarding.enabled': False, 'browser.sessionstore.resume_from_crash': False, 'browser.shell.checkDefaultBrowser': False, 'browser.startup.homepage_override.mstone': 'ignore', 'browser.startup.page': 0, 'browser.tabs.warnOnClose': False, 'browser.warnOnQuit': False, 'datareporting.policy.dataSubmissionEnabled': False, # 'devtools.chrome.enabled': True, # 'devtools.debugger.remote-enabled': True, 'engine.bookmarks.repair.enabled': False, 'extensions.autoDisableScopes': 10, 'extensions.legacy.enabled': True, 'extensions.update.enabled': False, 'extensions.update.notifyUser': False, # While this line is commented prod is launched instead of stage 'identity.fxaccounts.autoconfig.uri': fxa_urls['content'], 'testing.tps.skipPingValidation': True, 'services.sync.firstSync': 'notReady', 'services.sync.lastversion': '1.0', 'services.sync.log.appender.console': 'Trace', 'services.sync.log.appender.dump': 'Trace', 'services.sync.log.appender.file.level': 'Trace', 'services.sync.log.appender.file.logOnSuccess': True, 'services.sync.log.logger': 'Trace', 'services.sync.log.logger.engine': 'Trace', 'services.sync.testing.tps': True, 'testing.tps.logFile': tps_log, 'toolkit.startup.max_resumed_crashes': -1, 'tps.config': json.dumps(tps_config), 'tps.seconds_since_epoch': int(time.time()), 'xpinstall.signatures.required': False } profile = Profile(addons=[tps_addon], preferences=preferences) pytestconfig._profile = profile.profile yield profile
def build_profile(self): """ Create a local profile with test prefs and proxy definitions and push it to the remote device. """ preferences = [ os.path.join( here, 'profile_data', 'prefs_general.js')] prefs = {} for path in preferences: prefs.update(Preferences.read_prefs(path)) interpolation = { "server": "%s:%s" % (self.options.webServer, self.options.httpPort)} prefs = json.loads(json.dumps(prefs) % interpolation) for pref in prefs: prefs[pref] = Preferences.cast(prefs[pref]) proxy = {'remote': self.options.webServer, 'http': self.options.httpPort, 'https': self.options.sslPort, 'ws': self.options.sslPort } self.profile = Profile(preferences=prefs, proxy=proxy) self.options.profilePath = self.profile.profile if self.fillCertificateDB(self.options): self.log.error("Certificate integration failed") self.device.mkdir(self.remote_profile, parents=True) self.device.push(self.profile.profile, self.remote_profile) self.log.debug("profile %s -> %s" % (str(self.profile.profile), str(self.remote_profile)))
def create_profile(self, custom_addons=[], custom_prefs=None, root=True): # Create, install and initialize the profile to be # used in the test. temp_addons = ['quitter.xpi'] temp_addons.extend(custom_addons) addons = ['%s/xpi/%s' % (os.getcwd(), addon) for addon in temp_addons] # make sure firefox isn't running when we try to # install the profile. self.dm.pkill(self.build.app_name, root=root) if isinstance(custom_prefs, dict): prefs = dict(self.preferences.items() + custom_prefs.items()) else: prefs = self.preferences profile = Profile(preferences=prefs, addons=addons) if not self.install_profile(profile): return False success = False for attempt in range(1, self.options.phone_retry_limit+1): self.loggerdeco.debug('Attempt %d Initializing profile', attempt) self.run_fennec_with_profile(self.build.app_name, self._initialize_url) if self.wait_for_fennec(): success = True break sleep(self.options.phone_retry_wait) if not success or self.handle_crashes(): self.add_failure(self.name, TestStatus.TEST_UNEXPECTED_FAIL, 'Failure initializing profile', TreeherderStatus.TESTFAILED) return success
class GeckoInstance(object): required_prefs = { "marionette.defaultPrefs.enabled": True, "marionette.logging": True, "startup.homepage_welcome_url": "about:blank", "browser.shell.checkDefaultBrowser": False, "browser.startup.page": 0, "browser.sessionstore.resume_from_crash": False, "browser.warnOnQuit": False, "browser.displayedE10SPrompt": 5, "browser.displayedE10SPrompt.1": 5, "browser.displayedE10SPrompt.2": 5, "browser.displayedE10SPrompt.3": 5, "browser.displayedE10SPrompt.4": 5, "browser.tabs.remote.autostart.1": False, "browser.tabs.remote.autostart.2": False, "dom.ipc.reportProcessHangs": False, } def __init__(self, host, port, bin, profile=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None): self.marionette_host = host self.marionette_port = port self.bin = bin # Check if it is a Profile object or a path to profile self.profile = None if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(GeckoInstance.required_prefs) if prefs: self.required_prefs.update(prefs) self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path self.gecko_log = gecko_log def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if "-jsdebugger" in self.app_args: profile_args["preferences"].update( { "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.debugger.chrome-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, } ) if hasattr(self, "profile_path") and self.profile is None: if not self.profile_path: profile_args["restore"] = False self.profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path self.profile = Profile.clone(**profile_args) process_args = {"processOutputLine": [NullOutput()]} if self.gecko_log == "-": process_args["stream"] = sys.stdout else: if self.gecko_log is None: self.gecko_log = "gecko.log" elif os.path.isdir(self.gecko_log): fname = "gecko-%d.log" % time.time() self.gecko_log = os.path.join(self.gecko_log, fname) self.gecko_log = os.path.realpath(self.gecko_log) if os.access(self.gecko_log, os.F_OK): if platform.system() is "Windows": # NOTE: windows has a weird filesystem where it happily 'closes' # the file, but complains if you try to delete it. You get a # 'file still in use' error. Sometimes you can wait a bit and # a retry will succeed. # If all retries fail, we'll just continue without removing # the file. In this case, if we are restarting the instance, # then the new logs just get appended to the old file. tries = 0 while tries < 10: try: os.remove(self.gecko_log) break except WindowsError as e: if e.errno == errno.EACCES: tries += 1 time.sleep(0.5) else: raise e else: os.remove(self.gecko_log) process_args["logfile"] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({"MOZ_CRASHREPORTER": "1", "MOZ_CRASHREPORTER_NO_REPORT": "1"}) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=["-no-remote", "-marionette"] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args, ) self.runner.start() def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): if clean: self.profile.cleanup() self.profile = None self.close(restart=True) if prefs: self.prefs = prefs else: self.prefs = None self.start()
class GeckoInstance(object): required_prefs = { "browser.sessionstore.resume_from_crash": False, "browser.shell.checkDefaultBrowser": False, "browser.startup.page": 0, "browser.tabs.remote.autostart.1": False, "browser.tabs.remote.autostart.2": False, "browser.tabs.remote.autostart": False, "browser.urlbar.userMadeSearchSuggestionsChoice": True, "browser.warnOnQuit": False, "datareporting.healthreport.logging.consoleEnabled": False, "datareporting.healthreport.service.enabled": False, "datareporting.healthreport.service.firstRun": False, "datareporting.healthreport.uploadEnabled": False, "datareporting.policy.dataSubmissionEnabled": False, "datareporting.policy.dataSubmissionPolicyAccepted": False, "dom.ipc.reportProcessHangs": False, # Only install add-ons from the profile and the application scope # Also ensure that those are not getting disabled. # see: https://developer.mozilla.org/en/Installing_extensions "extensions.enabledScopes": 5, "extensions.autoDisableScopes": 10, "focusmanager.testmode": True, "marionette.defaultPrefs.enabled": True, "startup.homepage_welcome_url": "", "startup.homepage_welcome_url.additional": "", "toolkit.telemetry.enabled": False, # Until Bug 1238095 is fixed, we have to enable CPOWs in order # for Marionette tests to work properly. "dom.ipc.cpows.forbid-unsafe-from-browser": False, } def __init__(self, host, port, bin, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None, workspace=None, verbose=0): self.runner_class = Runner self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path self.binary = bin self.marionette_host = host self.marionette_port = port # Alternative to default temporary directory self.workspace = workspace self.addons = addons # Check if it is a Profile object or a path to profile self.profile = None if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(self.required_prefs) if prefs: self.required_prefs.update(prefs) self._gecko_log_option = gecko_log self._gecko_log = None self.verbose = verbose @property def gecko_log(self): if self._gecko_log: return self._gecko_log path = self._gecko_log_option if path != '-': if path is None: path = 'gecko.log' elif os.path.isdir(path): fname = 'gecko-%d.log' % time.time() path = os.path.join(path, fname) path = os.path.realpath(path) if os.access(path, os.F_OK): os.remove(path) self._gecko_log = path return self._gecko_log def _update_profile(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons 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) def start(self): self._update_profile() self.runner = self.runner_class(**self._get_runner_args()) self.runner.start() def _get_runner_args(self): process_args = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1'}) return { 'binary': self.binary, 'profile': self.profile, 'cmdargs': ['-no-remote', '-marionette'] + self.app_args, 'env': env, 'symbols_path': self.symbols_path, 'process_args': process_args } def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): self.close(restart=True) if clean and self.profile: self.profile.cleanup() self.profile = None if prefs: self.prefs = prefs else: self.prefs = None self.start()
class GeckoInstance(object): required_prefs = { "browser.sessionstore.resume_from_crash": False, "browser.shell.checkDefaultBrowser": False, # Needed for branded builds to prevent opening a second tab on startup "browser.startup.homepage_override.mstone": "ignore", "browser.startup.page": 0, "browser.tabs.remote.autostart.1": False, "browser.tabs.remote.autostart.2": False, "browser.tabs.remote.autostart": False, "browser.urlbar.userMadeSearchSuggestionsChoice": True, "browser.warnOnQuit": False, "datareporting.healthreport.logging.consoleEnabled": False, "datareporting.healthreport.service.enabled": False, "datareporting.healthreport.service.firstRun": False, "datareporting.healthreport.uploadEnabled": False, "datareporting.policy.dataSubmissionEnabled": False, "datareporting.policy.dataSubmissionPolicyAccepted": False, "dom.ipc.reportProcessHangs": False, # Only install add-ons from the profile and the application scope # Also ensure that those are not getting disabled. # see: https://developer.mozilla.org/en/Installing_extensions "extensions.enabledScopes": 5, "extensions.autoDisableScopes": 10, "focusmanager.testmode": True, "marionette.defaultPrefs.enabled": True, "startup.homepage_welcome_url": "", "startup.homepage_welcome_url.additional": "", "toolkit.telemetry.enabled": False, # Until Bug 1238095 is fixed, we have to enable CPOWs in order # for Marionette tests to work properly. "dom.ipc.cpows.forbid-unsafe-from-browser": False, } def __init__(self, host, port, bin, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None, workspace=None, verbose=0): self.runner_class = Runner self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path self.binary = bin self.marionette_host = host self.marionette_port = port # Alternative to default temporary directory self.workspace = workspace self.addons = addons # Check if it is a Profile object or a path to profile self.profile = None if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(self.required_prefs) if prefs: self.required_prefs.update(prefs) self._gecko_log_option = gecko_log self._gecko_log = None self.verbose = verbose @property def gecko_log(self): if self._gecko_log: return self._gecko_log path = self._gecko_log_option if path != '-': if path is None: path = 'gecko.log' elif os.path.isdir(path): fname = 'gecko-{}.log'.format(time.time()) path = os.path.join(path, fname) path = os.path.realpath(path) if os.access(path, os.F_OK): os.remove(path) self._gecko_log = path return self._gecko_log def _update_profile(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons 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) def start(self): self._update_profile() self.runner = self.runner_class(**self._get_runner_args()) self.runner.start() def _get_runner_args(self): process_args = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_CRASHREPORTER_SHUTDOWN': '1', }) return { 'binary': self.binary, 'profile': self.profile, 'cmdargs': ['-no-remote', '-marionette'] + self.app_args, 'env': env, 'symbols_path': self.symbols_path, 'process_args': process_args } def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): self.close(restart=True) if clean and self.profile: self.profile.cleanup() self.profile = None if prefs: self.prefs = prefs else: self.prefs = None self.start()
def run_single_test(self, testdir, testname): testpath = os.path.join(testdir, testname) self.log("Running test %s\n" % testname, True) # Read and parse the test file, merge it with the contents of the config # file, and write the combined output to a temporary file. f = open(testpath, 'r') testcontent = f.read() f.close() # We use yaml to parse the tests because it is a superset of json # but tolerates things like property names not being quoted, trailing # commas, etc. try: test = yaml.safe_load(testcontent) except Exception: test = yaml.safe_load( testcontent[testcontent.find('{'):testcontent.find('}') + 1]) self.preferences['tps.seconds_since_epoch'] = int(time.time()) # generate the profiles defined in the test, and a list of test phases profiles = {} phaselist = [] for phase in test: profilename = test[phase] # create the profile if necessary if profilename not in profiles: profiles[profilename] = Profile( preferences=self.preferences.copy(), addons=self.extensions) # create the test phase phaselist.append( TPSTestPhase(phase, profiles[profilename], testname, testpath, self.logfile, self.env, self.firefoxRunner, self.log, ignore_unused_engines=self.ignore_unused_engines)) # sort the phase list by name phaselist = sorted(phaselist, key=lambda phase: phase.phase) # run each phase in sequence, aborting at the first failure failed = False for phase in phaselist: phase.run() if phase.status != 'PASS': failed = True break for profilename in profiles: print("### Cleanup Profile ", profilename) cleanup_phase = TPSTestPhase('cleanup-' + profilename, profiles[profilename], testname, testpath, self.logfile, self.env, self.firefoxRunner, self.log) cleanup_phase.run() if cleanup_phase.status != 'PASS': failed = True # Keep going to run the remaining cleanup phases. if failed: self.handle_phase_failure(profiles) # grep the log for FF and sync versions f = open(self.logfile) logdata = f.read() match = self.syncVerRe.search(logdata) sync_version = match.group('syncversion') if match else 'unknown' match = self.ffVerRe.search(logdata) firefox_version = match.group('ffver') if match else 'unknown' match = self.ffBuildIDRe.search(logdata) firefox_buildid = match.group('ffbuildid') if match else 'unknown' f.close() if phase.status == 'PASS': logdata = '' else: # we only care about the log data for this specific test logdata = logdata[logdata.find('Running test %s' % (str(testname))):] result = { 'PASS': lambda x: ('TEST-PASS', ''), 'FAIL': lambda x: ('TEST-UNEXPECTED-FAIL', x.rstrip()), 'unknown': lambda x: ('TEST-UNEXPECTED-FAIL', 'test did not complete') }[phase.status](phase.errline) logstr = "\n%s | %s%s\n" % (result[0], testname, (' | %s' % result[1] if result[1] else '')) try: repoinfo = mozversion.get_version(self.binary) except Exception: repoinfo = {} apprepo = repoinfo.get('application_repository', '') appchangeset = repoinfo.get('application_changeset', '') # save logdata to a temporary file for posting to the db tmplogfile = None if logdata: tmplogfile = TempFile(prefix='tps_log_') tmplogfile.write(logdata) tmplogfile.close() self.errorlogs[testname] = tmplogfile resultdata = ({ 'productversion': { 'version': firefox_version, 'buildid': firefox_buildid, 'builddate': firefox_buildid[0:8], 'product': 'Firefox', 'repository': apprepo, 'changeset': appchangeset, }, 'addonversion': { 'version': sync_version, 'product': 'Firefox Sync' }, 'name': testname, 'message': result[1], 'state': result[0], 'logdata': logdata }) self.log(logstr, True) for phase in phaselist: print("\t{}: {}".format(phase.phase, phase.status)) return resultdata
class GeckoInstance(object): required_prefs = { # Increase the APZ content response timeout in tests to 1 minute. # This is to accommodate the fact that test environments tends to be slower # than production environments (with the b2g emulator being the slowest of them # all), resulting in the production timeout value sometimes being exceeded # and causing false-positive test failures. See bug 1176798, bug 1177018, # bug 1210465. "apz.content_response_timeout": 60000, # Do not send Firefox health reports to the production server "datareporting.healthreport.documentServerURI": "http://%(server)s/dummy/healthreport/", "datareporting.healthreport.about.reportUrl": "http://%(server)s/dummy/abouthealthreport/", # Do not show datareporting policy notifications which can interfer with tests "datareporting.policy.dataSubmissionPolicyBypassNotification": True, # Until Bug 1238095 is fixed, we have to enable CPOWs in order # for Marionette tests to work properly. "dom.ipc.cpows.forbid-unsafe-from-browser": False, "dom.ipc.reportProcessHangs": False, # No slow script dialogs "dom.max_chrome_script_run_time": 0, "dom.max_script_run_time": 0, # Only load extensions from the application and user profile # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION "extensions.autoDisableScopes": 0, "extensions.enabledScopes": 5, # don't block add-ons for e10s "extensions.e10sBlocksEnabling": False, # Disable metadata caching for installed add-ons by default "extensions.getAddons.cache.enabled": False, # Disable intalling any distribution add-ons "extensions.installDistroAddons": False, "extensions.showMismatchUI": False, # Turn off extension updates so they don't bother tests "extensions.update.enabled": False, "extensions.update.notifyUser": False, # Make sure opening about:addons won"t hit the network "extensions.webservice.discoverURL": "http://%(server)s/dummy/discoveryURL", # Allow the application to have focus even it runs in the background "focusmanager.testmode": True, # Disable useragent updates "general.useragent.updates.enabled": False, # Always use network provider for geolocation tests # so we bypass the OSX dialog raised by the corelocation provider "geo.provider.testing": True, # Do not scan Wifi "geo.wifi.scan": False, # No hang monitor "hangmonitor.timeout": 0, "javascript.options.showInConsole": True, "marionette.defaultPrefs.enabled": True, "media.volume_scale": "0.01", # Make sure the disk cache doesn't get auto disabled "network.http.bypass-cachelock-threshold": 200000, # Do not prompt for temporary redirects "network.http.prompt-temp-redirect": False, # Disable speculative connections so they aren"t reported as leaking when they"re # hanging around "network.http.speculative-parallel-limit": 0, # Do not automatically switch between offline and online "network.manage-offline-status": False, # Make sure SNTP requests don't hit the network "network.sntp.pools": "%(server)s", # Tests don't wait for the notification button security delay "security.notification_enable_delay": 0, # Ensure blocklist updates don't hit the network "services.settings.server": "http://%(server)s/dummy/blocklist/", # Disable password capture, so that tests that include forms aren"t # influenced by the presence of the persistent doorhanger notification "signon.rememberSignons": False, # Prevent starting into safe mode after application crashes "toolkit.startup.max_resumed_crashes": -1, # We want to collect telemetry, but we don't want to send in the results "toolkit.telemetry.server": "https://%(server)s/dummy/telemetry/", } def __init__(self, host=None, port=None, bin=None, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None, workspace=None, verbose=0): self.runner_class = Runner self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path self.binary = bin self.marionette_host = host self.marionette_port = port # Alternative to default temporary directory self.workspace = workspace self.addons = addons # Check if it is a Profile object or a path to profile self.profile = None if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(self.required_prefs) if prefs: self.required_prefs.update(prefs) self._gecko_log_option = gecko_log self._gecko_log = None self.verbose = verbose @property def gecko_log(self): if self._gecko_log: return self._gecko_log path = self._gecko_log_option if path != "-": if path is None: path = "gecko.log" elif os.path.isdir(path): fname = "gecko-{}.log".format(time.time()) path = os.path.join(path, fname) path = os.path.realpath(path) if os.access(path, os.F_OK): os.remove(path) self._gecko_log = path return self._gecko_log def _update_profile(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if "-jsdebugger" in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args["addons"] = self.addons 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) @classmethod def create(cls, app=None, *args, **kwargs): try: if not app: app_id = mozversion.get_version(binary=kwargs.get('bin'))['application_id'] app = app_ids[app_id] instance_class = apps[app] except KeyError: msg = 'Application "{0}" unknown (should be one of {1})' raise NotImplementedError(msg.format(app, apps.keys())) return instance_class(*args, **kwargs) def start(self): self._update_profile() self.runner = self.runner_class(**self._get_runner_args()) self.runner.start() def _get_runner_args(self): process_args = { "processOutputLine": [NullOutput()], } if self.gecko_log == "-": process_args["stream"] = sys.stdout else: process_args["logfile"] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({"MOZ_CRASHREPORTER": "1", "MOZ_CRASHREPORTER_NO_REPORT": "1", "MOZ_CRASHREPORTER_SHUTDOWN": "1", }) return { "binary": self.binary, "profile": self.profile, "cmdargs": ["-no-remote", "-marionette"] + self.app_args, "env": env, "symbols_path": self.symbols_path, "process_args": process_args } def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): self.close(restart=True) if clean and self.profile: self.profile.cleanup() self.profile = None if prefs: self.prefs = prefs else: self.prefs = None self.start()
def test_with_profile_should_cleanup(): with Profile() as profile: assert os.path.exists(profile.profile) # profile is cleaned assert not os.path.exists(profile.profile)
class GeckoInstance(object): required_prefs = { # Increase the APZ content response timeout in tests to 1 minute. # This is to accommodate the fact that test environments tends to be slower # than production environments (with the b2g emulator being the slowest of them # all), resulting in the production timeout value sometimes being exceeded # and causing false-positive test failures. See bug 1176798, bug 1177018, # bug 1210465. "apz.content_response_timeout": 60000, # Do not send Firefox health reports to the production server "datareporting.healthreport.documentServerURI": "http://%(server)s/dummy/healthreport/", "datareporting.healthreport.about.reportUrl": "http://%(server)s/dummy/abouthealthreport/", # Do not show datareporting policy notifications which can interfer with tests "datareporting.policy.dataSubmissionPolicyBypassNotification": True, "dom.ipc.reportProcessHangs": False, # No slow script dialogs "dom.max_chrome_script_run_time": 0, "dom.max_script_run_time": 0, # Only load extensions from the application and user profile # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION "extensions.autoDisableScopes": 0, "extensions.enabledScopes": 5, # don't block add-ons for e10s "extensions.e10sBlocksEnabling": False, # Disable metadata caching for installed add-ons by default "extensions.getAddons.cache.enabled": False, # Disable intalling any distribution add-ons "extensions.installDistroAddons": False, "extensions.showMismatchUI": False, # Turn off extension updates so they don't bother tests "extensions.update.enabled": False, "extensions.update.notifyUser": False, # Make sure opening about:addons won"t hit the network "extensions.webservice.discoverURL": "http://%(server)s/dummy/discoveryURL", # Allow the application to have focus even it runs in the background "focusmanager.testmode": True, # Disable useragent updates "general.useragent.updates.enabled": False, # Always use network provider for geolocation tests # so we bypass the OSX dialog raised by the corelocation provider "geo.provider.testing": True, # Do not scan Wifi "geo.wifi.scan": False, # No hang monitor "hangmonitor.timeout": 0, "javascript.options.showInConsole": True, # Enable Marionette component # (deprecated and can be removed when Firefox 60 ships) "marionette.enabled": True, "marionette.defaultPrefs.enabled": True, # Disable recommended automation prefs in CI "marionette.prefs.recommended": False, "media.volume_scale": "0.01", # Do not prompt for temporary redirects "network.http.prompt-temp-redirect": False, # Disable speculative connections so they aren"t reported as leaking when they"re # hanging around "network.http.speculative-parallel-limit": 0, # Do not automatically switch between offline and online "network.manage-offline-status": False, # Make sure SNTP requests don't hit the network "network.sntp.pools": "%(server)s", # Tests don't wait for the notification button security delay "security.notification_enable_delay": 0, # Ensure blocklist updates don't hit the network "services.settings.server": "http://%(server)s/dummy/blocklist/", # Disable password capture, so that tests that include forms aren"t # influenced by the presence of the persistent doorhanger notification "signon.rememberSignons": False, # Prevent starting into safe mode after application crashes "toolkit.startup.max_resumed_crashes": -1, # We want to collect telemetry, but we don't want to send in the results "toolkit.telemetry.server": "https://%(server)s/dummy/telemetry/", # Enabling the support for File object creation in the content process. "dom.file.createInChild": True, } def __init__(self, host=None, port=None, bin=None, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None, workspace=None, verbose=0, headless=False): self.runner_class = Runner self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path self.binary = bin self.marionette_host = host self.marionette_port = port # Alternative to default temporary directory self.workspace = workspace self.addons = addons # Check if it is a Profile object or a path to profile self.profile = None if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(self.required_prefs) if prefs: self.required_prefs.update(prefs) self._gecko_log_option = gecko_log self._gecko_log = None self.verbose = verbose self.headless = headless @property def gecko_log(self): if self._gecko_log: return self._gecko_log path = self._gecko_log_option if path != "-": if path is None: path = "gecko.log" elif os.path.isdir(path): fname = "gecko-{}.log".format(time.time()) path = os.path.join(path, fname) path = os.path.realpath(path) if os.access(path, os.F_OK): os.remove(path) self._gecko_log = path return self._gecko_log def _update_profile(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"][ "marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if "-jsdebugger" in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args["addons"] = self.addons 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) @classmethod def create(cls, app=None, *args, **kwargs): try: if not app and kwargs["bin"] is not None: app_id = mozversion.get_version( binary=kwargs["bin"])["application_id"] app = app_ids[app_id] instance_class = apps[app] except (IOError, KeyError): exc, val, tb = sys.exc_info() msg = 'Application "{0}" unknown (should be one of {1})' raise NotImplementedError, msg.format(app, apps.keys()), tb return instance_class(*args, **kwargs) def start(self): self._update_profile() self.runner = self.runner_class(**self._get_runner_args()) self.runner.start() def _get_runner_args(self): process_args = { "processOutputLine": [NullOutput()], } if self.gecko_log == "-": process_args["stream"] = sys.stdout else: process_args["logfile"] = self.gecko_log env = os.environ.copy() if self.headless: env["MOZ_HEADLESS"] = "1" env["DISPLAY"] = "77" # Set a fake display. # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ "MOZ_CRASHREPORTER": "1", "MOZ_CRASHREPORTER_NO_REPORT": "1", "MOZ_CRASHREPORTER_SHUTDOWN": "1", }) return { "binary": self.binary, "profile": self.profile, "cmdargs": ["-no-remote", "-marionette"] + self.app_args, "env": env, "symbols_path": self.symbols_path, "process_args": process_args } def close(self, clean=False): """ Close the managed Gecko process. Depending on self.runner_class, setting `clean` to True may also kill the emulator process in which this instance is running. :param clean: If True, also perform runner cleanup. """ if self.runner: self.runner.stop() if clean: self.runner.cleanup() if clean and self.profile: self.profile.cleanup() self.profile = None def restart(self, prefs=None, clean=True): """ Close then start the managed Gecko process. :param prefs: Dictionary of preference names and values. :param clean: If True, reset the profile before starting. """ self.close(clean=clean) if prefs: self.prefs = prefs else: self.prefs = None self.start()
class GeckoInstance(object): required_prefs = {"marionette.defaultPrefs.enabled": True, "marionette.logging": True, "browser.displayedE10SPrompt": 5, "browser.displayedE10SPrompt.1": 5, "browser.displayedE10SPrompt.2": 5, "browser.displayedE10SPrompt.3": 5, "browser.displayedE10SPrompt.4": 5, "browser.sessionstore.resume_from_crash": False, "browser.shell.checkDefaultBrowser": False, "browser.startup.page": 0, "browser.tabs.remote.autostart.1": False, "browser.tabs.remote.autostart.2": False, "browser.warnOnQuit": False, "dom.ipc.reportProcessHangs": False, "focusmanager.testmode": True, "startup.homepage_welcome_url": "about:blank"} def __init__(self, host, port, bin, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None): self.marionette_host = host self.marionette_port = port self.bin = bin # Check if it is a Profile object or a path to profile self.profile = None self.addons = addons if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(GeckoInstance.required_prefs) if prefs: self.required_prefs.update(prefs) self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path if gecko_log != '-': if gecko_log is None: gecko_log = 'gecko.log' elif os.path.isdir(gecko_log): fname = 'gecko-%d.log' % time.time() gecko_log = os.path.join(gecko_log, fname) gecko_log = os.path.realpath(gecko_log) if os.access(gecko_log, os.F_OK): os.remove(gecko_log) self.gecko_log = gecko_log def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons if hasattr(self, "profile_path") and self.profile is None: if not self.profile_path: self.profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path self.profile = Profile.clone(**profile_args) process_args = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args) self.runner.start() def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): self.close(restart=True) if clean: self.profile.cleanup() self.profile = None if prefs: self.prefs = prefs else: self.prefs = None self.start()
class GeckoInstance(object): required_prefs = { "browser.displayedE10SPrompt.1": 5, "browser.displayedE10SPrompt.2": 5, "browser.displayedE10SPrompt.3": 5, "browser.displayedE10SPrompt.4": 5, "browser.displayedE10SPrompt": 5, "browser.sessionstore.resume_from_crash": False, "browser.shell.checkDefaultBrowser": False, "browser.startup.page": 0, "browser.tabs.remote.autostart.1": False, "browser.tabs.remote.autostart.2": False, "browser.tabs.remote.autostart": False, "browser.urlbar.userMadeSearchSuggestionsChoice": True, "browser.warnOnQuit": False, "datareporting.healthreport.logging.consoleEnabled": False, "datareporting.healthreport.service.enabled": False, "datareporting.healthreport.service.firstRun": False, "datareporting.healthreport.uploadEnabled": False, "datareporting.policy.dataSubmissionEnabled": False, "datareporting.policy.dataSubmissionPolicyAccepted": False, "dom.ipc.reportProcessHangs": False, "focusmanager.testmode": True, "marionette.defaultPrefs.enabled": True, "startup.homepage_welcome_url": "about:blank", "toolkit.telemetry.enabled": False, } def __init__(self, host, port, bin, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None, workspace=None, verbose=0): 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 if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(GeckoInstance.required_prefs) if prefs: self.required_prefs.update(prefs) self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path if gecko_log != '-': if gecko_log is None: gecko_log = 'gecko.log' elif os.path.isdir(gecko_log): fname = 'gecko-%d.log' % time.time() gecko_log = os.path.join(gecko_log, fname) gecko_log = os.path.realpath(gecko_log) if os.access(gecko_log, os.F_OK): os.remove(gecko_log) self.gecko_log = gecko_log self.verbose = verbose def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if '-jsdebugger' in self.app_args: profile_args["preferences"].update({ "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, }) if self.addons: profile_args['addons'] = self.addons 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 = { 'processOutputLine': [NullOutput()], } if self.gecko_log == '-': process_args['stream'] = sys.stdout else: process_args['logfile'] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({ 'MOZ_CRASHREPORTER': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', }) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=['-no-remote', '-marionette'] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args) self.runner.start() def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): self.close(restart=True) if clean: self.profile.cleanup() self.profile = None if prefs: self.prefs = prefs else: self.prefs = None self.start()
def test_with_profile_should_cleanup(self): with Profile() as profile: self.assertTrue(os.path.exists(profile.profile)) # profile is cleaned self.assertFalse(os.path.exists(profile.profile))
def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if "-jsdebugger" in self.app_args: profile_args["preferences"].update( { "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.debugger.chrome-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, } ) if hasattr(self, "profile_path") and self.profile is None: if not self.profile_path: profile_args["restore"] = False self.profile = Profile(**profile_args) else: profile_args["path_from"] = self.profile_path self.profile = Profile.clone(**profile_args) process_args = {"processOutputLine": [NullOutput()]} if self.gecko_log == "-": process_args["stream"] = sys.stdout else: if self.gecko_log is None: self.gecko_log = "gecko.log" elif os.path.isdir(self.gecko_log): fname = "gecko-%d.log" % time.time() self.gecko_log = os.path.join(self.gecko_log, fname) self.gecko_log = os.path.realpath(self.gecko_log) if os.access(self.gecko_log, os.F_OK): if platform.system() is "Windows": # NOTE: windows has a weird filesystem where it happily 'closes' # the file, but complains if you try to delete it. You get a # 'file still in use' error. Sometimes you can wait a bit and # a retry will succeed. # If all retries fail, we'll just continue without removing # the file. In this case, if we are restarting the instance, # then the new logs just get appended to the old file. tries = 0 while tries < 10: try: os.remove(self.gecko_log) break except WindowsError as e: if e.errno == errno.EACCES: tries += 1 time.sleep(0.5) else: raise e else: os.remove(self.gecko_log) process_args["logfile"] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({"MOZ_CRASHREPORTER": "1", "MOZ_CRASHREPORTER_NO_REPORT": "1"}) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=["-no-remote", "-marionette"] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args, ) self.runner.start()
class GeckoInstance(object): required_prefs = { "browser.sessionstore.resume_from_crash": False, "browser.shell.checkDefaultBrowser": False, "browser.startup.page": 0, "browser.tabs.remote.autostart.1": False, "browser.tabs.remote.autostart.2": False, "browser.tabs.remote.autostart": False, "browser.urlbar.userMadeSearchSuggestionsChoice": True, "browser.warnOnQuit": False, "datareporting.healthreport.logging.consoleEnabled": False, "datareporting.healthreport.service.enabled": False, "datareporting.healthreport.service.firstRun": False, "datareporting.healthreport.uploadEnabled": False, "datareporting.policy.dataSubmissionEnabled": False, "datareporting.policy.dataSubmissionPolicyAccepted": False, "dom.ipc.reportProcessHangs": False, # Only install add-ons from the profile and the application scope # Also ensure that those are not getting disabled. # see: https://developer.mozilla.org/en/Installing_extensions "extensions.enabledScopes": 5, "extensions.autoDisableScopes": 10, "focusmanager.testmode": True, "marionette.defaultPrefs.enabled": True, "startup.homepage_welcome_url": "about:blank", "toolkit.telemetry.enabled": False, # Until Bug 1238095 is fixed, we have to enable CPOWs in order # for Marionette tests to work properly. "dom.ipc.cpows.forbid-unsafe-from-browser": False, } def __init__( self, host, port, bin, profile=None, addons=None, app_args=None, symbols_path=None, gecko_log=None, prefs=None, workspace=None, verbose=0, ): 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 if isinstance(profile, Profile): self.profile = profile else: self.profile_path = profile self.prefs = prefs self.required_prefs = deepcopy(GeckoInstance.required_prefs) if prefs: self.required_prefs.update(prefs) self.app_args = app_args or [] self.runner = None self.symbols_path = symbols_path if gecko_log != "-": if gecko_log is None: gecko_log = "gecko.log" elif os.path.isdir(gecko_log): fname = "gecko-%d.log" % time.time() gecko_log = os.path.join(gecko_log, fname) gecko_log = os.path.realpath(gecko_log) if os.access(gecko_log, os.F_OK): os.remove(gecko_log) self.gecko_log = gecko_log self.verbose = verbose def start(self): profile_args = {"preferences": deepcopy(self.required_prefs)} profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port if self.prefs: profile_args["preferences"].update(self.prefs) if self.verbose: level = "TRACE" if self.verbose >= 2 else "DEBUG" profile_args["preferences"]["marionette.logging"] = level if "-jsdebugger" in self.app_args: profile_args["preferences"].update( { "devtools.browsertoolbox.panel": "jsdebugger", "devtools.debugger.remote-enabled": True, "devtools.chrome.enabled": True, "devtools.debugger.prompt-connection": False, "marionette.debugging.clicktostart": True, } ) if self.addons: profile_args["addons"] = self.addons 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 = {"processOutputLine": [NullOutput()]} if self.gecko_log == "-": process_args["stream"] = sys.stdout else: process_args["logfile"] = self.gecko_log env = os.environ.copy() # environment variables needed for crashreporting # https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting env.update({"MOZ_CRASHREPORTER": "1", "MOZ_CRASHREPORTER_NO_REPORT": "1"}) self.runner = Runner( binary=self.bin, profile=self.profile, cmdargs=["-no-remote", "-marionette"] + self.app_args, env=env, symbols_path=self.symbols_path, process_args=process_args, ) self.runner.start() def close(self, restart=False): if not restart: self.profile = None if self.runner: self.runner.stop() self.runner.cleanup() def restart(self, prefs=None, clean=True): self.close(restart=True) if clean: self.profile.cleanup() self.profile = None if prefs: self.prefs = prefs else: self.prefs = None self.start()