diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index d6ea50fa7842..4df609d13aab 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -132,6 +132,7 @@ var whitelist = [ {file: "chrome://marionette/content/test_anonymous_content.xul"}, {file: "chrome://marionette/content/test_dialog.properties"}, {file: "chrome://marionette/content/test_dialog.xul"}, + {file: "chrome://marionette/content/PerTestCoverageUtils.jsm"}, // Bug 1348533 {file: "chrome://mozapps/skin/downloads/buttons.png", platforms: ["macosx"]}, {file: "chrome://mozapps/skin/downloads/downloadButtons.png", platforms: ["linux", "win"]}, diff --git a/testing/marionette/jar.mn b/testing/marionette/jar.mn index f23195e2bb67..8c5be664ba9b 100644 --- a/testing/marionette/jar.mn +++ b/testing/marionette/jar.mn @@ -46,4 +46,5 @@ marionette.jar: content/test_dialog.xul (chrome/test_dialog.xul) content/test_nested_iframe.xul (chrome/test_nested_iframe.xul) content/test.xul (chrome/test.xul) + content/PerTestCoverageUtils.jsm (../../tools/code-coverage/PerTestCoverageUtils.jsm) #endif diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py index 54802faf83b1..6f1d35a749b7 100644 --- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/executormarionette.py @@ -29,7 +29,8 @@ from .protocol import (AssertsProtocolPart, SelectorProtocolPart, ClickProtocolPart, SendKeysProtocolPart, - TestDriverProtocolPart) + TestDriverProtocolPart, + CoverageProtocolPart) from ..testrunner import Stop from ..webdriver_server import GeckoDriverServer @@ -371,6 +372,53 @@ class MarionetteTestDriverProtocolPart(TestDriverProtocolPart): self.parent.base.execute_script("window.postMessage(%s, '*')" % json.dumps(obj)) +class MarionetteCoverageProtocolPart(CoverageProtocolPart): + def setup(self): + self.marionette = self.parent.marionette + 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, socket.error): + # 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, socket.error): + # This usually happens if the process crashed + pass + + class MarionetteProtocol(Protocol): implements = [MarionetteBaseProtocolPart, MarionetteTestharnessProtocolPart, @@ -380,7 +428,8 @@ class MarionetteProtocol(Protocol): MarionetteClickProtocolPart, MarionetteSendKeysProtocolPart, MarionetteTestDriverProtocolPart, - MarionetteAssertsProtocolPart] + MarionetteAssertsProtocolPart, + MarionetteCoverageProtocolPart] def __init__(self, executor, browser, capabilities=None, timeout_multiplier=1, e10s=True): do_delayed_imports() @@ -599,6 +648,9 @@ class MarionetteTestharnessExecutor(TestharnessExecutor): 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, @@ -621,6 +673,10 @@ class MarionetteTestharnessExecutor(TestharnessExecutor): done, rv = handler(result) if done: break + + if self.protocol.coverage.is_enabled: + self.protocol.coverage.dump() + return rv @@ -689,8 +745,14 @@ class MarionetteRefTestExecutor(RefTestExecutor): 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: diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py index 2e48162e0fd3..71fc3c9a8f65 100644 --- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/protocol.py @@ -303,3 +303,20 @@ class AssertsProtocolPart(ProtocolPart): def get(self): """Get a count of assertions since the last browser start""" pass + + +class CoverageProtocolPart(ProtocolPart): + """Protocol part for collecting per-test coverage data.""" + __metaclass__ = ABCMeta + + name = "coverage" + + @abstractmethod + def reset(self): + """Reset coverage counters""" + pass + + @abstractmethod + def dump(self): + """Dump coverage counters""" + pass