Bug 1513880 [wpt PR 14496] - Revert "Make testharness tests run in a top-level browsing context": Remove .orig files from conflicts, a=testonly DONTBUILD
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 23 Jan 2019 21:13:05 +0200
changeset 515170 211eda3487ef5bb72a2482e15051808ec508166d
parent 515166 309abca54dae664c346136ec2d0be957b39b676c
child 515171 f0f4bf8af10a1ba026623963950277dac0814360
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1513880, 14496
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1513880 [wpt PR 14496] - Revert "Make testharness tests run in a top-level browsing context": Remove .orig files from conflicts, a=testonly DONTBUILD
testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py.orig
testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/fennec.py.orig
testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py.orig
testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py.orig
deleted file mode 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/base.py.orig
+++ /dev/null
@@ -1,206 +0,0 @@
-import os
-import platform
-import socket
-from abc import ABCMeta, abstractmethod
-from copy import deepcopy
-
-from ..wptcommandline import require_arg  # noqa: F401
-
-here = os.path.split(__file__)[0]
-
-
-def inherit(super_module, child_globals, product_name):
-    super_wptrunner = super_module.__wptrunner__
-    child_globals["__wptrunner__"] = child_wptrunner = deepcopy(super_wptrunner)
-
-    child_wptrunner["product"] = product_name
-
-    for k in ("check_args", "browser", "browser_kwargs", "executor_kwargs",
-              "env_extras", "env_options"):
-        attr = super_wptrunner[k]
-        child_globals[attr] = getattr(super_module, attr)
-
-    for v in super_module.__wptrunner__["executor"].values():
-        child_globals[v] = getattr(super_module, v)
-
-    if "run_info_extras" in super_wptrunner:
-        attr = super_wptrunner["run_info_extras"]
-        child_globals[attr] = getattr(super_module, attr)
-
-
-def cmd_arg(name, value=None):
-    prefix = "-" if platform.system() == "Windows" else "--"
-    rv = prefix + name
-
-
-def inherit(super_module, child_globals, product_name):
-    super_wptrunner = super_module.__wptrunner__
-    child_globals["__wptrunner__"] = child_wptrunner = deepcopy(super_wptrunner)
-
-    child_wptrunner["product"] = product_name
-
-    for k in ("check_args", "browser", "browser_kwargs", "executor_kwargs",
-              "env_extras", "env_options"):
-        attr = super_wptrunner[k]
-        child_globals[attr] = getattr(super_module, attr)
-
-    for v in super_module.__wptrunner__["executor"].values():
-        child_globals[v] = getattr(super_module, v)
-
-    if "run_info_extras" in super_wptrunner:
-        attr = super_wptrunner["run_info_extras"]
-        child_globals[attr] = getattr(super_module, attr)
-
-
-def cmd_arg(name, value=None):
-    prefix = "-" if platform.system() == "Windows" else "--"
-    rv = prefix + name
-    if value is not None:
-        rv += "=" + value
-    return rv
-
-
-def get_free_port(start_port, exclude=None):
-    """Get the first port number after start_port (inclusive) that is
-    not currently bound.
-
-    :param start_port: Integer port number at which to start testing.
-    :param exclude: Set of port numbers to skip"""
-    port = start_port
-    while True:
-        if exclude and port in exclude:
-            port += 1
-            continue
-        s = socket.socket()
-        try:
-            s.bind(("127.0.0.1", port))
-        except socket.error:
-            port += 1
-        else:
-            return port
-        finally:
-            s.close()
-
-def browser_command(binary, args, debug_info):
-    if debug_info:
-        if debug_info.requiresEscapedArgs:
-            args = [item.replace("&", "\\&") for item in args]
-        debug_args = [debug_info.path] + debug_info.args
-    else:
-        debug_args = []
-
-    command = [binary] + args
-
-    return debug_args, command
-
-
-class BrowserError(Exception):
-    pass
-
-
-class Browser(object):
-    __metaclass__ = ABCMeta
-
-    process_cls = None
-    init_timeout = 30
-
-    def __init__(self, logger):
-        """Abstract class serving as the basis for Browser implementations.
-
-        The Browser is used in the TestRunnerManager to start and stop the browser
-        process, and to check the state of that process. This class also acts as a
-        context manager, enabling it to do browser-specific setup at the start of
-        the testrun and cleanup after the run is complete.
-
-        :param logger: Structured logger to use for output.
-        """
-        self.logger = logger
-
-    def __enter__(self):
-        self.setup()
-        return self
-
-    def __exit__(self, *args, **kwargs):
-        self.cleanup()
-
-    def setup(self):
-        """Used for browser-specific setup that happens at the start of a test run"""
-        pass
-
-    def settings(self, test):
-        return {}
-
-    @abstractmethod
-    def start(self, group_metadata, **kwargs):
-        """Launch the browser object and get it into a state where is is ready to run tests"""
-        pass
-
-    @abstractmethod
-    def stop(self, force=False):
-        """Stop the running browser process."""
-        pass
-
-    @abstractmethod
-    def pid(self):
-        """pid of the browser process or None if there is no pid"""
-        pass
-
-    @abstractmethod
-    def is_alive(self):
-        """Boolean indicating whether the browser process is still running"""
-        pass
-
-    def setup_ssl(self, hosts):
-        """Return a certificate to use for tests requiring ssl that will be trusted by the browser"""
-        raise NotImplementedError("ssl testing not supported")
-
-    def cleanup(self):
-        """Browser-specific cleanup that is run after the testrun is finished"""
-        pass
-
-    def executor_browser(self):
-        """Returns the ExecutorBrowser subclass for this Browser subclass and the keyword arguments
-        with which it should be instantiated"""
-        return ExecutorBrowser, {}
-
-    def check_crash(self, process, test):
-        """Check if a crash occured and output any useful information to the
-        log. Returns a boolean indicating whether a crash occured."""
-        return False
-
-
-class NullBrowser(Browser):
-    def __init__(self, logger, **kwargs):
-        super(NullBrowser, self).__init__(logger)
-
-    def start(self, **kwargs):
-        """No-op browser to use in scenarios where the TestRunnerManager shouldn't
-        actually own the browser process (e.g. Servo where we start one browser
-        per test)"""
-        pass
-
-    def stop(self, force=False):
-        pass
-
-    def pid(self):
-        return None
-
-    def is_alive(self):
-        return True
-
-    def on_output(self, line):
-        raise NotImplementedError
-
-
-class ExecutorBrowser(object):
-    def __init__(self, **kwargs):
-        """View of the Browser used by the Executor object.
-        This is needed because the Executor runs in a child process and
-        we can't ship Browser instances between processes on Windows.
-
-        Typically this will have a few product-specific properties set,
-        but in some cases it may have more elaborate methods for setting
-        up the browser from the runner process.
-        """
-        for k, v in kwargs.iteritems():
-            setattr(self, k, v)
deleted file mode 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/fennec.py.orig
+++ /dev/null
@@ -1,217 +0,0 @@
-import os
-import tempfile
-
-import moznetwork
-from mozprocess import ProcessHandler
-from mozprofile import FirefoxProfile
-from mozrunner import FennecEmulatorRunner
-
-from tools.serve.serve import make_hosts_file
-
-from .base import (get_free_port,
-                   cmd_arg,
-                   browser_command)
-from ..executors.executormarionette import (MarionetteTestharnessExecutor,  # noqa: F401
-                                            MarionetteRefTestExecutor)  # noqa: F401
-from .firefox import (get_timeout_multiplier,
-                      update_properties,
-                      executor_kwargs,
-                      FirefoxBrowser)
-
-
-__wptrunner__ = {"product": "fennec",
-                 "check_args": "check_args",
-                 "browser": "FennecBrowser",
-                 "executor": {"testharness": "MarionetteTestharnessExecutor",
-                              "reftest": "MarionetteRefTestExecutor"},
-                 "browser_kwargs": "browser_kwargs",
-                 "executor_kwargs": "executor_kwargs",
-                 "env_extras": "env_extras",
-                 "env_options": "env_options",
-                 "run_info_extras": "run_info_extras",
-                 "update_properties": "update_properties"}
-
-
-def check_args(**kwargs):
-    pass
-
-
-def browser_kwargs(test_type, run_info_data, config, **kwargs):
-    return {"package_name": kwargs["package_name"],
-            "device_serial": kwargs["device_serial"],
-            "prefs_root": kwargs["prefs_root"],
-            "extra_prefs": kwargs["extra_prefs"],
-            "test_type": test_type,
-            "debug_info": kwargs["debug_info"],
-            "symbols_path": kwargs["symbols_path"],
-            "stackwalk_binary": kwargs["stackwalk_binary"],
-            "certutil_binary": kwargs["certutil_binary"],
-            "ca_certificate_path": config.ssl_config["ca_cert_path"],
-            "stackfix_dir": kwargs["stackfix_dir"],
-            "binary_args": kwargs["binary_args"],
-            "timeout_multiplier": get_timeout_multiplier(test_type,
-                                                         run_info_data,
-                                                         **kwargs),
-            "leak_check": kwargs["leak_check"],
-            "stylo_threads": kwargs["stylo_threads"],
-            "chaos_mode_flags": kwargs["chaos_mode_flags"],
-            "config": config,
-            "install_fonts": kwargs["install_fonts"],
-            "tests_root": config.doc_root}
-
-
-def env_extras(**kwargs):
-    return []
-
-
-def run_info_extras(**kwargs):
-    return {"e10s": False,
-            "headless": False,
-            "sw-e10s": False}
-
-
-def env_options():
-    # The server host is set to public localhost IP so that resources can be accessed
-    # from Android emulator
-    return {"server_host": moznetwork.get_ip(),
-            "bind_address": False,
-            "supports_debugger": True}
-
-
-def write_hosts_file(config, device):
-    new_hosts = make_hosts_file(config, moznetwork.get_ip())
-    current_hosts = device.get_file("/etc/hosts")
-    if new_hosts == current_hosts:
-        return
-    hosts_fd, hosts_path = tempfile.mkstemp()
-    try:
-        with os.fdopen(hosts_fd, "w") as f:
-            f.write(new_hosts)
-        device.remount()
-        device.push(hosts_path, "/etc/hosts")
-    finally:
-        os.remove(hosts_path)
-
-
-class FennecBrowser(FirefoxBrowser):
-    used_ports = set()
-    init_timeout = 300
-    shutdown_timeout = 60
-
-    def __init__(self, logger, prefs_root, test_type, package_name=None,
-                 device_serial="emulator-5444", **kwargs):
-        FirefoxBrowser.__init__(self, logger, None, prefs_root, test_type, **kwargs)
-        self._package_name = package_name
-        self.device_serial = device_serial
-        self.tests_root = kwargs["tests_root"]
-        self.install_fonts = kwargs["install_fonts"]
-
-    @property
-    def package_name(self):
-        """
-        Name of app to run on emulator.
-        """
-        if self._package_name is None:
-            self._package_name = "org.mozilla.fennec"
-            user = os.getenv("USER")
-            if user:
-                self._package_name += "_" + user
-        return self._package_name
-
-    def start(self, **kwargs):
-        if self.marionette_port is None:
-            self.marionette_port = get_free_port(2828, exclude=self.used_ports)
-            self.used_ports.add(self.marionette_port)
-
-        env = {}
-        env["MOZ_CRASHREPORTER"] = "1"
-        env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
-        env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
-        env["STYLO_THREADS"] = str(self.stylo_threads)
-        if self.chaos_mode_flags is not None:
-            env["MOZ_CHAOSMODE"] = str(self.chaos_mode_flags)
-
-        preferences = self.load_prefs()
-
-        self.profile = FirefoxProfile(preferences=preferences)
-        self.profile.set_preferences({"marionette.port": self.marionette_port,
-                                      "dom.disable_open_during_load": False,
-                                      "places.history.enabled": False,
-                                      "dom.send_after_paint_to_content": True,
-                                      "network.preload": True})
-        if self.test_type == "reftest":
-            self.logger.info("Setting android reftest preferences")
-            self.profile.set_preferences({"browser.viewport.desktopWidth": 600,
-                                          # Disable high DPI
-                                          "layout.css.devPixelsPerPx": "1.0",
-                                          # Ensure that the full browser element
-                                          # appears in the screenshot
-                                          "apz.allow_zooming": False,
-                                          "android.widget_paints_background": False,
-                                          # Ensure that scrollbars are always painted
-                                          "ui.scrollbarFadeBeginDelay": 100000})
-
-        if self.install_fonts:
-            self.logger.debug("Copying Ahem font to profile")
-            font_dir = os.path.join(self.profile.profile, "fonts")
-            if not os.path.exists(font_dir):
-                os.makedirs(font_dir)
-            with open(os.path.join(self.tests_root, "fonts", "Ahem.ttf"), "rb") as src:
-                with open(os.path.join(font_dir, "Ahem.ttf"), "wb") as dest:
-                    dest.write(src.read())
-
-        if self.leak_check and kwargs.get("check_leaks", True):
-            self.leak_report_file = os.path.join(self.profile.profile, "runtests_leaks.log")
-            if os.path.exists(self.leak_report_file):
-                os.remove(self.leak_report_file)
-            env["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
-        else:
-            self.leak_report_file = None
-
-        if self.ca_certificate_path is not None:
-            self.setup_ssl()
-
-        debug_args, cmd = browser_command(self.package_name,
-                                          self.binary_args if self.binary_args else [] +
-                                          [cmd_arg("marionette"), "about:blank"],
-                                          self.debug_info)
-
-        self.runner = FennecEmulatorRunner(app=self.package_name,
-                                           profile=self.profile,
-                                           cmdargs=cmd[1:],
-                                           env=env,
-                                           symbols_path=self.symbols_path,
-                                           serial=self.device_serial,
-                                           # TODO - choose appropriate log dir
-                                           logdir=os.getcwd(),
-                                           process_class=ProcessHandler,
-                                           process_args={"processOutputLine": [self.on_output]})
-
-        self.logger.debug("Starting %s" % self.package_name)
-        # connect to a running emulator
-        self.runner.device.connect()
-
-        write_hosts_file(self.config, self.runner.device.device)
-
-        self.runner.stop()
-        self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
-
-        self.runner.device.device.forward(
-            local="tcp:{}".format(self.marionette_port),
-            remote="tcp:{}".format(self.marionette_port))
-
-        self.logger.debug("%s Started" % self.package_name)
-
-    def stop(self, force=False):
-        if self.runner is not None:
-            if (self.runner.device.connected and
-                len(self.runner.device.device.list_forwards()) > 0):
-                try:
-                    self.runner.device.device.remove_forwards(
-                        "tcp:{}".format(self.marionette_port))
-                except Exception:
-                    self.logger.warning("Failed to remove port forwarding")
-            # We assume that stopping the runner prompts the
-            # browser to shut down. This allows the leak log to be written
-            self.runner.stop()
-        self.logger.debug("stopped")
deleted file mode 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/sauce.py.orig
+++ /dev/null
@@ -1,252 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import glob
-import os
-import shutil
-import subprocess
-import tarfile
-import tempfile
-import time
-from cStringIO import StringIO as CStringIO
-
-import requests
-
-from .base import Browser, ExecutorBrowser, require_arg
-from ..executors import executor_kwargs as base_executor_kwargs
-from ..executors.executorselenium import (SeleniumTestharnessExecutor,
-                                          SeleniumRefTestExecutor)
-
-here = os.path.split(__file__)[0]
-# Number of seconds to wait between polling operations when detecting status of
-# Sauce Connect sub-process.
-sc_poll_period = 1
-
-
-__wptrunner__ = {"product": "sauce",
-                 "check_args": "check_args",
-                 "browser": "SauceBrowser",
-                 "executor": {"testharness": "SeleniumTestharnessExecutor",
-                              "reftest": "SeleniumRefTestExecutor"},
-                 "browser_kwargs": "browser_kwargs",
-                 "executor_kwargs": "executor_kwargs",
-                 "env_extras": "env_extras",
-                 "env_options": "env_options"}
-
-
-def get_capabilities(**kwargs):
-    browser_name = kwargs["sauce_browser"]
-    platform = kwargs["sauce_platform"]
-    version = kwargs["sauce_version"]
-    build = kwargs["sauce_build"]
-    tags = kwargs["sauce_tags"]
-    tunnel_id = kwargs["sauce_tunnel_id"]
-    prerun_script = {
-        "MicrosoftEdge": {
-            "executable": "sauce-storage:edge-prerun.bat",
-            "background": False,
-        },
-        "safari": {
-            "executable": "sauce-storage:safari-prerun.sh",
-            "background": False,
-        }
-    }
-    capabilities = {
-        "browserName": browser_name,
-        "build": build,
-        "disablePopupHandler": True,
-        "name": "%s %s on %s" % (browser_name, version, platform),
-        "platform": platform,
-        "public": "public",
-        "selenium-version": "3.3.1",
-        "tags": tags,
-        "tunnel-identifier": tunnel_id,
-        "version": version,
-        "prerun": prerun_script.get(browser_name)
-    }
-
-    if browser_name == 'MicrosoftEdge':
-        capabilities['selenium-version'] = '2.4.8'
-
-    return capabilities
-
-
-def get_sauce_config(**kwargs):
-    browser_name = kwargs["sauce_browser"]
-    sauce_user = kwargs["sauce_user"]
-    sauce_key = kwargs["sauce_key"]
-
-    hub_url = "%s:%s@localhost:4445" % (sauce_user, sauce_key)
-    data = {
-        "url": "http://%s/wd/hub" % hub_url,
-        "browserName": browser_name,
-        "capabilities": get_capabilities(**kwargs)
-    }
-
-    return data
-
-
-def check_args(**kwargs):
-    require_arg(kwargs, "sauce_browser")
-    require_arg(kwargs, "sauce_platform")
-    require_arg(kwargs, "sauce_version")
-    require_arg(kwargs, "sauce_user")
-    require_arg(kwargs, "sauce_key")
-
-
-def browser_kwargs(test_type, run_info_data, config, **kwargs):
-    sauce_config = get_sauce_config(**kwargs)
-
-    return {"sauce_config": sauce_config}
-
-
-def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
-                    **kwargs):
-    executor_kwargs = base_executor_kwargs(test_type, server_config,
-                                           cache_manager, run_info_data, **kwargs)
-
-    executor_kwargs["capabilities"] = get_capabilities(**kwargs)
-
-    return executor_kwargs
-
-
-def env_extras(**kwargs):
-    return [SauceConnect(**kwargs)]
-
-
-def env_options():
-    return {"supports_debugger": False}
-
-
-def get_tar(url, dest):
-    resp = requests.get(url, stream=True)
-    resp.raise_for_status()
-    with tarfile.open(fileobj=CStringIO(resp.raw.read())) as f:
-        f.extractall(path=dest)
-
-
-class SauceConnect():
-
-    def __init__(self, **kwargs):
-        self.sauce_user = kwargs["sauce_user"]
-        self.sauce_key = kwargs["sauce_key"]
-        self.sauce_tunnel_id = kwargs["sauce_tunnel_id"]
-        self.sauce_connect_binary = kwargs.get("sauce_connect_binary")
-        self.sauce_connect_args = kwargs.get("sauce_connect_args")
-        self.sauce_init_timeout = kwargs.get("sauce_init_timeout")
-        self.sc_process = None
-        self.temp_dir = None
-        self.env_config = None
-
-    def __call__(self, env_options, env_config):
-        self.env_config = env_config
-
-        return self
-
-    def __enter__(self):
-        # Because this class implements the context manager protocol, it is
-        # possible for instances to be provided to the `with` statement
-        # directly. This class implements the callable protocol so that data
-        # which is not available during object initialization can be provided
-        # prior to this moment. Instances must be invoked in preparation for
-        # the context manager protocol, but this additional constraint is not
-        # itself part of the protocol.
-        assert self.env_config is not None, 'The instance has been invoked.'
-
-        if not self.sauce_connect_binary:
-            self.temp_dir = tempfile.mkdtemp()
-            get_tar("https://saucelabs.com/downloads/sc-4.4.9-linux.tar.gz", self.temp_dir)
-            self.sauce_connect_binary = glob.glob(os.path.join(self.temp_dir, "sc-*-linux/bin/sc"))[0]
-
-        self.upload_prerun_exec('edge-prerun.bat')
-        self.upload_prerun_exec('safari-prerun.sh')
-
-        self.sc_process = subprocess.Popen([
-            self.sauce_connect_binary,
-            "--user=%s" % self.sauce_user,
-            "--api-key=%s" % self.sauce_key,
-            "--no-remove-colliding-tunnels",
-            "--tunnel-identifier=%s" % self.sauce_tunnel_id,
-            "--metrics-address=0.0.0.0:9876",
-            "--readyfile=./sauce_is_ready",
-            "--tunnel-domains",
-            ",".join(self.env_config.domains_set)
-        ] + self.sauce_connect_args)
-
-        tot_wait = 0
-        while not os.path.exists('./sauce_is_ready') and self.sc_process.poll() is None:
-            if tot_wait >= self.sauce_init_timeout:
-                self.quit()
-
-                raise SauceException("Sauce Connect Proxy was not ready after %d seconds" % tot_wait)
-
-            time.sleep(sc_poll_period)
-            tot_wait += sc_poll_period
-
-        if self.sc_process.returncode is not None:
-            raise SauceException("Unable to start Sauce Connect Proxy. Process exited with code %s", self.sc_process.returncode)
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.env_config = None
-        self.quit()
-        if self.temp_dir and os.path.exists(self.temp_dir):
-            try:
-                shutil.rmtree(self.temp_dir)
-            except OSError:
-                pass
-
-    def upload_prerun_exec(self, file_name):
-        auth = (self.sauce_user, self.sauce_key)
-        url = "https://saucelabs.com/rest/v1/storage/%s/%s?overwrite=true" % (self.sauce_user, file_name)
-
-        with open(os.path.join(here, 'sauce_setup', file_name), 'rb') as f:
-            requests.post(url, data=f, auth=auth)
-
-    def quit(self):
-        """The Sauce Connect process may be managing an active "tunnel" to the
-        Sauce Labs service. Issue a request to the process to close any tunnels
-        and exit. If this does not occur within 5 seconds, force the process to
-        close."""
-        kill_wait = 5
-        tot_wait = 0
-        self.sc_process.terminate()
-
-        while self.sc_process.poll() is None:
-            time.sleep(sc_poll_period)
-            tot_wait += sc_poll_period
-
-            if tot_wait >= kill_wait:
-                self.sc_process.kill()
-                break
-
-
-class SauceException(Exception):
-    pass
-
-
-class SauceBrowser(Browser):
-    init_timeout = 300
-
-    def __init__(self, logger, sauce_config):
-        Browser.__init__(self, logger)
-        self.sauce_config = sauce_config
-
-    def start(self, **kwargs):
-        pass
-
-    def stop(self, force=False):
-        pass
-
-    def pid(self):
-        return None
-
-    def is_alive(self):
-        # TODO: Should this check something about the connection?
-        return True
-
-    def cleanup(self):
-        pass
-
-    def executor_browser(self):
-        return ExecutorBrowser, {"webdriver_url": self.sauce_config["url"]}
deleted file mode 100644
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py.orig
+++ /dev/null
@@ -1,882 +0,0 @@
-import json
-import os
-import threading
-import traceback
-import urlparse
-import uuid
-
-errors = None
-marionette = None
-pytestrunner = None
-
-here = os.path.join(os.path.split(__file__)[0])
-
-from .base import (CallbackHandler,
-                   RefTestExecutor,
-                   RefTestImplementation,
-                   TestharnessExecutor,
-                   WdspecExecutor,
-                   WebDriverProtocol,
-                   extra_timeout,
-                   strip_server)
-from .protocol import (ActionSequenceProtocolPart,
-                       AssertsProtocolPart,
-                       BaseProtocolPart,
-                       TestharnessProtocolPart,
-                       PrefsProtocolPart,
-                       Protocol,
-                       StorageProtocolPart,
-                       SelectorProtocolPart,
-                       ClickProtocolPart,
-                       SendKeysProtocolPart,
-                       TestDriverProtocolPart,
-                       CoverageProtocolPart)
-from ..testrunner import Stop
-from ..webdriver_server import GeckoDriverServer
-
-
-def do_delayed_imports():
-    global errors, marionette
-
-    # Marionette client used to be called marionette, recently it changed
-    # to marionette_driver for unfathomable reasons
-    try:
-        import marionette
-        from marionette import errors
-    except ImportError:
-        from marionette_driver import marionette, errors
-
-
-class MarionetteBaseProtocolPart(BaseProtocolPart):
-    def __init__(self, parent):
-        super(MarionetteBaseProtocolPart, self).__init__(parent)
-        self.timeout = None
-
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def execute_script(self, script, async=False):
-        method = self.marionette.execute_async_script if async else self.marionette.execute_script
-        return method(script, new_sandbox=False, sandbox=None)
-
-    def set_timeout(self, timeout):
-        """Set the Marionette script timeout.
-
-        :param timeout: Script timeout in seconds
-
-        """
-        if timeout != self.timeout:
-            self.marionette.timeout.script = timeout
-            self.timeout = timeout
-
-    @property
-    def current_window(self):
-        return self.marionette.current_window_handle
-
-    def set_window(self, handle):
-        self.marionette.switch_to_window(handle)
-
-    def wait(self):
-        try:
-            socket_timeout = self.marionette.client.socket_timeout
-        except AttributeError:
-            # This can happen if there was a crash
-            return
-        if socket_timeout:
-            try:
-                self.marionette.timeout.script = socket_timeout / 2
-            except IOError:
-                self.logger.debug("Socket closed")
-                return
-
-        while True:
-            try:
-                self.marionette.execute_async_script("")
-            except errors.NoSuchWindowException:
-                # The window closed
-                break
-            except errors.ScriptTimeoutException:
-                self.logger.debug("Script timed out")
-                pass
-            except errors.JavascriptException as e:
-                # This can happen if we navigate, but just keep going
-                self.logger.debug(e.message)
-                pass
-            except IOError:
-                self.logger.debug("Socket closed")
-                break
-            except Exception as e:
-                self.logger.warning(traceback.format_exc(e))
-                break
-
-
-class MarionetteTestharnessProtocolPart(TestharnessProtocolPart):
-    def __init__(self, parent):
-        super(MarionetteTestharnessProtocolPart, self).__init__(parent)
-        self.runner_handle = None
-        with open(os.path.join(here, "runner.js")) as f:
-            self.runner_script = f.read()
-
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def load_runner(self, url_protocol):
-        # Check if we previously had a test window open, and if we did make sure it's closed
-        if self.runner_handle:
-            self._close_windows()
-        url = urlparse.urljoin(self.parent.executor.server_url(url_protocol),
-                               "/testharness_runner.html")
-        self.logger.debug("Loading %s" % url)
-        try:
-            self.dismiss_alert(lambda: self.marionette.navigate(url))
-        except Exception as e:
-            self.logger.critical(
-                "Loading initial page %s failed. Ensure that the "
-                "there are no other programs bound to this port and "
-                "that your firewall rules or network setup does not "
-                "prevent access.\e%s" % (url, traceback.format_exc(e)))
-            raise
-        self.runner_handle = self.marionette.current_window_handle
-        format_map = {"title": threading.current_thread().name.replace("'", '"')}
-        self.parent.base.execute_script(self.runner_script % format_map)
-
-    def _close_windows(self):
-        handles = self.marionette.window_handles
-        runner_handle = None
-        try:
-            handles.remove(self.runner_handle)
-            runner_handle = self.runner_handle
-        except ValueError:
-            # The runner window probably changed id but we can restore it
-            # This isn't supposed to happen, but marionette ids are not yet stable
-            # We assume that the first handle returned corresponds to the runner,
-            # but it hopefully doesn't matter too much if that assumption is
-            # wrong since we reload the runner in that tab anyway.
-            runner_handle = handles.pop(0)
-            self.logger.info("Changing harness_window to %s" % runner_handle)
-
-        for handle in handles:
-            try:
-                self.dismiss_alert(lambda: self.marionette.switch_to_window(handle))
-                self.marionette.switch_to_window(handle)
-                self.logger.info("Closing window %s" % handle)
-                self.marionette.close()
-            except errors.NoSuchWindowException:
-                # We might have raced with the previous test to close this
-                # window, skip it.
-                pass
-        self.marionette.switch_to_window(runner_handle)
-        return runner_handle
-
-    def close_old_windows(self, url_protocol):
-        runner_handle = self._close_windows()
-        if runner_handle != self.runner_handle:
-            self.load_runner(url_protocol)
-        return self.runner_handle
-
-    def dismiss_alert(self, f):
-        while True:
-            try:
-                f()
-            except errors.UnexpectedAlertOpen:
-                alert = self.marionette.switch_to_alert()
-                try:
-                    alert.dismiss()
-                except errors.NoAlertPresentException:
-                    pass
-            else:
-                break
-
-    def get_test_window(self, window_id, parent):
-        test_window = None
-        if window_id:
-            try:
-                # Try this, it's in Level 1 but nothing supports it yet
-                win_s = self.parent.base.execute_script("return window['%s'];" % self.window_id)
-                win_obj = json.loads(win_s)
-                test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"]
-            except Exception:
-                pass
-
-        if test_window is None:
-            after = self.marionette.window_handles
-            if len(after) == 2:
-                test_window = next(iter(set(after) - set([parent])))
-            elif after[0] == parent and len(after) > 2:
-                # Hope the first one here is the test window
-                test_window = after[1]
-            else:
-                raise Exception("unable to find test window")
-
-        assert test_window != parent
-        return test_window
-
-
-class MarionettePrefsProtocolPart(PrefsProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def set(self, name, value):
-        if value.lower() not in ("true", "false"):
-            try:
-                int(value)
-            except ValueError:
-                value = "'%s'" % value
-        else:
-            value = value.lower()
-
-        self.logger.info("Setting pref %s (%s)" % (name, value))
-
-        script = """
-            let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
-                                          .getService(Components.interfaces.nsIPrefBranch);
-            let pref = '%s';
-            let type = prefInterface.getPrefType(pref);
-            let value = %s;
-            switch(type) {
-                case prefInterface.PREF_STRING:
-                    prefInterface.setCharPref(pref, value);
-                    break;
-                case prefInterface.PREF_BOOL:
-                    prefInterface.setBoolPref(pref, value);
-                    break;
-                case prefInterface.PREF_INT:
-                    prefInterface.setIntPref(pref, value);
-                    break;
-            }
-            """ % (name, value)
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            self.marionette.execute_script(script)
-
-    def clear(self, name):
-        self.logger.info("Clearing pref %s" % (name))
-        script = """
-            let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
-                                          .getService(Components.interfaces.nsIPrefBranch);
-            let pref = '%s';
-            prefInterface.clearUserPref(pref);
-            """ % name
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            self.marionette.execute_script(script)
-
-    def get(self, name):
-        script = """
-            let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
-                                          .getService(Components.interfaces.nsIPrefBranch);
-            let pref = '%s';
-            let type = prefInterface.getPrefType(pref);
-            switch(type) {
-                case prefInterface.PREF_STRING:
-                    return prefInterface.getCharPref(pref);
-                case prefInterface.PREF_BOOL:
-                    return prefInterface.getBoolPref(pref);
-                case prefInterface.PREF_INT:
-                    return prefInterface.getIntPref(pref);
-                case prefInterface.PREF_INVALID:
-                    return null;
-            }
-            """ % name
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            self.marionette.execute_script(script)
-
-
-class MarionetteStorageProtocolPart(StorageProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def clear_origin(self, url):
-        self.logger.info("Clearing origin %s" % (url))
-        script = """
-            let url = '%s';
-            let uri = Components.classes["@mozilla.org/network/io-service;1"]
-                                .getService(Ci.nsIIOService)
-                                .newURI(url);
-            let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
-                                .getService(Ci.nsIScriptSecurityManager);
-            let principal = ssm.createCodebasePrincipal(uri, {});
-            let qms = Components.classes["@mozilla.org/dom/quota-manager-service;1"]
-                                .getService(Components.interfaces.nsIQuotaManagerService);
-            qms.clearStoragesForPrincipal(principal, "default", null, true);
-            """ % url
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            self.marionette.execute_script(script)
-
-
-class MarionetteAssertsProtocolPart(AssertsProtocolPart):
-    def setup(self):
-        self.assert_count = {"chrome": 0, "content": 0}
-        self.chrome_assert_count = 0
-        self.marionette = self.parent.marionette
-
-    def get(self):
-        script = """
-        debug = Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2);
-        if (debug.isDebugBuild) {
-          return debug.assertionCount;
-        }
-        return 0;
-        """
-
-        def get_count(context, **kwargs):
-            try:
-                context_count = self.marionette.execute_script(script, **kwargs)
-                if context_count:
-                    self.parent.logger.info("Got %s assert count %s" % (context, context_count))
-                    test_count = context_count - self.assert_count[context]
-                    self.assert_count[context] = context_count
-                    return test_count
-            except errors.NoSuchWindowException:
-                # If the window was already closed
-                self.parent.logger.warning("Failed to get assertion count; window was closed")
-            except (errors.MarionetteException, IOError):
-                # This usually happens if the process crashed
-                pass
-
-        counts = []
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            counts.append(get_count("chrome"))
-        if self.parent.e10s:
-            counts.append(get_count("content", sandbox="system"))
-
-        counts = [item for item in counts if item is not None]
-
-        if not counts:
-            return None
-
-        return sum(counts)
-
-
-class MarionetteSelectorProtocolPart(SelectorProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def elements_by_selector(self, selector):
-        return self.marionette.find_elements("css selector", selector)
-
-
-class MarionetteClickProtocolPart(ClickProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def element(self, element):
-        return element.click()
-
-
-class MarionetteSendKeysProtocolPart(SendKeysProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def send_keys(self, element, keys):
-        return element.send_keys(keys)
-
-
-class MarionetteActionSequenceProtocolPart(ActionSequenceProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def send_actions(self, actions):
-        actions = self.marionette._to_json(actions)
-        self.logger.info(actions)
-        self.marionette._send_message("WebDriver:PerformActions", actions)
-
-
-class MarionetteTestDriverProtocolPart(TestDriverProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-    def send_message(self, message_type, status, message=None):
-        obj = {
-            "type": "testdriver-%s" % str(message_type),
-            "status": str(status)
-        }
-        if message:
-            obj["message"] = str(message)
-        self.parent.base.execute_script("window.postMessage(%s, '*')" % json.dumps(obj))
-
-
-class MarionetteCoverageProtocolPart(CoverageProtocolPart):
-    def setup(self):
-        self.marionette = self.parent.marionette
-
-        if not self.parent.ccov:
-            self.is_enabled = False
-            return
-
-        script = """
-            ChromeUtils.import("chrome://marionette/content/PerTestCoverageUtils.jsm");
-            return PerTestCoverageUtils.enabled;
-            """
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            self.is_enabled = self.marionette.execute_script(script)
-
-    def reset(self):
-        script = """
-            var callback = arguments[arguments.length - 1];
-
-            ChromeUtils.import("chrome://marionette/content/PerTestCoverageUtils.jsm");
-            PerTestCoverageUtils.beforeTest().then(callback, callback);
-            """
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            try:
-                error = self.marionette.execute_async_script(script)
-                if error is not None:
-                    raise Exception('Failure while resetting counters: %s' % json.dumps(error))
-            except (errors.MarionetteException, IOError):
-                # This usually happens if the process crashed
-                pass
-
-    def dump(self):
-        if len(self.marionette.window_handles):
-            handle = self.marionette.window_handles[0]
-            self.marionette.switch_to_window(handle)
-
-        script = """
-            var callback = arguments[arguments.length - 1];
-
-            ChromeUtils.import("chrome://marionette/content/PerTestCoverageUtils.jsm");
-            PerTestCoverageUtils.afterTest().then(callback, callback);
-            """
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            try:
-                error = self.marionette.execute_async_script(script)
-                if error is not None:
-                    raise Exception('Failure while dumping counters: %s' % json.dumps(error))
-            except (errors.MarionetteException, IOError):
-                # This usually happens if the process crashed
-                pass
-
-
-class MarionetteProtocol(Protocol):
-    implements = [MarionetteBaseProtocolPart,
-                  MarionetteTestharnessProtocolPart,
-                  MarionettePrefsProtocolPart,
-                  MarionetteStorageProtocolPart,
-                  MarionetteSelectorProtocolPart,
-                  MarionetteClickProtocolPart,
-                  MarionetteSendKeysProtocolPart,
-                  MarionetteActionSequenceProtocolPart,
-                  MarionetteTestDriverProtocolPart,
-                  MarionetteAssertsProtocolPart,
-                  MarionetteCoverageProtocolPart]
-
-    def __init__(self, executor, browser, capabilities=None, timeout_multiplier=1, e10s=True, ccov=False):
-        do_delayed_imports()
-
-        super(MarionetteProtocol, self).__init__(executor, browser)
-        self.marionette = None
-        self.marionette_port = browser.marionette_port
-        self.capabilities = capabilities
-        self.timeout_multiplier = timeout_multiplier
-        self.runner_handle = None
-        self.e10s = e10s
-        self.ccov = ccov
-
-    def connect(self):
-        self.logger.debug("Connecting to Marionette on port %i" % self.marionette_port)
-        startup_timeout = marionette.Marionette.DEFAULT_STARTUP_TIMEOUT * self.timeout_multiplier
-        self.marionette = marionette.Marionette(host='127.0.0.1',
-                                                port=self.marionette_port,
-                                                socket_timeout=None,
-                                                startup_timeout=startup_timeout)
-
-        self.logger.debug("Waiting for Marionette connection")
-        while True:
-            try:
-                self.marionette.raise_for_port()
-                break
-            except IOError:
-                # When running in a debugger wait indefinitely for Firefox to start
-                if self.executor.debug_info is None:
-                    raise
-
-        self.logger.debug("Starting Marionette session")
-        self.marionette.start_session(self.capabilities)
-        self.logger.debug("Marionette session started")
-
-    def after_connect(self):
-        pass
-
-    def teardown(self):
-        try:
-            self.marionette._request_in_app_shutdown()
-            self.marionette.delete_session(send_request=False)
-        except Exception:
-            # This is typically because the session never started
-            pass
-        if self.marionette is not None:
-            del self.marionette
-        super(MarionetteProtocol, self).teardown()
-
-    @property
-    def is_alive(self):
-        try:
-            self.marionette.current_window_handle
-        except Exception:
-            return False
-        return True
-
-    def on_environment_change(self, old_environment, new_environment):
-        #Unset all the old prefs
-        for name in old_environment.get("prefs", {}).iterkeys():
-            value = self.executor.original_pref_values[name]
-            if value is None:
-                self.prefs.clear(name)
-            else:
-                self.prefs.set(name, value)
-
-        for name, value in new_environment.get("prefs", {}).iteritems():
-            self.executor.original_pref_values[name] = self.prefs.get(name)
-            self.prefs.set(name, value)
-
-
-class ExecuteAsyncScriptRun(object):
-    def __init__(self, logger, func, protocol, url, timeout):
-        self.logger = logger
-        self.result = (None, None)
-        self.protocol = protocol
-        self.func = func
-        self.url = url
-        self.timeout = timeout
-        self.result_flag = threading.Event()
-
-    def run(self):
-        index = self.url.rfind("/storage/")
-        if index != -1:
-            # Clear storage
-            self.protocol.storage.clear_origin(self.url)
-
-        timeout = self.timeout
-
-        try:
-            if timeout is not None:
-                self.protocol.base.set_timeout(timeout + extra_timeout)
-            else:
-                # We just want it to never time out, really, but marionette doesn't
-                # make that possible. It also seems to time out immediately if the
-                # timeout is set too high. This works at least.
-                self.protocol.base.set_timeout(2**28 - 1)
-        except IOError:
-            self.logger.error("Lost marionette connection before starting test")
-            return Stop
-
-        if timeout is not None:
-            wait_timeout = timeout + 2 * extra_timeout
-        else:
-            wait_timeout = None
-
-        timer = threading.Timer(wait_timeout, self._timeout)
-        timer.start()
-
-        self._run()
-
-        self.result_flag.wait()
-        timer.cancel()
-
-        if self.result == (None, None):
-            self.logger.debug("Timed out waiting for a result")
-            self.result = False, ("EXTERNAL-TIMEOUT", None)
-        elif self.result[1] is None:
-            # We didn't get any data back from the test, so check if the
-            # browser is still responsive
-            if self.protocol.is_alive:
-                self.result = False, ("INTERNAL-ERROR", None)
-            else:
-                self.result = False, ("CRASH", None)
-        return self.result
-
-    def _run(self):
-        try:
-            self.result = True, self.func(self.protocol, self.url, self.timeout)
-        except errors.ScriptTimeoutException:
-            self.logger.debug("Got a marionette timeout")
-            self.result = False, ("EXTERNAL-TIMEOUT", None)
-        except IOError:
-            # This can happen on a crash
-            # Also, should check after the test if the firefox process is still running
-            # and otherwise ignore any other result and set it to crash
-            self.result = False, ("CRASH", None)
-        except Exception as e:
-            message = getattr(e, "message", "")
-            if message:
-                message += "\n"
-            message += traceback.format_exc(e)
-            self.logger.warning(traceback.format_exc())
-            self.result = False, ("INTERNAL-ERROR", e)
-        finally:
-            self.result_flag.set()
-
-    def _timeout(self):
-        self.result = False, ("EXTERNAL-TIMEOUT", None)
-        self.result_flag.set()
-
-
-class MarionetteTestharnessExecutor(TestharnessExecutor):
-    supports_testdriver = True
-
-    def __init__(self, browser, server_config, timeout_multiplier=1,
-                 close_after_done=True, debug_info=None, capabilities=None,
-                 debug=False, ccov=False, **kwargs):
-        """Marionette-based executor for testharness.js tests"""
-        TestharnessExecutor.__init__(self, browser, server_config,
-                                     timeout_multiplier=timeout_multiplier,
-                                     debug_info=debug_info)
-        self.protocol = MarionetteProtocol(self,
-                                           browser,
-                                           capabilities,
-                                           timeout_multiplier,
-                                           kwargs["e10s"],
-                                           ccov)
-        self.script = open(os.path.join(here, "testharness_webdriver.js")).read()
-        self.script_resume = open(os.path.join(here, "testharness_webdriver_resume.js")).read()
-        self.close_after_done = close_after_done
-        self.window_id = str(uuid.uuid4())
-        self.debug = debug
-
-        self.original_pref_values = {}
-
-        if marionette is None:
-            do_delayed_imports()
-
-    def setup(self, runner):
-        super(MarionetteTestharnessExecutor, self).setup(runner)
-        self.protocol.testharness.load_runner(self.last_environment["protocol"])
-
-    def is_alive(self):
-        return self.protocol.is_alive
-
-    def on_environment_change(self, new_environment):
-        self.protocol.on_environment_change(self.last_environment, new_environment)
-
-        if new_environment["protocol"] != self.last_environment["protocol"]:
-            self.protocol.testharness.load_runner(new_environment["protocol"])
-
-    def do_test(self, test):
-        timeout = (test.timeout * self.timeout_multiplier if self.debug_info is None
-                   else None)
-
-        success, data = ExecuteAsyncScriptRun(self.logger,
-                                              self.do_testharness,
-                                              self.protocol,
-                                              self.test_url(test),
-                                              timeout).run()
-        # The format of data depends on whether the test ran to completion or not
-        # For asserts we only care about the fact that if it didn't complete, the
-        # status is in the first field.
-        status = None
-        if not success:
-            status = data[0]
-
-        extra = None
-        if self.debug and (success or status not in ("CRASH", "INTERNAL-ERROR")):
-            assertion_count = self.protocol.asserts.get()
-            if assertion_count is not None:
-                extra = {"assertion_count": assertion_count}
-
-        if success:
-            return self.convert_result(test, data, extra=extra)
-
-        return (test.result_cls(extra=extra, *data), [])
-
-    def do_testharness(self, protocol, url, timeout):
-        parent_window = protocol.testharness.close_old_windows(protocol)
-
-        if timeout is not None:
-            timeout_ms = str(timeout * 1000)
-        else:
-            timeout_ms = "null"
-
-        if self.protocol.coverage.is_enabled:
-            self.protocol.coverage.reset()
-
-        format_map = {"abs_url": url,
-                      "url": strip_server(url),
-                      "window_id": self.window_id,
-                      "timeout_multiplier": self.timeout_multiplier,
-                      "timeout": timeout_ms,
-                      "explicit_timeout": timeout is None}
-
-        script = self.script % format_map
-
-        protocol.base.execute_script(script, async=True)
-        test_window = protocol.testharness.get_test_window(self.window_id, parent_window)
-
-        handler = CallbackHandler(self.logger, protocol, test_window)
-        while True:
-            self.protocol.base.set_window(test_window)
-            result = protocol.base.execute_script(
-                self.script_resume % format_map, async=True)
-            if result is None:
-                # This can happen if we get an content process crash
-                return None
-            done, rv = handler(result)
-            if done:
-                break
-
-        if self.protocol.coverage.is_enabled:
-            self.protocol.coverage.dump()
-
-        return rv
-
-
-class MarionetteRefTestExecutor(RefTestExecutor):
-    def __init__(self, browser, server_config, timeout_multiplier=1,
-                 screenshot_cache=None, close_after_done=True,
-                 debug_info=None, reftest_internal=False,
-                 reftest_screenshot="unexpected", ccov=False,
-                 group_metadata=None, capabilities=None, debug=False, **kwargs):
-        """Marionette-based executor for reftests"""
-        RefTestExecutor.__init__(self,
-                                 browser,
-                                 server_config,
-                                 screenshot_cache=screenshot_cache,
-                                 timeout_multiplier=timeout_multiplier,
-                                 debug_info=debug_info)
-        self.protocol = MarionetteProtocol(self, browser, capabilities,
-                                           timeout_multiplier, kwargs["e10s"],
-                                           ccov)
-        self.implementation = (InternalRefTestImplementation
-                               if reftest_internal
-                               else RefTestImplementation)(self)
-        self.implementation_kwargs = ({"screenshot": reftest_screenshot} if
-                                      reftest_internal else {})
-
-        self.close_after_done = close_after_done
-        self.has_window = False
-        self.original_pref_values = {}
-        self.group_metadata = group_metadata
-        self.debug = debug
-
-        with open(os.path.join(here, "reftest.js")) as f:
-            self.script = f.read()
-        with open(os.path.join(here, "reftest-wait_marionette.js")) as f:
-            self.wait_script = f.read()
-
-    def setup(self, runner):
-        super(self.__class__, self).setup(runner)
-        self.implementation.setup(**self.implementation_kwargs)
-
-    def teardown(self):
-        try:
-            self.implementation.teardown()
-            handles = self.protocol.marionette.window_handles
-            if handles:
-                self.protocol.marionette.switch_to_window(handles[0])
-            super(self.__class__, self).teardown()
-        except Exception as e:
-            # Ignore errors during teardown
-            self.logger.warning("Exception during reftest teardown:\n%s" %
-                                traceback.format_exc(e))
-
-    def is_alive(self):
-        return self.protocol.is_alive
-
-    def on_environment_change(self, new_environment):
-        self.protocol.on_environment_change(self.last_environment, new_environment)
-
-    def do_test(self, test):
-        if not isinstance(self.implementation, InternalRefTestImplementation):
-            if self.close_after_done and self.has_window:
-                self.protocol.marionette.close()
-                self.protocol.marionette.switch_to_window(
-                    self.protocol.marionette.window_handles[-1])
-                self.has_window = False
-
-            if not self.has_window:
-                self.protocol.base.execute_script(self.script)
-                self.protocol.base.set_window(self.protocol.marionette.window_handles[-1])
-                self.has_window = True
-
-        if self.protocol.coverage.is_enabled:
-            self.protocol.coverage.reset()
-
-        result = self.implementation.run_test(test)
-
-        if self.protocol.coverage.is_enabled:
-            self.protocol.coverage.dump()
-
-        if self.debug:
-            assertion_count = self.protocol.asserts.get()
-            if "extra" not in result:
-                result["extra"] = {}
-            result["extra"]["assertion_count"] = assertion_count
-
-        return self.convert_result(test, result)
-
-    def screenshot(self, test, viewport_size, dpi):
-        # https://github.com/w3c/wptrunner/issues/166
-        assert viewport_size is None
-        assert dpi is None
-
-        timeout = self.timeout_multiplier * test.timeout if self.debug_info is None else None
-
-        test_url = self.test_url(test)
-
-        return ExecuteAsyncScriptRun(self.logger,
-                                     self._screenshot,
-                                     self.protocol,
-                                     test_url,
-                                     timeout).run()
-
-    def _screenshot(self, protocol, url, timeout):
-        protocol.marionette.navigate(url)
-
-        protocol.base.execute_script(self.wait_script, async=True)
-
-        screenshot = protocol.marionette.screenshot(full=False)
-        # strip off the data:img/png, part of the url
-        if screenshot.startswith("data:image/png;base64,"):
-            screenshot = screenshot.split(",", 1)[1]
-
-        return screenshot
-
-
-class InternalRefTestImplementation(object):
-    def __init__(self, executor):
-        self.timeout_multiplier = executor.timeout_multiplier
-        self.executor = executor
-
-    @property
-    def logger(self):
-        return self.executor.logger
-
-    def setup(self, screenshot="unexpected"):
-        data = {"screenshot": screenshot}
-        if self.executor.group_metadata is not None:
-            data["urlCount"] = {urlparse.urljoin(self.executor.server_url(key[0]), key[1]):value
-                                for key, value in self.executor.group_metadata.get("url_count", {}).iteritems()
-                                if value > 1}
-        self.executor.protocol.marionette.set_context(self.executor.protocol.marionette.CONTEXT_CHROME)
-        self.executor.protocol.marionette._send_message("reftest:setup", data)
-
-    def run_test(self, test):
-        references = self.get_references(test)
-        timeout = (test.timeout * 1000) * self.timeout_multiplier
-        rv = self.executor.protocol.marionette._send_message("reftest:run",
-                                                             {"test": self.executor.test_url(test),
-                                                              "references": references,
-                                                              "expected": test.expected(),
-                                                              "timeout": timeout})["value"]
-        return rv
-
-    def get_references(self, node):
-        rv = []
-        for item, relation in node.references:
-            rv.append([self.executor.test_url(item), self.get_references(item), relation])
-        return rv
-
-    def teardown(self):
-        try:
-            self.executor.protocol.marionette._send_message("reftest:teardown", {})
-            self.executor.protocol.marionette.set_context(self.executor.protocol.marionette.CONTEXT_CONTENT)
-        except Exception as e:
-            # Ignore errors during teardown
-            self.logger.warning(traceback.format_exc(e))
-
-
-
-class GeckoDriverProtocol(WebDriverProtocol):
-    server_cls = GeckoDriverServer
-
-
-class MarionetteWdspecExecutor(WdspecExecutor):
-    protocol_cls = GeckoDriverProtocol