Bug 1416410 - Record wdspec harness outcomes. r?jgraham draft
authorAndreas Tolfsen <ato@sny.no>
Tue, 14 Nov 2017 12:58:39 -0500
changeset 702590 631176d172ac9ebd51a63092d41387b1f6aec376
parent 702588 b6bed1b710c3e22cab49f22f1b5f44d80286bcb9
child 741526 73a55793a5d6db6feaa1e2d86ab3f354e954e14e
push id90547
push userbmo:ato@sny.no
push dateThu, 23 Nov 2017 11:51:37 +0000
reviewersjgraham
bugs1416410
milestone59.0a1
Bug 1416410 - Record wdspec harness outcomes. r?jgraham This fixes the problem that wdspec tests fail silently when there is a problem with collecting the file in pytest. For example, if the Python test file contains a SyntaxError we currently fail to record this as ERROR, and instead report it as OK. MozReview-Commit-ID: 5W46gaLQa0c
testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py
testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/base.py
@@ -352,22 +352,20 @@ class WdspecExecutor(TestExecutor):
                                   timeout).run()
 
         if success:
             return self.convert_result(test, data)
 
         return (test.result_cls(*data), [])
 
     def do_wdspec(self, session_config, path, timeout):
-        harness_result = ("OK", None)
-        subtest_results = pytestrunner.run(path,
-                                           self.server_config,
-                                           session_config,
-                                           timeout=timeout)
-        return (harness_result, subtest_results)
+        return pytestrunner.run(path,
+                                self.server_config,
+                                session_config,
+                                timeout=timeout)
 
     def do_delayed_imports(self):
         global pytestrunner
         from . import pytestrunner
 
 
 class Protocol(object):
     def __init__(self, executor, browser):
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/pytestrunner/runner.py
@@ -1,9 +1,10 @@
-"""Provides interface to deal with pytest.
+"""
+Provides interface to deal with pytest.
 
 Usage::
 
     session = webdriver.client.Session("127.0.0.1", "4444", "/")
     harness_result = ("OK", None)
     subtest_results = pytestrunner.run("/path/to/test", session.url)
     return (harness_result, subtest_results)
 """
@@ -19,55 +20,71 @@ pytest = None
 
 
 def do_delayed_imports():
     global pytest
     import pytest
 
 
 def run(path, server_config, session_config, timeout=0):
-    """Run Python test at ``path`` in pytest.  The provided ``session``
+    """
+    Run Python test at ``path`` in pytest.  The provided ``session``
     is exposed as a fixture available in the scope of the test functions.
 
     :param path: Path to the test file.
     :param session_config: dictionary of host, port,capabilities parameters
     to pass through to the webdriver session
     :param timeout: Duration before interrupting potentially hanging
         tests.  If 0, there is no timeout.
 
-    :returns: List of subtest results, which are tuples of (test id,
-        status, message, stacktrace).
+    :returns: (<harness result>, [<subtest result>, ...]),
+        where <subtest result> is (test id, status, message, stacktrace).
     """
-
     if pytest is None:
         do_delayed_imports()
 
-    recorder = SubtestResultRecorder()
-
     os.environ["WD_HOST"] = session_config["host"]
     os.environ["WD_PORT"] = str(session_config["port"])
     os.environ["WD_CAPABILITIES"] = json.dumps(session_config["capabilities"])
     os.environ["WD_SERVER_CONFIG"] = json.dumps(server_config)
 
-    plugins = [recorder]
-
-    # TODO(ato): Deal with timeouts
+    harness = HarnessResultRecorder()
+    subtests = SubtestResultRecorder()
 
     with TemporaryDirectory() as cache:
-        pytest.main(["--strict",  # turn warnings into errors
-                     "--verbose",  # show each individual subtest
-                     "--capture", "no",  # enable stdout/stderr from tests
-                     "--basetemp", cache,  # temporary directory
-                     "--showlocals",  # display contents of variables in local scope
-                     "-p", "no:mozlog",  # use the WPT result recorder
-                     "-p", "no:cacheprovider",  # disable state preservation across invocations
-                     path],
-                    plugins=plugins)
+        try:
+            pytest.main(["--strict",  # turn warnings into errors
+                         "--verbose",  # show each individual subtest
+                         "--capture", "no",  # enable stdout/stderr from tests
+                         "--basetemp", cache,  # temporary directory
+                         "--showlocals",  # display contents of variables in local scope
+                         "-p", "no:mozlog",  # use the WPT result recorder
+                         "-p", "no:cacheprovider",  # disable state preservation across invocations
+                         path],
+                        plugins=[harness, subtests])
+        except Exception as e:
+            harness.outcome = ("ERROR", str(e))
+
+    return (harness.outcome, subtests.results)
 
-    return recorder.results
+
+class HarnessResultRecorder(object):
+    outcomes = {
+        "failed": "ERROR",
+        "passed": "OK",
+        "skipped": "SKIP",
+    }
+
+    def __init__(self):
+        # we are ok unless told otherwise
+        self.outcome = ("OK", None)
+
+    def pytest_collectreport(self, report):
+        harness_result = self.outcomes[report.outcome]
+        self.outcome = (harness_result, None)
 
 
 class SubtestResultRecorder(object):
     def __init__(self):
         self.results = []
 
     def pytest_runtest_logreport(self, report):
         if report.passed and report.when == "call":