diff --git a/tools/wpt/browser.py b/tools/wpt/browser.py index 8d8e9703648fb4..ce176211353e65 100644 --- a/tools/wpt/browser.py +++ b/tools/wpt/browser.py @@ -2321,13 +2321,10 @@ def install(self, dest=None, channel="nightly"): return path def find_binary(self, venv_path=None, channel=None): - path = which("servo", path=os.path.join(venv_path, "servo")) - if path is None: - path = which("servo") - return path + return which("servo") def find_webdriver(self, venv_path=None, channel=None): - return None + return which("servodriver") def install_webdriver(self, dest=None, channel=None, browser_binary=None): raise NotImplementedError diff --git a/tools/wpt/run.py b/tools/wpt/run.py index 0f35fb5e68c877..64c3cb5c67ad9b 100644 --- a/tools/wpt/run.py +++ b/tools/wpt/run.py @@ -773,6 +773,27 @@ def setup_kwargs(self, kwargs): if binary is None: raise WptrunError("Unable to find servo binary in PATH") kwargs["binary"] = binary + if kwargs["webdriver_binary"] is None: + webdriver_binary = None + if not kwargs["install_webdriver"]: + webdriver_binary = self.browser.find_webdriver(self.venv.bin_path) + + if webdriver_binary is None: + install = self.prompt_install("servodriver") + + if install: + webdriver_binary = self.browser.install_webdriver( + dest=self.venv.bin_path, + channel=browser_channel, + browser_binary=kwargs["binary"], + ) + else: + logger.info("Using webdriver binary %s" % webdriver_binary) + + if webdriver_binary: + kwargs["webdriver_binary"] = webdriver_binary + else: + raise WptrunError("Unable to locate or install matching servodriver binary") class ServoWebDriver(Servo): diff --git a/tools/wptrunner/wptrunner/browsers/servo.py b/tools/wptrunner/wptrunner/browsers/servo.py index 7a95b08e7ad9ef..568430740fbac9 100644 --- a/tools/wptrunner/wptrunner/browsers/servo.py +++ b/tools/wptrunner/wptrunner/browsers/servo.py @@ -1,6 +1,11 @@ # mypy: allow-untyped-defs import os +import requests +import tempfile +import time + +from tools.serve.serve import make_hosts_file from .base import ExecutorBrowser, NullBrowser, WebDriverBrowser, require_arg from .base import get_timeout_multiplier # noqa: F401 @@ -17,7 +22,7 @@ "product": "servo", "check_args": "check_args", "browser": {None: "ServoBrowser", - "wdspec": "ServoWdspecBrowser"}, + "wdspec": "ServoBrowser"}, "executor": { "crashtest": "ServoCrashtestExecutor", "testharness": "ServoTestharnessExecutor", @@ -34,27 +39,24 @@ def check_args(**kwargs): - require_arg(kwargs, "binary") + require_arg(kwargs, "webdriver_binary") def browser_kwargs(logger, test_type, run_info_data, config, subsuite, **kwargs): return { "binary": kwargs["binary"], + "webdriver_binary": kwargs["webdriver_binary"], "debug_info": kwargs["debug_info"], "binary_args": kwargs["binary_args"] + subsuite.config.get("binary_args", []), "headless": kwargs["headless"], + "server_config": config, "user_stylesheets": kwargs.get("user_stylesheets"), - "ca_certificate_path": config.ssl_config["ca_cert_path"], } -def executor_kwargs(logger, test_type, test_environment, run_info_data, - **kwargs): +def executor_kwargs(logger, test_type, test_environment, run_info_data, **kwargs): rv = base_executor_kwargs(test_type, test_environment, run_info_data, **kwargs) - rv["pause_after_test"] = kwargs["pause_after_test"] - rv["headless"] = kwargs.get("headless", False) - if test_type == "wdspec": - rv["capabilities"] = {} + rv['capabilities'] = {} return rv @@ -64,8 +66,6 @@ def env_extras(**kwargs): def env_options(): return {"server_host": "127.0.0.1", - "bind_address": False, - "testharnessreport": "testharnessreport-servo.js", "supports_debugger": True} @@ -73,59 +73,118 @@ def update_properties(): return ["debug", "os", "processor", "subsuite"], {"os": ["version"], "processor": ["bits"]} -class ServoBrowser(NullBrowser): - def __init__(self, logger, binary, debug_info=None, binary_args=None, - user_stylesheets=None, ca_certificate_path=None, **kwargs): - NullBrowser.__init__(self, logger, **kwargs) - self.binary = binary - self.debug_info = debug_info - self.binary_args = binary_args or [] - self.user_stylesheets = user_stylesheets or [] - self.ca_certificate_path = ca_certificate_path - - def executor_browser(self): - return ExecutorBrowser, { - "binary": self.binary, - "debug_info": self.debug_info, - "binary_args": self.binary_args, - "user_stylesheets": self.user_stylesheets, - "ca_certificate_path": self.ca_certificate_path, - } - - -class ServoWdspecBrowser(WebDriverBrowser): - # TODO: could share an implemenation with servodriver.py, perhaps - def __init__(self, logger, binary="servo", webdriver_binary="servo", - binary_args=None, webdriver_args=None, env=None, port=None, - headless=None, - **kwargs): - - env = os.environ.copy() if env is None else env +def write_hosts_file(config): + hosts_fd, hosts_path = tempfile.mkstemp() + with os.fdopen(hosts_fd, "w") as f: + f.write(make_hosts_file(config, "127.0.0.1")) + return hosts_path + + +class ServoBrowser(WebDriverBrowser): + init_timeout = 300 # Large timeout for cases where we're booting an Android emulator + shutdown_retry_attempts = 3 + + def __init__(self, logger, debug_info=None, webdriver_host="127.0.0.1", + server_config=None, binary_args=None, + user_stylesheets=None, headless=None, **kwargs): + hosts_path = write_hosts_file(server_config) + env = os.environ.copy() + env["HOST_FILE"] = hosts_path env["RUST_BACKTRACE"] = "1" + if debug_info: + env["DELAY_AFTER_ACCEPT"] = env.get("DELAY_SECS", "15") + + args = [ + "--hard-fail", + "-u", "Servo/wptrunner", + # See https://github.com/servo/servo/issues/30080. + # For some reason rustls does not like the certificate generated by the WPT tooling. + "--ignore-certificate-errors", + "--enable-experimental-web-platform-features", + "--window-size", "800x600", + "about:blank", + ] + + ca_cert_path = server_config.ssl_config["ca_cert_path"] + if ca_cert_path: + args += ["--certificate-path", ca_cert_path] + if binary_args: + args += binary_args + if user_stylesheets: + for stylesheet in user_stylesheets: + args += ["--user-stylesheet", stylesheet] + if headless: + args += ["--headless"] + + # Add the shared `wpt-prefs.json` file to the list of arguments. + args += ["--prefs-file", self.find_wpt_prefs(logger)] + super().__init__(logger, - binary=binary, - webdriver_binary=webdriver_binary, - webdriver_args=webdriver_args, - port=port, - env=env, - **kwargs) - self.binary_args = binary_args - self.headless = ["--headless"] if headless else None + webdriver_args=args, host=webdriver_host, env=env, + supports_pac=False, **kwargs) + self.hosts_path = hosts_path def make_command(self): - command = [self.binary, - f"--webdriver={self.port}", - "--hard-fail", - # See https://github.com/servo/servo/issues/30080. - # For some reason rustls does not like the certificate generated by the WPT tooling. - "--ignore-certificate-errors", - "--window-size", - "800x600", - "about:blank"] + self.webdriver_args - if self.binary_args: - command += self.binary_args - if self.headless: - command += self.headless - return command + return [self.webdriver_binary, f"--webdriver={self.port}"] + self.webdriver_args + + def cleanup(self): + os.remove(self.hosts_path) + + def is_alive(self): + # This is broken. It is always True. + if not super().is_alive(): + return False + try: + requests.get(f"http://{self.host}:{self.port}/status", timeout=3) + except requests.exceptions.Timeout: + # FIXME: This indicates a hanged browser. Reasons need to be investigated further. + # It happens with ~0.1% probability in our CI runs. + self.logger.debug("Servo webdriver status request timed out.") + return True + except Exception as exception: + self.logger.debug(f"Servo has shut down normally. {exception}") + return False + + return True + + def stop(self, force=False): + retry_cnt = 0 + while self.is_alive(): + self.logger.info("Trying to shut down gracefully by extension command") + try: + requests.delete( + f"http://{self.host}:{self.port}/session/dummy-session-id/servo/shutdown", + timeout=3 + ) + except requests.exceptions.ConnectionError: + self.logger.debug("Browser already shut down (connection refused)") + break + except requests.exceptions.RequestException as exeception: + self.logger.debug(f"Request exception: {exeception}") + break + except requests.exceptions.Timeout: + self.logger.debug("Request timed out") + break + + retry_cnt += 1 + if retry_cnt >= self.shutdown_retry_attempts: + self.logger.warning("Max retry exceeded to normally shut down. Killing instead.") + break + time.sleep(1) + super().stop(force) + + def find_wpt_prefs(self, logger): + default_path = os.path.join("resources", "wpt-prefs.json") + # The cwd is the servo repo for `./mach test-wpt`, but on WPT runners + # it is the WPT repo. The nightly tar is extracted inside the Python + # virtual environment within the repo. This means that on WPT runners, + # the cwd has the `_venv3/servo` directory inside which we find the + # binary and the 'resources' directory. + for dir in [".", "./_venv3/servo"]: + candidate = os.path.abspath(os.path.join(dir, default_path)) + if os.path.isfile(candidate): + return candidate + logger.error("Unable to find wpt-prefs.json") + return default_path diff --git a/tools/wptrunner/wptrunner/executors/executorservo.py b/tools/wptrunner/wptrunner/executors/executorservo.py index 9c1a762703aaee..758f36f82a0d8f 100644 --- a/tools/wptrunner/wptrunner/executors/executorservo.py +++ b/tools/wptrunner/wptrunner/executors/executorservo.py @@ -1,369 +1,150 @@ # mypy: allow-untyped-defs -import base64 -import json -import os -import subprocess -import tempfile -import threading -import traceback -import uuid +from .executorwebdriver import ( + WebDriverProtocol, + WebDriverTestharnessExecutor, + WebDriverTestharnessProtocolPart, + WebDriverRefTestExecutor, + WebDriverCrashtestExecutor, +) -from mozprocess import ProcessHandler -from tools.serve.serve import make_hosts_file +webdriver = None +ServoCommandExtensions = None -from .base import (RefTestExecutor, RefTestImplementation, TestExecutor, - crashtest_result_converter, - testharness_result_converter, - reftest_result_converter, - TimedRunner) -from .protocol import ConnectionlessProtocol -from ..browsers.base import browser_command +# See parse_pref_from_command_line() in components/config/opts.rs +def parse_pref_value(value): + if value == "true": + return True + if value == "false": + return False + try: + return float(value) + except ValueError: + return value -pytestrunner = None -webdriver = None +def do_delayed_imports(): + global webdriver + import webdriver -# A mixin class that includes functionality common to all Servo -# executors that work by spawing a new process. This is intended to -# be used along with either the `TestExecutor` class or its children -# and must be the first in the inheritance list to allow `super` -# to forward the calls to correct base class. -class ServoExecutorMixin: - def __init__(self, logger, browser, server_config, headless, - timeout_multiplier, debug_info, - pause_after_test, reftest_screenshot="unexpected"): - super().__init__(logger, browser, server_config, - timeout_multiplier=timeout_multiplier, - debug_info=debug_info, - reftest_screenshot=reftest_screenshot) - self.binary = self.browser.binary - self.interactive = (False if self.debug_info is None - else self.debug_info.interactive) - self.pause_after_test = pause_after_test - self.environment = {} - self.protocol = ConnectionlessProtocol(self, browser) - self.headless = headless - - self.wpt_prefs_path = self.find_wpt_prefs() - - hosts_fd, self.hosts_path = tempfile.mkstemp() - with os.fdopen(hosts_fd, "w") as f: - f.write(make_hosts_file(self.server_config, "127.0.0.1")) - - self.env_for_tests = os.environ.copy() - self.env_for_tests["HOST_FILE"] = self.hosts_path - self.env_for_tests["RUST_BACKTRACE"] = "1" - - def setup(self, runner, protocol=None): - self.runner = runner - self.runner.send_message("init_succeeded") - return True + global ServoCommandExtensions + + class ServoCommandExtensions: + def __init__(self, session): + self.session = session + + def get_prefs(self, *prefs): + body = {"prefs": list(prefs)} + return self.session.send_session_command("GET", "servo/prefs/get", body) + + def set_prefs(self, prefs): + body = {"prefs": prefs} + return self.session.send_session_command("POST", "servo/prefs/set", body) + + def reset_prefs(self, *prefs): + body = {"prefs": list(prefs)} + return self.session.send_session_command("POST", "servo/prefs/reset", body) + + def shutdown(self): + body = {} + return self.session.send_session_command("DELETE", "servo/shutdown", body) + + # Clear all cookies for all origins. + def reset_all_cookies(self): + body = {} + return self.session.send_session_command("POST", "servo/cookies/reset", body) + + def change_prefs(self, old_prefs, new_prefs): + # Servo interprets reset with an empty list as reset everything + if old_prefs: + self.reset_prefs(*old_prefs.keys()) + self.set_prefs({k: parse_pref_value(v) for k, v in new_prefs.items()}) + + +class ServoTestharnessProtocolPart(WebDriverTestharnessProtocolPart): + def reset_browser_state(self): + self.parent.webdriver.extension.reset_all_cookies() + + +class ServoProtocol(WebDriverProtocol): + implements = [ + ServoTestharnessProtocolPart, + ] + for base_part in WebDriverProtocol.implements: + if base_part.name not in {part.name for part in implements}: + implements.append(base_part) + + def __init__(self, executor, browser, capabilities, **kwargs): + do_delayed_imports() + self.implements = list(ServoProtocol.implements) + super().__init__(executor, browser, capabilities, **kwargs) + + def connect(self): + """Connect to browser via WebDriver and crete a WebDriver session.""" + self.logger.debug("Connecting to WebDriver on URL: %s" % self.url) + + host, port = self.url.split(":")[1].strip("/"), self.url.split(':')[-1].strip("/") + + capabilities = {"alwaysMatch": self.capabilities} + self.webdriver = webdriver.Session(host, port, + capabilities=capabilities, + enable_bidi=self.enable_bidi, + extension=ServoCommandExtensions) + self.webdriver.start() + + +class ServoTestharnessExecutor(WebDriverTestharnessExecutor): + supports_testdriver = True + protocol_cls = ServoProtocol + + def __init__(self, logger, browser, server_config, timeout_multiplier=1, + close_after_done=True, capabilities=None, debug_info=None, + **kwargs): + WebDriverTestharnessExecutor.__init__(self, logger, browser, server_config, + timeout_multiplier, capabilities=capabilities, + debug_info=debug_info, close_after_done=close_after_done, + cleanup_after_test=False) + + def on_environment_change(self, new_environment): + self.protocol.webdriver.extension.change_prefs( + self.last_environment.get("prefs", {}), + new_environment.get("prefs", {}) + ) + + +class ServoRefTestExecutor(WebDriverRefTestExecutor): + protocol_cls = ServoProtocol + + def __init__(self, logger, browser, server_config, timeout_multiplier=1, + screenshot_cache=None, capabilities=None, debug_info=None, + **kwargs): + WebDriverRefTestExecutor.__init__(self, logger, browser, server_config, + timeout_multiplier, screenshot_cache, + capabilities=capabilities, + debug_info=debug_info) + + def on_environment_change(self, new_environment): + self.protocol.webdriver.extension.change_prefs( + self.last_environment.get("prefs", {}), + new_environment.get("prefs", {}) + ) + + +class ServoCrashtestExecutor(WebDriverCrashtestExecutor): + protocol_cls = ServoProtocol - def teardown(self): - try: - os.unlink(self.hosts_path) - except OSError: - pass - super().teardown() + def __init__(self, logger, browser, server_config, timeout_multiplier=1, + screenshot_cache=None, capabilities=None, debug_info=None, + **kwargs): + WebDriverCrashtestExecutor.__init__(self, logger, browser, server_config, + timeout_multiplier, screenshot_cache, + capabilities=capabilities, + debug_info=debug_info) def on_environment_change(self, new_environment): - self.environment = new_environment - return super().on_environment_change(new_environment) - - def on_output(self, line): - line = line.decode("utf8", "replace") - if self.interactive: - print(line) - else: - self.logger.process_output(self.proc.pid, line, " ".join(self.command), self.test.url) - - def find_wpt_prefs(self): - default_path = os.path.join("resources", "wpt-prefs.json") - # The cwd is the servo repo for `./mach test-wpt`, but on WPT runners - # it is the WPT repo. The nightly tar is extracted inside the python - # virtual environment within the repo. This means that on WPT runners, - # the cwd has the `_venv3/servo` directory inside which we find the - # binary and the 'resources' directory. - for dir in [".", "./_venv3/servo"]: - candidate = os.path.abspath(os.path.join(dir, default_path)) - if os.path.isfile(candidate): - return candidate - self.logger.error("Unable to find wpt-prefs.json") - return default_path - - def build_servo_command(self, test, extra_args=None): - args = [ - "--hard-fail", "-u", "Servo/wptrunner", - # See https://github.com/servo/servo/issues/30080. - # For some reason rustls does not like the certificate generated by the WPT tooling. - "--ignore-certificate-errors", - "--enable-experimental-web-platform-features", - self.test_url(test), - ] - if self.headless: - args += ["-z"] - for stylesheet in self.browser.user_stylesheets: - args += ["--user-stylesheet", stylesheet] - for pref, value in self.environment.get('prefs', {}).items(): - args += ["--pref", f"{pref}={value}"] - args += ["--prefs-file", self.wpt_prefs_path] - if self.browser.ca_certificate_path: - args += ["--certificate-path", self.browser.ca_certificate_path] - if extra_args: - args += extra_args - args += self.browser.binary_args - debug_args, command = browser_command(self.binary, args, self.debug_info) - return debug_args + command - - -class ServoTestharnessExecutor(ServoExecutorMixin, TestExecutor): - convert_result = testharness_result_converter - - def __init__(self, logger, browser, server_config, headless, - timeout_multiplier=1, debug_info=None, - pause_after_test=False, **kwargs): - super().__init__(logger, browser, server_config, - headless, - timeout_multiplier=timeout_multiplier, - debug_info=debug_info, - pause_after_test=pause_after_test) - self.result_data = None - self.result_flag = None - - def do_test(self, test): - self.test = test - self.result_data = None - self.result_flag = threading.Event() - - self.command = self.build_servo_command(test) - - if not self.interactive: - self.proc = ProcessHandler(self.command, - processOutputLine=[self.on_output], - onFinish=self.on_finish, - env=self.env_for_tests, - storeOutput=False) - self.proc.run() - else: - self.proc = subprocess.Popen(self.command, env=self.env_for_tests) - - try: - timeout = test.timeout * self.timeout_multiplier - - # Now wait to get the output we expect, or until we reach the timeout - if not self.interactive and not self.pause_after_test: - wait_timeout = timeout + 5 - self.result_flag.wait(wait_timeout) - else: - wait_timeout = None - self.proc.wait() - - proc_is_running = True - - if self.result_flag.is_set(): - if self.result_data is not None: - result = self.convert_result(test, self.result_data) - else: - self.proc.wait() - result = (test.make_result("CRASH", None), []) - proc_is_running = False - else: - result = (test.make_result("TIMEOUT", None), []) - - if proc_is_running: - if self.pause_after_test: - self.logger.info("Pausing until the browser exits") - self.proc.wait() - else: - self.proc.kill() - except: # noqa - self.proc.kill() - raise - - return result - - def on_output(self, line): - prefix = "ALERT: RESULT: " - decoded_line = line.decode("utf8", "replace") - if decoded_line.startswith(prefix): - try: - self.result_data = json.loads(decoded_line[len(prefix):]) - except json.JSONDecodeError as error: - self.logger.error(f"Could not process test output JSON: {error}") - self.result_flag.set() - else: - super().on_output(line) - - def on_finish(self): - self.result_flag.set() - - -class TempFilename: - def __init__(self, directory): - self.directory = directory - self.path = None - - def __enter__(self): - self.path = os.path.join(self.directory, str(uuid.uuid4())) - return self.path - - def __exit__(self, *args, **kwargs): - try: - os.unlink(self.path) - except OSError: - pass - - -class ServoRefTestExecutor(ServoExecutorMixin, RefTestExecutor): - convert_result = reftest_result_converter - - def __init__(self, logger, browser, server_config, binary=None, timeout_multiplier=1, - screenshot_cache=None, debug_info=None, pause_after_test=False, - reftest_screenshot="unexpected", **kwargs): - super().__init__(logger, - browser, - server_config, - headless=True, - timeout_multiplier=timeout_multiplier, - debug_info=debug_info, - reftest_screenshot=reftest_screenshot, - pause_after_test=pause_after_test) - - self.screenshot_cache = screenshot_cache - self.reftest_screenshot = reftest_screenshot - self.implementation = RefTestImplementation(self) - self.tempdir = tempfile.mkdtemp() - - def reset(self): - self.implementation.reset() - - def teardown(self): - os.rmdir(self.tempdir) - super().teardown() - - def screenshot(self, test, viewport_size, dpi, page_ranges): - with TempFilename(self.tempdir) as output_path: - extra_args = ["--exit", - "--output=%s" % output_path, - "--window-size", viewport_size or "800x600"] - - if dpi: - extra_args += ["--device-pixel-ratio", str(dpi)] - - self.command = self.build_servo_command(test, extra_args) - - if not self.interactive: - self.proc = ProcessHandler(self.command, - processOutputLine=[self.on_output], - env=self.env_for_tests) - - try: - self.proc.run() - timeout = test.timeout * self.timeout_multiplier + 5 - rv = self.proc.wait(timeout=timeout) - except KeyboardInterrupt: - self.proc.kill() - raise - else: - self.proc = subprocess.Popen(self.command, env=self.env_for_tests) - try: - rv = self.proc.wait() - except KeyboardInterrupt: - self.proc.kill() - raise - - if rv is None: - self.proc.kill() - return False, ("EXTERNAL-TIMEOUT", None) - - if rv != 0 or not os.path.exists(output_path): - return False, ("CRASH", None) - - with open(output_path, "rb") as f: - # Might need to strip variable headers or something here - data = f.read() - # Returning the screenshot as a string could potentially be avoided, - # see https://github.com/web-platform-tests/wpt/issues/28929. - return True, [base64.b64encode(data).decode()] - - def do_test(self, test): - # FIXME: This is a temporary fix until Servo syncs with upstream WPT. - # Once that happens, we can patch the `RefTestImplementation.get_screenshot_list` - # method to cast dpi to integer when using it in arithmetic expressions. - if test.dpi is not None: - test.dpi = int(test.dpi) - self.test = test - result = self.implementation.run_test(test) - - return self.convert_result(test, result) - - -class ServoTimedRunner(TimedRunner): - def run_func(self): - try: - self.result = (True, self.func(self.protocol, self.url, self.timeout)) - except Exception as e: - message = getattr(e, "message", "") - if message: - message += "\n" - message += traceback.format_exc(e) - self.result = False, ("INTERNAL-ERROR", message) - finally: - self.result_flag.set() - - def set_timeout(self): - pass - - -class ServoCrashtestExecutor(ServoExecutorMixin, TestExecutor): - convert_result = crashtest_result_converter - - def __init__(self, logger, browser, server_config, headless, - binary=None, timeout_multiplier=1, screenshot_cache=None, - debug_info=None, pause_after_test=False, **kwargs): - super().__init__(logger, - browser, - server_config, - headless, - timeout_multiplier=timeout_multiplier, - debug_info=debug_info, - pause_after_test=pause_after_test) - - def do_test(self, test): - timeout = (test.timeout * self.timeout_multiplier if self.debug_info is None - else None) - - test_url = self.test_url(test) - # We want to pass the full test object into build_servo_command, - # so stash it in the class - self.test = test - success, data = ServoTimedRunner(self.logger, self.do_crashtest, self.protocol, - test_url, timeout, self.extra_timeout).run() - # Ensure that no processes hang around if they timeout. - self.proc.kill() - - if success: - return self.convert_result(test, data) - - return (test.make_result(*data), []) - - def do_crashtest(self, protocol, url, timeout): - self.command = self.build_servo_command(self.test, extra_args=["-x"]) - - if not self.interactive: - self.proc = ProcessHandler(self.command, - env=self.env_for_tests, - processOutputLine=[self.on_output], - storeOutput=False) - self.proc.run() - else: - self.proc = subprocess.Popen(self.command, env=self.env_for_tests) - - self.proc.wait() - - if self.proc.poll() >= 0: - return {"status": "PASS", "message": None} - return {"status": "CRASH", "message": None} + self.protocol.webdriver.extension.change_prefs( + self.last_environment.get("prefs", {}), + new_environment.get("prefs", {}) + ) diff --git a/tools/wptrunner/wptrunner/testharnessreport-servo.js b/tools/wptrunner/wptrunner/testharnessreport-servo.js deleted file mode 100644 index 4439393a18125b..00000000000000 --- a/tools/wptrunner/wptrunner/testharnessreport-servo.js +++ /dev/null @@ -1,24 +0,0 @@ -(function() { - var props = { - output:%(output)d, - timeout_multiplier: %(timeout_multiplier)s, - explicit_timeout: %(explicit_timeout)s, - debug: %(debug)s - }; - var start_loc = document.createElement('a'); - start_loc.href = location.href; - setup(props); - - add_completion_callback(function (tests, harness_status) { - var id = decodeURIComponent(start_loc.pathname) + decodeURIComponent(start_loc.search) + decodeURIComponent(start_loc.hash); - console.log("ALERT: RESULT: " + JSON.stringify([ - id, - harness_status.status, - harness_status.message, - harness_status.stack, - tests.map(function(t) { - return [t.name, t.status, t.message, t.stack] - }), - ])); - }); -})();