def setUp(self): # start server self.loop_test_servers = LoopTestServers() MarionetteTestCase.setUp(self) LoopTestDriver.setUp(self, self.marionette) # Although some of these preferences might require restart, we don't # use enforce_gecko_prefs (which would restart), as we need to restart # for the add-on installation anyway. self.marionette.set_prefs(FIREFOX_PREFERENCES) xpi_file = os.environ.get("LOOP_XPI_FILE") if xpi_file: addons = Addons(self.marionette) # XXX We should really use temp=True here, but due to the later # restart to ensure the add-on is installed correctly, this won't work # at the moment. What we need is a fully restartless add-on - bug 1229352 # at which point we should be able to make this install temporarily # and after the restart. addons.install(os.path.abspath(xpi_file)) self.e10s_enabled = os.environ.get("TEST_E10S") == "1" # Restart the browser nicely, so the preferences and add-on installation # take full effect. self.marionette.restart(in_app=True) # this is browser chrome, kids, not the content window just yet self.marionette.set_context("chrome")
def launch(self, _job, task): """Launch the browser""" self.connected = False self.extension = MessageServer() self.extension.start() from marionette_driver.marionette import Marionette from marionette_driver.addons import Addons args = [ '-profile', '"{0}"'.format(task['profile']), '-no-remote', '-marionette', 'about:blank' ] if self.path.find(' ') > -1: command_line = '"{0}"'.format(self.path) else: command_line = self.path command_line += ' ' + ' '.join(args) DesktopBrowser.launch_browser(self, command_line) self.marionette = Marionette('localhost', port=2828) self.marionette.start_session(timeout=self.task['time_limit']) logging.debug('Installing extension') self.addons = Addons(self.marionette) extension_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'support', 'Firefox', 'extension') self.extension_id = self.addons.install(extension_path, temp=True) logging.debug('Resizing browser to %dx%d', task['width'], task['height']) self.marionette.set_window_position(x=0, y=0) self.marionette.set_window_size(height=task['height'], width=task['width']) self.marionette.navigate(START_PAGE) time.sleep(0.5) self.wait_for_extension() if self.connected: DesktopBrowser.wait_for_idle(self)
def install_addon(self): """Install a minimal addon and add its ID to self.addon_ids.""" resources_dir = os.path.join(os.path.dirname(__file__), "resources") addon_path = os.path.abspath(os.path.join(resources_dir, "helloworld")) try: # Ensure the Environment has init'd so the installed addon # triggers an "environment-change" ping. script = """\ let [resolve] = arguments; Cu.import("resource://gre/modules/TelemetryEnvironment.jsm"); TelemetryEnvironment.onInitialized().then(resolve); """ with self.marionette.using_context(self.marionette.CONTEXT_CHROME): self.marionette.execute_async_script(textwrap.dedent(script)) addons = Addons(self.marionette) addon_id = addons.install(addon_path, temp=True) except MarionetteException as e: self.fail("{} - Error installing addon: {} - ".format( e.cause, e.message)) else: self.addon_ids.append(addon_id)
def setup(self, runner): super(MarionetteTestharnessExecutor, self).setup(runner) for extension_path in self.install_extensions: self.logger.info("Installing extension from %s" % extension_path) addons = Addons(self.protocol.marionette) addons.install(extension_path) self.protocol.testharness.load_runner(self.last_environment["protocol"])
def install_extension_with_service_worker(self): addons = Addons(self.marionette) test_extension_path = os.path.join(os.path.dirname(self.filepath), "data", EXT_DIR_PATH) addons.install(test_extension_path, temp=True) self.test_extension_base_url = self.get_extension_url() Wait(self.marionette).until( lambda _: self.is_extension_service_worker_registered, message="Wait the extension service worker to be registered")
def launch(self, job, task): """Launch the browser""" if self.job['message_server'] is not None: self.job['message_server'].flush_messages() self.connected = False from marionette_driver.marionette import Marionette from marionette_driver.addons import Addons args = [ '-profile', '"{0}"'.format(task['profile']), '-no-remote', '-marionette', 'about:blank' ] if self.path.find(' ') > -1: command_line = '"{0}"'.format(self.path) else: command_line = self.path command_line += ' ' + ' '.join(args) DesktopBrowser.launch_browser(self, command_line) try: self.marionette = Marionette('localhost', port=2828) self.marionette.start_session(timeout=self.task['time_limit']) self.configure_prefs() logging.debug('Installing extension') self.addons = Addons(self.marionette) extension_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'support', 'Firefox', 'extension') self.extension_id = self.addons.install(extension_path, temp=True) logging.debug('Resizing browser to %dx%d', task['width'], task['height']) self.marionette.set_window_position(x=0, y=0) self.marionette.set_window_size(height=task['height'], width=task['width']) if 'browserVersion' in self.marionette.session_capabilities: self.browser_version = self.marionette.session_capabilities[ 'browserVersion'] self.marionette.navigate(self.start_page) time.sleep(0.5) self.wait_for_extension() if self.connected: # Override the UA String if necessary ua_string = self.execute_js('navigator.userAgent;') modified = False if 'uastring' in self.job: ua_string = self.job['uastring'] modified = True if ua_string is not None and 'AppendUA' in task: ua_string += ' ' + task['AppendUA'] modified = True if modified: logging.debug(ua_string) self.marionette.set_pref('general.useragent.override', ua_string) # Wait for the browser startup to finish DesktopBrowser.wait_for_idle(self) except Exception as err: task['error'] = 'Error starting Firefox: {0}'.format(err.__str__())
def install_addon(self): """Install a minimal addon.""" resources_dir = os.path.join(os.path.dirname(__file__), "resources") addon_path = os.path.abspath(os.path.join(resources_dir, "helloworld")) try: addons = Addons(self.marionette) addons.install(addon_path, temp=True) except MarionetteException as e: self.fail("{} - Error installing addon: {} - ".format( e.cause, e.message))
def _install_addon(self): # The addon that gets installed here is the easyscreenshot addon taken from AMO. # It has high compatibility with firefox and doesn't cause any adverse side affects that # could affect our tests like tabs opening, etc. # Developed by: MozillaOnline # Addon URL: https://addons.mozilla.org/en-US/firefox/addon/easyscreenshot/ try: addon_path = os.path.join(resources_dir, 'easyscreenshot.xpi') addons = Addons(self.marionette) addons.install(addon_path) except MarionetteException as e: self.fail('{} - Error installing addon: {} - '.format( e.cause, e.message))
def test_initial_installation(self): m = self.marionette b = self.browser # Navigate to the site and click the install button with m.using_context(m.CONTEXT_CONTENT): m.navigate(SITE_URL) m.find_element(By.CSS_SELECTOR, 'button.install').click() w = Wait(m, ignored_exceptions=NoSuchElementException) w.until(lambda m: m.find_element(By.CSS_SELECTOR, 'button.install.state-change')) # HACK: Checking _visibility_ of chrome elements, like notifications, # is known to be buggy. Padding the wait_for_notification call with # sleeps is the current workaround. See https://bugzil.la/1094246#c17 time.sleep(15) # Click through the blocked notification b.wait_for_notification(AddOnInstallBlockedNotification, timeout=60) # HACK: Things seem to fail intermittently here if we don't wait a tick time.sleep(5) b.notification.allow_button.click() # Click through the installation notification b.wait_for_notification(AddOnInstallConfirmationNotification) b.notification.install_button().click() # Wait for and close the completion notification b.wait_for_notification(AddOnInstallCompleteNotification, timeout=60) b.notification.close() # The toolbar button should show up soon after installation with m.using_context(m.CONTEXT_CHROME): w = Wait(m, ignored_exceptions=NoSuchElementException) w.until(lambda m: m.find_element('id', target=TOOLBAR_BUTTON_ID)) # And the add-on should open up an onboarding tab... Wait(m).until(lambda m: len(b.tabbar.tabs) > 1) next_tab_loc = b.tabbar.tabs[1].location self.assertTrue( next_tab_loc.endswith('/onboarding') or next_tab_loc.endswith('/onboarding/')) b.tabbar.close_tab(b.tabbar.tabs[1]) # The frontend should show a list of experiments after it contacts the add-on with m.using_context(m.CONTEXT_CONTENT): w = Wait(m, ignored_exceptions=NoSuchElementException) w.until( lambda m: m.find_element(By.CSS_SELECTOR, 'div.experiments')) # Clean up by uninstalling the add-on Addons(m).uninstall('@testpilot-addon')
def test_initial_installation(self): m = self.marionette b = self.browser # Navigate to the site and click the install button with m.using_context(m.CONTEXT_CONTENT): m.navigate(SITE_URL) m.find_element(By.CSS_SELECTOR, 'button[data-hook=install]').click() w = Wait(m, ignored_exceptions=NoSuchElementException) w.until(lambda m: m.find_element(By.CSS_SELECTOR, 'button[data-hook=install].state-change')) # Click through the blocked notification b.wait_for_notification(AddOnInstallBlockedNotification, timeout=60) # HACK: Things seem to fail intermittently here if we don't wait a tick time.sleep(0.5) b.notification.allow_button.click() # Click through the installation notification b.wait_for_notification(AddOnInstallConfirmationNotification) b.notification.install_button().click() # Wait for and close the completion notification b.wait_for_notification(AddOnInstallCompleteNotification, timeout=60) b.notification.close() # The toolbar button should show up soon after installation with m.using_context(m.CONTEXT_CHROME): w = Wait(m, ignored_exceptions=NoSuchElementException) w.until(lambda m: m.find_element('id', target=TOOLBAR_BUTTON_ID)) # And the add-on should open up an onboarding tab... Wait(m).until(lambda m: len(b.tabbar.tabs) > 1) next_tab_loc = b.tabbar.tabs[1].location self.assertTrue(next_tab_loc.endswith('/onboarding') or next_tab_loc.endswith('/onboarding/')) b.tabbar.close_tab(b.tabbar.tabs[1]) # The frontend should redirect to /experiments after it contacts the add-on Wait(m).until(lambda m: b.tabbar.tabs[0].location.endswith('/experiments') or b.tabbar.tabs[0].location.endswith('/experiments/')) # Clean up by uninstalling the add-on Addons(m).uninstall('@testpilot-addon')
def runApp(self, profile, binary, cmdargs, env, timeout=None, debuggerInfo=None, symbolsPath=None, options=None, valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None): def timeoutHandler(): self.handleTimeout(timeout, proc, options.utilityPath, debuggerInfo) interactive = False debug_args = None if debuggerInfo: interactive = debuggerInfo.interactive debug_args = [debuggerInfo.path] + debuggerInfo.args def record_last_test(message): """Records the last test seen by this harness for the benefit of crash logging.""" if message['action'] == 'test_start': if " " in message['test']: self.lastTestSeen = message['test'].split(" ")[0] else: self.lastTestSeen = message['test'] self.log.add_handler(record_last_test) outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=symbolsPath) kp_kwargs = { 'kill_on_timeout': False, 'cwd': SCRIPT_DIRECTORY, 'onTimeout': [timeoutHandler], 'processOutputLine': [outputHandler], } if interactive: # If an interactive debugger is attached, # don't use timeouts, and don't capture ctrl-c. timeout = None signal.signal(signal.SIGINT, lambda sigid, frame: None) runner_cls = mozrunner.runners.get( mozinfo.info.get('appname', 'firefox'), mozrunner.Runner) runner = runner_cls(profile=profile, binary=binary, process_class=mozprocess.ProcessHandlerMixin, cmdargs=cmdargs, env=env, process_args=kp_kwargs) runner.start(debug_args=debug_args, interactive=interactive, outputTimeout=timeout) proc = runner.process_handler if self.use_marionette: marionette_args = { 'socket_timeout': options.marionette_socket_timeout, 'startup_timeout': options.marionette_startup_timeout, 'symbols_path': options.symbolsPath, } if options.marionette: host, port = options.marionette.split(':') marionette_args['host'] = host marionette_args['port'] = int(port) marionette = Marionette(**marionette_args) marionette.start_session(timeout=options.marionette_port_timeout) addons = Addons(marionette) if options.specialPowersExtensionPath: addons.install(options.specialPowersExtensionPath, temp=True) addons.install(options.reftestExtensionPath, temp=True) marionette.delete_session() status = runner.wait() runner.process_handler = None if status: msg = "TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s" % \ (self.lastTestSeen, status) # use process_output so message is logged verbatim self.log.process_output(None, msg) else: self.lastTestSeen = self.TEST_SEEN_FINAL crashed = mozcrash.log_crashes(self.log, os.path.join(profile.profile, 'minidumps'), symbolsPath, test=self.lastTestSeen) runner.cleanup() if not status and crashed: status = 1 return status, self.lastTestSeen
def runApp(self, options, cmdargs=None, timeout=None, debuggerInfo=None, symbolsPath=None, valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None, **profileArgs): if cmdargs is None: cmdargs = [] cmdargs = cmdargs[:] if self.use_marionette: cmdargs.append('-marionette') binary = options.app profile = self.createReftestProfile(options, **profileArgs) # browser environment env = self.buildBrowserEnv(options, profile.profile) self.log.info("Running with e10s: {}".format(options.e10s)) def timeoutHandler(): self.handleTimeout(timeout, proc, options.utilityPath, debuggerInfo) interactive = False debug_args = None if debuggerInfo: interactive = debuggerInfo.interactive debug_args = [debuggerInfo.path] + debuggerInfo.args def record_last_test(message): """Records the last test seen by this harness for the benefit of crash logging.""" def testid(test): if " " in test: return test.split(" ")[0] return test if message['action'] == 'test_start': self.lastTestSeen = testid(message['test']) elif message['action'] == 'test_end': if self.lastTest and message['test'] == self.lastTest: self.lastTestSeen = "Last test finished" else: self.lastTestSeen = '{} (finished)'.format( testid(message['test'])) self.log.add_handler(record_last_test) kp_kwargs = { 'kill_on_timeout': False, 'cwd': SCRIPT_DIRECTORY, 'onTimeout': [timeoutHandler], 'processOutputLine': [self.outputHandler], } if mozinfo.isWin: # Prevents log interleaving on Windows at the expense of losing # true log order. See bug 798300 and bug 1324961 for more details. kp_kwargs['processStderrLine'] = [self.outputHandler] if interactive: # If an interactive debugger is attached, # don't use timeouts, and don't capture ctrl-c. timeout = None signal.signal(signal.SIGINT, lambda sigid, frame: None) runner_cls = mozrunner.runners.get( mozinfo.info.get('appname', 'firefox'), mozrunner.Runner) runner = runner_cls(profile=profile, binary=binary, process_class=mozprocess.ProcessHandlerMixin, cmdargs=cmdargs, env=env, process_args=kp_kwargs) runner.start(debug_args=debug_args, interactive=interactive, outputTimeout=timeout) proc = runner.process_handler self.outputHandler.proc_name = 'GECKO({})'.format(proc.pid) # Used to defer a possible IOError exception from Marionette marionette_exception = None if self.use_marionette: marionette_args = { 'socket_timeout': options.marionette_socket_timeout, 'startup_timeout': options.marionette_startup_timeout, 'symbols_path': options.symbolsPath, } if options.marionette: host, port = options.marionette.split(':') marionette_args['host'] = host marionette_args['port'] = int(port) try: marionette = Marionette(**marionette_args) marionette.start_session() addons = Addons(marionette) if options.specialPowersExtensionPath: addons.install(options.specialPowersExtensionPath, temp=True) addons.install(options.reftestExtensionPath, temp=True) marionette.delete_session() except IOError: # Any IOError as thrown by Marionette means that something is # wrong with the process, like a crash or the socket is no # longer open. We defer raising this specific error so that # post-test checks for leaks and crashes are performed and # reported first. marionette_exception = sys.exc_info() status = runner.wait() runner.process_handler = None self.outputHandler.proc_name = None if status: msg = "TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s" % \ (self.lastTestSeen, status) # use process_output so message is logged verbatim self.log.process_output(None, msg) crashed = mozcrash.log_crashes(self.log, os.path.join(profile.profile, 'minidumps'), options.symbolsPath, test=self.lastTestSeen) if not status and crashed: status = 1 runner.cleanup() self.cleanup(profile.profile) if marionette_exception is not None: exc, value, tb = marionette_exception raise exc, value, tb self.log.info( "Process mode: {}".format('e10s' if options.e10s else 'non-e10s')) return status
shutil.copy("firefox_prefs.js", "/tmp/foo" + str(timestamp) + "/prefs.js") time.sleep(1) # Launch Firefox with the new profile p = subprocess.Popen([ FIREFOX_PATH + " -profile /tmp/foo" + str(timestamp) + " -marionette -devtools" ], shell=True, preexec_fn=os.setsid) client = Marionette('localhost', port=2828) client.start_session() addons = Addons(client) addons.install(os.getcwd() + "/har-export-trigger-0.6.1.xpi", temp=True) for run in range(1, TIMES + 1): timestamp = datetime.datetime.now().strftime("%Y-%m-%d+%H-%M-%S.%f") unixtimestamp = int(time.time()) try: hostname = URL_TO_FETCH.split('/')[2] except IndexError: hostname = URL_TO_FETCH URL_TO_FETCH = "http://" + hostname print("Run " + str(run) + "/" + str(TIMES) + " - Fetching " + URL_TO_FETCH + " at " + timestamp) time.sleep(1) event = None
def setUp(self): super(TestAddons, self).setUp() self.addons = Addons(self.marionette) self.preinstalled_addons = self.all_addon_ids
def setUp(self): MarionetteTestCase.setUp(self) self.addons = Addons(self.marionette)
def run_tests(firefox_path=None): basedir = os.path.dirname(__file__) if sys.platform == 'darwin' and os.path.isdir(firefox_path): firefox_path = os.path.join(firefox_path, 'Contents', 'MacOS', 'firefox') driver = Marionette(app='fxdesktop', bin=firefox_path, gecko_log='-', prefs={'xpinstall.signatures.required': False}) driver.start_session() try: build1 = tempfile.NamedTemporaryFile(mode='wb', suffix='.xpi', delete=False) build2 = tempfile.NamedTemporaryFile(mode='wb', suffix='.xpi', delete=False) try: gulp_build(basedir, build1.name) jpm_build(basedir, os.path.join(basedir, 'testhelper'), build2.name) addons = Addons(driver) addons.install(build1.name, temp=True) addons.install(build2.name, temp=True) finally: os.unlink(build1.name) os.unlink(build2.name) driver.expected = expected driver.keys = Keys class restore_url: def __enter__(self): self.url = driver.get_url() def __exit__(self, type, value, traceback): driver.navigate('about:blank') driver.navigate(self.url) driver.restore_url = restore_url def wait_until(method): Wait(driver, default_timeout).until(lambda d: method()) driver.wait_until = wait_until def accept_alert(): driver.switch_to_alert().accept() driver.accept_alert = accept_alert max_timestamp = {'value': 0} def get_urls(): result = [] prefix = '[testhelper] Loading: ' new_timestamp = max_timestamp['value'] with driver.using_context(driver.CONTEXT_CHROME): messages = driver.execute_script( 'return ' + 'Cc["@mozilla.org/consoleservice;1"]' + '.getService(Ci.nsIConsoleService).getMessageArray()' + '.map(m => m instanceof Ci.nsIScriptError ? ' + '[m.timeStamp, m.errorMessage] : [null, null])') for timestamp, message in messages: if timestamp <= max_timestamp['value']: continue if not message.startswith(prefix): continue if timestamp > new_timestamp: new_timestamp = timestamp result.append(message[len(prefix):]) max_timestamp['value'] = new_timestamp return result driver.get_urls = get_urls def close_windows(keep): for h in [h for h in driver.chrome_window_handles if h != keep]: driver.switch_to_window(h) driver.close_chrome_window() driver.switch_to_window(keep) driver.close_windows = close_windows def close_background_tabs(): current_tab = driver.current_window_handle for h in [h for h in driver.window_handles if h != current_tab]: driver.switch_to_window(h) driver.close() driver.switch_to_window(current_tab) driver.close_background_tabs = close_background_tabs def wait_for_load(): code = 'return document.readyState == "complete";' driver.wait_until(lambda: driver.execute_script(code)) driver.wait_for_load = wait_for_load def click(self): action = Actions(driver) action.click(self) action.perform() HTMLElement.click = click def middle_click(self): action = Actions(driver) action.middle_click(self) action.perform() HTMLElement.middle_click = middle_click def context_click(self): action = Actions(driver) action.context_click(self) action.perform() HTMLElement.context_click = context_click testdir = os.path.join(basedir, 'tests') for filename in os.listdir(testdir): if filename.startswith('.') or not filename.endswith('.py'): continue filepath = os.path.join(testdir, filename) globals = {} execfile(filepath, globals) globals['run'](driver) finally: driver.cleanup()
def setUp(self): MarionetteTestCase.setUp(self) self.addons = Addons(self.marionette) self.addon_path = os.path.join(here, 'mn-restartless.xpi')