Beispiel #1
0
    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")
Beispiel #2
0
 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)
Beispiel #3
0
    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)
Beispiel #4
0
    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")
Beispiel #6
0
 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__())
Beispiel #7
0
    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))
Beispiel #8
0
 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')
Beispiel #11
0
    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
Beispiel #12
0
    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
Beispiel #14
0
    def setUp(self):
        super(TestAddons, self).setUp()

        self.addons = Addons(self.marionette)
        self.preinstalled_addons = self.all_addon_ids
Beispiel #15
0
 def setUp(self):
     MarionetteTestCase.setUp(self)
     self.addons = Addons(self.marionette)
Beispiel #16
0
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()
Beispiel #17
0
 def setUp(self):
     MarionetteTestCase.setUp(self)
     self.addons = Addons(self.marionette)
     self.addon_path = os.path.join(here, 'mn-restartless.xpi')