diff options
Diffstat (limited to 'testing/web-platform/harness/wptrunner/browsers/firefox.py')
-rw-r--r-- | testing/web-platform/harness/wptrunner/browsers/firefox.py | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/testing/web-platform/harness/wptrunner/browsers/firefox.py b/testing/web-platform/harness/wptrunner/browsers/firefox.py new file mode 100644 index 000000000..183820c5c --- /dev/null +++ b/testing/web-platform/harness/wptrunner/browsers/firefox.py @@ -0,0 +1,274 @@ +# 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 os +import platform +import subprocess +import sys + +import mozinfo +from mozprocess import ProcessHandler +from mozprofile import FirefoxProfile, Preferences +from mozprofile.permissions import ServerLocations +from mozrunner import FirefoxRunner +from mozrunner.utils import get_stack_fixer_function +from mozcrash import mozcrash + +from .base import (get_free_port, + Browser, + ExecutorBrowser, + require_arg, + cmd_arg, + browser_command) +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executormarionette import (MarionetteTestharnessExecutor, + MarionetteRefTestExecutor, + MarionetteWdspecExecutor) +from ..environment import hostnames + + +here = os.path.join(os.path.split(__file__)[0]) + +__wptrunner__ = {"product": "firefox", + "check_args": "check_args", + "browser": "FirefoxBrowser", + "executor": {"testharness": "MarionetteTestharnessExecutor", + "reftest": "MarionetteRefTestExecutor", + "wdspec": "MarionetteWdspecExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_options": "env_options", + "run_info_extras": "run_info_extras", + "update_properties": "update_properties"} + + +def check_args(**kwargs): + require_arg(kwargs, "binary") + if kwargs["ssl_type"] != "none": + require_arg(kwargs, "certutil_binary") + + +def browser_kwargs(**kwargs): + return {"binary": kwargs["binary"], + "prefs_root": kwargs["prefs_root"], + "debug_info": kwargs["debug_info"], + "symbols_path": kwargs["symbols_path"], + "stackwalk_binary": kwargs["stackwalk_binary"], + "certutil_binary": kwargs["certutil_binary"], + "ca_certificate_path": kwargs["ssl_env"].ca_cert_path(), + "e10s": kwargs["gecko_e10s"], + "stackfix_dir": kwargs["stackfix_dir"]} + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + executor_kwargs = base_executor_kwargs(test_type, server_config, + cache_manager, **kwargs) + executor_kwargs["close_after_done"] = test_type != "reftest" + if kwargs["timeout_multiplier"] is None: + if test_type == "reftest": + if run_info_data["debug"] or run_info_data.get("asan"): + executor_kwargs["timeout_multiplier"] = 4 + else: + executor_kwargs["timeout_multiplier"] = 2 + elif run_info_data["debug"] or run_info_data.get("asan"): + executor_kwargs["timeout_multiplier"] = 3 + if test_type == "wdspec": + executor_kwargs["webdriver_binary"] = kwargs.get("webdriver_binary") + return executor_kwargs + + +def env_options(): + return {"host": "127.0.0.1", + "external_host": "web-platform.test", + "bind_hostname": "false", + "certificate_domain": "web-platform.test", + "supports_debugger": True} + + +def run_info_extras(**kwargs): + return {"e10s": kwargs["gecko_e10s"]} + + +def update_properties(): + return ["debug", "e10s", "os", "version", "processor", "bits"], {"debug", "e10s"} + + +class FirefoxBrowser(Browser): + used_ports = set() + init_timeout = 60 + + def __init__(self, logger, binary, prefs_root, debug_info=None, + symbols_path=None, stackwalk_binary=None, certutil_binary=None, + ca_certificate_path=None, e10s=False, stackfix_dir=None): + Browser.__init__(self, logger) + self.binary = binary + self.prefs_root = prefs_root + self.marionette_port = None + self.runner = None + self.debug_info = debug_info + self.profile = None + self.symbols_path = symbols_path + self.stackwalk_binary = stackwalk_binary + self.ca_certificate_path = ca_certificate_path + self.certutil_binary = certutil_binary + self.e10s = e10s + if self.symbols_path and stackfix_dir: + self.stack_fixer = get_stack_fixer_function(stackfix_dir, + self.symbols_path) + else: + self.stack_fixer = None + + def start(self): + self.marionette_port = get_free_port(2828, exclude=self.used_ports) + self.used_ports.add(self.marionette_port) + + env = os.environ.copy() + env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1" + + locations = ServerLocations(filename=os.path.join(here, "server-locations.txt")) + + preferences = self.load_prefs() + + self.profile = FirefoxProfile(locations=locations, + preferences=preferences) + self.profile.set_preferences({"marionette.defaultPrefs.enabled": True, + "marionette.defaultPrefs.port": self.marionette_port, + "dom.disable_open_during_load": False, + "network.dns.localDomains": ",".join(hostnames), + "network.proxy.type": 0, + "places.history.enabled": False}) + if self.e10s: + self.profile.set_preferences({"browser.tabs.remote.autostart": True}) + + # Bug 1262954: winxp + e10s, disable hwaccel + if (self.e10s and platform.system() in ("Windows", "Microsoft") and + '5.1' in platform.version()): + self.profile.set_preferences({"layers.acceleration.disabled": True}) + + if self.ca_certificate_path is not None: + self.setup_ssl() + + debug_args, cmd = browser_command(self.binary, [cmd_arg("marionette"), "about:blank"], + self.debug_info) + + self.runner = FirefoxRunner(profile=self.profile, + binary=cmd[0], + cmdargs=cmd[1:], + env=env, + process_class=ProcessHandler, + process_args={"processOutputLine": [self.on_output]}) + + self.logger.debug("Starting Firefox") + + self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive) + self.logger.debug("Firefox Started") + + def load_prefs(self): + prefs_path = os.path.join(self.prefs_root, "prefs_general.js") + if os.path.exists(prefs_path): + preferences = Preferences.read_prefs(prefs_path) + else: + self.logger.warning("Failed to find base prefs file in %s" % prefs_path) + preferences = [] + + return preferences + + def stop(self): + self.logger.debug("Stopping browser") + if self.runner is not None: + try: + self.runner.stop() + except OSError: + # This can happen on Windows if the process is already dead + pass + + def pid(self): + if self.runner.process_handler is None: + return None + + try: + return self.runner.process_handler.pid + except AttributeError: + return None + + def on_output(self, line): + """Write a line of output from the firefox process to the log""" + data = line.decode("utf8", "replace") + if self.stack_fixer: + data = self.stack_fixer(data) + self.logger.process_output(self.pid(), + data, + command=" ".join(self.runner.command)) + + def is_alive(self): + if self.runner: + return self.runner.is_running() + return False + + def cleanup(self): + self.stop() + + def executor_browser(self): + assert self.marionette_port is not None + return ExecutorBrowser, {"marionette_port": self.marionette_port} + + def log_crash(self, process, test): + dump_dir = os.path.join(self.profile.profile, "minidumps") + + mozcrash.log_crashes(self.logger, + dump_dir, + symbols_path=self.symbols_path, + stackwalk_binary=self.stackwalk_binary, + process=process, + test=test) + + def setup_ssl(self): + """Create a certificate database to use in the test profile. This is configured + to trust the CA Certificate that has signed the web-platform.test server + certificate.""" + + self.logger.info("Setting up ssl") + + # Make sure the certutil libraries from the source tree are loaded when using a + # local copy of certutil + # TODO: Maybe only set this if certutil won't launch? + env = os.environ.copy() + certutil_dir = os.path.dirname(self.binary) + if mozinfo.isMac: + env_var = "DYLD_LIBRARY_PATH" + elif mozinfo.isUnix: + env_var = "LD_LIBRARY_PATH" + else: + env_var = "PATH" + + + env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]]) + if env_var in env else certutil_dir).encode( + sys.getfilesystemencoding() or 'utf-8', 'replace') + + def certutil(*args): + cmd = [self.certutil_binary] + list(args) + self.logger.process_output("certutil", + subprocess.check_output(cmd, + env=env, + stderr=subprocess.STDOUT), + " ".join(cmd)) + + pw_path = os.path.join(self.profile.profile, ".crtdbpw") + with open(pw_path, "w") as f: + # Use empty password for certificate db + f.write("\n") + + cert_db_path = self.profile.profile + + # Create a new certificate db + certutil("-N", "-d", cert_db_path, "-f", pw_path) + + # Add the CA certificate to the database and mark as trusted to issue server certs + certutil("-A", "-d", cert_db_path, "-f", pw_path, "-t", "CT,,", + "-n", "web-platform-tests", "-i", self.ca_certificate_path) + + # List all certs in the database + certutil("-L", "-d", cert_db_path) |