Skip to content

Commit cbb0908

Browse files
[wptrunner] Plumb expectations wpttest.{Test -> (Subtest)Result}
This allows vendors to override expectations at runtime via browser-specific result converters. Callers that want to simply pass through the testloader-read expectations should use the newly introduced `Test.make_{subtest_,}result()` to construct `(Subtest)Result`s instead of invoking the constructor directly (each pair has the same signature). This is a pure refactor; no functional changes intended. Successor to: web-platform-tests#44134 (comment)
1 parent 33b559d commit cbb0908

11 files changed

+60
-38
lines changed

tools/wptrunner/wptrunner/executors/base.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ def __call__(self, test, result, extra=None):
9090
"""Convert a JSON result into a (TestResult, [SubtestResult]) tuple"""
9191
result_url, status, message, stack, subtest_results = result
9292
assert result_url == test.url, (f"Got results from {result_url}, expected {test.url}")
93-
harness_result = test.result_cls(self.harness_codes[status], message, extra=extra, stack=stack)
93+
harness_result = test.make_result(self.harness_codes[status], message, extra=extra, stack=stack)
9494
return (harness_result,
95-
[test.subtest_result_cls(st_name, self.test_codes[st_status], st_message, st_stack)
95+
[test.make_subtest_result(st_name, self.test_codes[st_status], st_message, st_stack)
9696
for st_name, st_status, st_message, st_stack in subtest_results])
9797

9898

@@ -152,7 +152,7 @@ def get_pages(ranges_value, total_pages):
152152
def reftest_result_converter(self, test, result):
153153
extra = result.get("extra", {})
154154
_ensure_hash_in_reftest_screenshots(extra)
155-
return (test.result_cls(
155+
return (test.make_result(
156156
result["status"],
157157
result["message"],
158158
extra=extra,
@@ -165,14 +165,14 @@ def pytest_result_converter(self, test, data):
165165
if subtest_data is None:
166166
subtest_data = []
167167

168-
harness_result = test.result_cls(*harness_data)
168+
harness_result = test.make_result(*harness_data)
169169
subtest_results = [test.subtest_result_cls(*item) for item in subtest_data]
170170

171171
return (harness_result, subtest_results)
172172

173173

174174
def crashtest_result_converter(self, test, result):
175-
return test.result_cls(**result), []
175+
return test.make_result(**result), []
176176

177177

178178
class ExecutorException(Exception):
@@ -352,7 +352,7 @@ def result_from_exception(self, test, e, exception_string):
352352
if message:
353353
message += "\n"
354354
message += exception_string
355-
return test.result_cls(status, message), []
355+
return test.make_result(status, message), []
356356

357357
def wait(self):
358358
return self.protocol.base.wait()
@@ -648,7 +648,7 @@ def do_test(self, test):
648648
if success:
649649
return self.convert_result(test, data)
650650

651-
return (test.result_cls(*data), [])
651+
return (test.make_result(*data), [])
652652

653653
def do_wdspec(self, path, timeout):
654654
session_config = {"host": self.browser.host,

tools/wptrunner/wptrunner/executors/executorchrome.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def convert_from_crashtest_result(test, result):
4646
status = result["status"]
4747
if status == "PASS":
4848
status = "OK"
49-
harness_result = test.result_cls(status, result["message"])
49+
harness_result = test.make_result(status, result["message"])
5050
# Don't report subtests.
5151
return harness_result, []
5252
# `crashtest` statuses are a subset of `(print-)reftest`

tools/wptrunner/wptrunner/executors/executorcontentshell.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,14 @@ def _convert_exception(test, exception, errors):
213213
"""Converts our TimeoutError and CrashError exceptions into test results.
214214
"""
215215
if isinstance(exception, TimeoutError):
216-
return (test.result_cls("EXTERNAL-TIMEOUT", errors), [])
216+
return (test.make_result("EXTERNAL-TIMEOUT", errors), [])
217217
if isinstance(exception, CrashError):
218-
return (test.result_cls("CRASH", errors), [])
218+
return (test.make_result("CRASH", errors), [])
219219
if isinstance(exception, LeakError):
220220
# TODO: the internal error is to force a restart, but it doesn't correctly
221221
# describe what the issue is. Need to find a way to return a "FAIL",
222222
# and restart the content_shell after the test run.
223-
return (test.result_cls("INTERNAL-ERROR", errors), [])
223+
return (test.make_result("INTERNAL-ERROR", errors), [])
224224
raise exception
225225

226226

@@ -312,7 +312,7 @@ def do_test(self, test):
312312
timeout_for_test(self, test))
313313
errors = self.protocol.content_shell_errors.read_errors()
314314
if not text:
315-
return (test.result_cls("ERROR", errors), [])
315+
return (test.make_result("ERROR", errors), [])
316316

317317
result_url, status, message, stack, subtest_results = json.loads(text)
318318
if result_url != test.url:

tools/wptrunner/wptrunner/executors/executormarionette.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ def do_test(self, test):
979979
if success:
980980
return self.convert_result(test, data, extra=extra)
981981

982-
return (test.result_cls(extra=extra, *data), [])
982+
return (test.make_result(extra=extra, *data), [])
983983

984984
def do_testharness(self, protocol, url, timeout):
985985
parent_window = protocol.testharness.close_old_windows(self.last_environment["protocol"])
@@ -1277,7 +1277,7 @@ def do_test(self, test):
12771277
if success:
12781278
return self.convert_result(test, data)
12791279

1280-
return (test.result_cls(extra=extra, *data), [])
1280+
return (test.make_result(extra=extra, *data), [])
12811281

12821282
def do_crashtest(self, protocol, url, timeout):
12831283
if self.protocol.coverage.is_enabled:

tools/wptrunner/wptrunner/executors/executorselenium.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def do_test(self, test):
369369
if success:
370370
return self.convert_result(test, data)
371371

372-
return (test.result_cls(*data), [])
372+
return (test.make_result(*data), [])
373373

374374
def do_testharness(self, protocol, url, timeout):
375375
format_map = {"url": strip_server(url)}

tools/wptrunner/wptrunner/executors/executorservo.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ def do_test(self, test):
136136
result = self.convert_result(test, self.result_data)
137137
else:
138138
self.proc.wait()
139-
result = (test.result_cls("CRASH", None), [])
139+
result = (test.make_result("CRASH", None), [])
140140
proc_is_running = False
141141
else:
142-
result = (test.result_cls("TIMEOUT", None), [])
142+
result = (test.make_result("TIMEOUT", None), [])
143143

144144
if proc_is_running:
145145
if self.pause_after_test:
@@ -312,7 +312,7 @@ def do_test(self, test):
312312
if success:
313313
return self.convert_result(test, data)
314314

315-
return (test.result_cls(*data), [])
315+
return (test.make_result(*data), [])
316316

317317
def do_crashtest(self, protocol, url, timeout):
318318
self.command = self.build_servo_command(self.test, extra_args=["-x"])

tools/wptrunner/wptrunner/executors/executorservodriver.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def do_test(self, test):
201201
if success:
202202
return self.convert_result(test, data)
203203

204-
return (test.result_cls(*data), [])
204+
return (test.make_result(*data), [])
205205

206206
def do_testharness(self, session, url, timeout):
207207
session.url = url
@@ -257,15 +257,15 @@ def do_test(self, test):
257257
result = self.implementation.run_test(test)
258258
return self.convert_result(test, result)
259259
except OSError:
260-
return test.result_cls("CRASH", None), []
260+
return test.make_result("CRASH", None), []
261261
except TimeoutError:
262-
return test.result_cls("TIMEOUT", None), []
262+
return test.make_result("TIMEOUT", None), []
263263
except Exception as e:
264264
message = getattr(e, "message", "")
265265
if message:
266266
message += "\n"
267267
message += traceback.format_exc()
268-
return test.result_cls("INTERNAL-ERROR", message), []
268+
return test.make_result("INTERNAL-ERROR", message), []
269269

270270
def screenshot(self, test, viewport_size, dpi, page_ranges):
271271
# https://github.com/web-platform-tests/wpt/issues/7135

tools/wptrunner/wptrunner/executors/executorwebdriver.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ def do_test(self, test):
586586
if success:
587587
return self.convert_result(test, data)
588588

589-
return (test.result_cls(*data), [])
589+
return (test.make_result(*data), [])
590590

591591
def do_testharness(self, protocol, url, timeout):
592592
# The previous test may not have closed its old windows (if something
@@ -752,7 +752,7 @@ def do_test(self, test):
752752
if success:
753753
return self.convert_result(test, data)
754754

755-
return (test.result_cls(*data), [])
755+
return (test.make_result(*data), [])
756756

757757
def do_crashtest(self, protocol, url, timeout):
758758
protocol.base.load(url)

tools/wptrunner/wptrunner/executors/executorwktr.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ def _convert_exception(test, exception, errors):
172172
"""Converts our TimeoutError and CrashError exceptions into test results.
173173
"""
174174
if isinstance(exception, TimeoutError):
175-
return (test.result_cls("EXTERNAL-TIMEOUT", errors), [])
175+
return (test.make_result("EXTERNAL-TIMEOUT", errors), [])
176176
if isinstance(exception, CrashError):
177-
return (test.result_cls("CRASH", errors), [])
177+
return (test.make_result("CRASH", errors), [])
178178
raise exception
179179

180180

@@ -245,7 +245,7 @@ def do_test(self, test):
245245

246246
errors = self.protocol.wktr_errors.read_errors()
247247
if not text:
248-
return (test.result_cls("ERROR", errors), [])
248+
return (test.make_result("ERROR", errors), [])
249249

250250
output = None
251251
output_prefix = "CONSOLE MESSAGE: WPTRUNNER OUTPUT:"
@@ -255,10 +255,10 @@ def do_test(self, test):
255255
if output is None:
256256
output = line[len(output_prefix):]
257257
else:
258-
return (test.result_cls("ERROR", "multiple wptrunner outputs"), [])
258+
return (test.make_result("ERROR", "multiple wptrunner outputs"), [])
259259

260260
if output is None:
261-
return (test.result_cls("ERROR", "no wptrunner output"), [])
261+
return (test.make_result("ERROR", "no wptrunner output"), [])
262262

263263
return self.convert_result(test, json.loads(output))
264264
except BaseException as exception:

tools/wptrunner/wptrunner/testrunner.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -663,9 +663,9 @@ def _timeout(self):
663663
self.inject_message(
664664
"test_ended",
665665
test,
666-
(test.result_cls("EXTERNAL-TIMEOUT",
667-
"TestRunner hit external timeout "
668-
"(this may indicate a hang)"), []),
666+
(test.make_result("EXTERNAL-TIMEOUT",
667+
"TestRunner hit external timeout "
668+
"(this may indicate a hang)"), []),
669669
)
670670

671671
def test_ended(self, test, results):
@@ -691,8 +691,8 @@ def test_ended(self, test, results):
691691
for result in test_results:
692692
if test.disabled(result.name):
693693
continue
694-
expected = test.expected(result.name)
695-
known_intermittent = test.known_intermittent(result.name)
694+
expected = result.expected
695+
known_intermittent = result.known_intermittent
696696
is_unexpected = expected != result.status and result.status not in known_intermittent
697697
is_expected_notrun = (expected == "NOTRUN" or "NOTRUN" in known_intermittent)
698698

@@ -728,8 +728,8 @@ def test_ended(self, test, results):
728728
stack=result.stack,
729729
subsuite=self.state.subsuite)
730730

731-
expected = test.expected()
732-
known_intermittent = test.known_intermittent()
731+
expected = file_result.expected
732+
known_intermittent = file_result.known_intermittent
733733
status = file_result.status
734734

735735
if self.browser.check_crash(test.id) and status != "CRASH":

tools/wptrunner/wptrunner/wpttest.py

+24-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import sys
55
from abc import ABC
66
from collections import defaultdict
7-
from typing import Any, ClassVar, Dict, Optional, Type
7+
from typing import Any, ClassVar, Dict, Optional, Set, Type
88
from urllib.parse import urljoin
99

1010
from .wptmanifest.parser import atoms
@@ -14,6 +14,9 @@
1414

1515

1616
class Result(ABC):
17+
default_expected: ClassVar[str]
18+
statuses: Set[str]
19+
1720
def __init__(self,
1821
status,
1922
message,
@@ -25,7 +28,7 @@ def __init__(self,
2528
raise ValueError("Unrecognised status %s" % status)
2629
self.status = status
2730
self.message = message
28-
self.expected = expected
31+
self.expected = expected if expected is not None else self.default_expected
2932
self.known_intermittent = known_intermittent if known_intermittent is not None else []
3033
self.extra = extra if extra is not None else {}
3134
self.stack = stack
@@ -238,6 +241,25 @@ def __eq__(self, other):
238241
def __ne__(self, other):
239242
return not self.__eq__(other)
240243

244+
def make_result(self,
245+
status,
246+
message,
247+
expected=None,
248+
extra=None,
249+
stack=None,
250+
known_intermittent=None):
251+
if expected is None:
252+
expected = self.expected()
253+
known_intermittent = self.known_intermittent()
254+
return self.result_cls(status, message, expected, extra, stack, known_intermittent)
255+
256+
def make_subtest_result(self, name, status, message, stack=None, expected=None,
257+
known_intermittent=None):
258+
if expected is None:
259+
expected = self.expected(name)
260+
known_intermittent = self.known_intermittent(name)
261+
return self.subtest_result_cls(name, status, message, stack, expected, known_intermittent)
262+
241263
def update_metadata(self, metadata=None):
242264
if metadata is None:
243265
metadata = {}

0 commit comments

Comments
 (0)