Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PROTOTYPE] RFC-212 Addrequire_webdriver_bidi metadata #48622

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
disabled: https://github.com/web-platform-tests/wpt/issues/47544
1 change: 1 addition & 0 deletions infrastructure/webdriver/bidi/subscription.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="require_webdriver_bidi" content="true" />
<title>Test console log are present</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
Expand Down
23 changes: 23 additions & 0 deletions infrastructure/webdriver/bidi/subscription.window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// META: title=Test console log are present
// META: require_webdriver_bidi=true
// META: script=/resources/testdriver.js

'use strict';

promise_test(async () => {
const some_message = "SOME MESSAGE";
// Subscribe to `log.entryAdded` BiDi events. This will not add a listener to the page.
await test_driver.bidi.log.entry_added.subscribe();
// Add a listener for the log.entryAdded event. This will not subscribe to the event, so the subscription is
// required before. The cleanup is done automatically after the test is finished.
const log_entry_promise = test_driver.bidi.log.entry_added.once();
// Emit a console.log message.
// Note: Lint rule is disabled in `lint.ignore` file.
console.log(some_message);
// Wait for the log.entryAdded event to be received.
const event = await log_entry_promise;
// Assert the log.entryAdded event has the expected message.
assert_equals(event.args.length, 1);
const event_message = event.args[0];
assert_equals(event_message.value, some_message);
}, "Assert testdriver can subscribe and receive events");
1 change: 1 addition & 0 deletions lint.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ CONSOLE: webaudio/resources/audit.js:41

# Intentional use of console.*
CONSOLE: infrastructure/webdriver/bidi/subscription.html
CONSOLE: infrastructure/webdriver/bidi/subscription.window.js

# use of console in a public library - annotation-model ensures
# it is not actually used
Expand Down
10 changes: 10 additions & 0 deletions tools/lint/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,16 @@ def check_parsed(repo_root: Text, path: Text, f: IO[bytes]) -> List[rules.Error]
if timeout_value != "long":
errors.append(rules.InvalidTimeout.error(path, (timeout_value,)))

if len(source_file.require_webdriver_bidi_nodes) > 1:
errors.append(rules.MultipleRequireBidi.error(path))

for timeout_node in source_file.require_webdriver_bidi_nodes:
require_webdriver_bidi_value = timeout_node.attrib.get("content",
"").lower()
if require_webdriver_bidi_value != "true" and require_webdriver_bidi_value != "false":
errors.append(rules.InvalidRequireBidi.error(path, (
require_webdriver_bidi_value,)))

if source_file.content_is_ref_node or source_file.content_is_testharness:
for element in source_file.variant_nodes:
if "content" not in element.attrib:
Expand Down
18 changes: 18 additions & 0 deletions tools/lint/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,24 @@ class InvalidTimeout(Rule):
to_fix = "replace the value of the `content` attribute with `long`"


class MultipleRequireBidi(Rule):
name = "MULTIPLE-REQUIRE-WEBDRIVER-BIDI"
description = "More than one meta name='require_webdriver_bidi'"
to_fix = """
ensure each test file has only one instance of a `<meta
name="require_webdriver_bidi"...>` element
"""


class InvalidRequireBidi(Rule):
name = "INVALID-REQUIRE-WEBDRIVER-BIDI"
description = collapse("""
Test file with `<meta name='require_webdriver_bidi'...>` element that has a `content`
attribute whose value is not a boolean: %s
""")
to_fix = "replace the value of the `content` attribute with `true` or `false`"


class MultipleTestharness(Rule):
name = "MULTIPLE-TESTHARNESS"
description = "More than one `<script src='/resources/testharness.js'>`"
Expand Down
6 changes: 6 additions & 0 deletions tools/manifest/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ def timeout(self) -> Optional[Text]:
def pac(self) -> Optional[Text]:
return self._extras.get("pac")

@property
def require_webdriver_bidi(self) -> Optional[Text]:
return self._extras.get("require_webdriver_bidi")

@property
def testdriver(self) -> Optional[Text]:
return self._extras.get("testdriver")
Expand All @@ -183,6 +187,8 @@ def to_json(self) -> Tuple[Optional[Text], Dict[Text, Any]]:
rv[-1]["timeout"] = self.timeout
if self.pac is not None:
rv[-1]["pac"] = self.pac
if self.require_webdriver_bidi is not None:
rv[-1]["require_webdriver_bidi"] = self.require_webdriver_bidi
if self.testdriver:
rv[-1]["testdriver"] = self.testdriver
if self.jsshell:
Expand Down
29 changes: 29 additions & 0 deletions tools/manifest/sourcefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,14 @@ def timeout_nodes(self) -> List[ElementTree.Element]:
assert self.root is not None
return self.root.findall(".//{http://www.w3.org/1999/xhtml}meta[@name='timeout']")

@cached_property
def require_webdriver_bidi_nodes(self) -> List[ElementTree.Element]:
"""List of ElementTree Elements corresponding to nodes in a test that
specify timeouts"""
assert self.root is not None
return self.root.findall(
".//{http://www.w3.org/1999/xhtml}meta[@name='require_webdriver_bidi']")

@cached_property
def pac_nodes(self) -> List[ElementTree.Element]:
"""List of ElementTree Elements corresponding to nodes in a test that
Expand Down Expand Up @@ -492,6 +500,23 @@ def pac(self) -> Optional[Text]:

return None

@cached_property
def require_webdriver_bidi(self) -> Optional[Text]:
"""Flag indicating if BiDi functionality is required for the given test"""
if self.script_metadata:
for (meta, content) in self.script_metadata:
if meta == 'require_webdriver_bidi':
return content

if self.root is None:
return None

if self.require_webdriver_bidi_nodes:
return self.require_webdriver_bidi_nodes[0].attrib.get("content",
None)

return None

@cached_property
def viewport_nodes(self) -> List[ElementTree.Element]:
"""List of ElementTree Elements corresponding to nodes in a test that
Expand Down Expand Up @@ -965,6 +990,7 @@ def manifest_items(self) -> Tuple[Text, List[ManifestItem]]:
global_variant_url(self.rel_url, suffix) + variant,
timeout=self.timeout,
pac=self.pac,
require_webdriver_bidi=self.require_webdriver_bidi,
jsshell=jsshell,
script_metadata=self.script_metadata
)
Expand All @@ -983,6 +1009,7 @@ def manifest_items(self) -> Tuple[Text, List[ManifestItem]]:
test_url + variant,
timeout=self.timeout,
pac=self.pac,
require_webdriver_bidi=self.require_webdriver_bidi,
script_metadata=self.script_metadata
)
for variant in self.test_variants
Expand All @@ -999,6 +1026,7 @@ def manifest_items(self) -> Tuple[Text, List[ManifestItem]]:
test_url + variant,
timeout=self.timeout,
pac=self.pac,
require_webdriver_bidi=self.require_webdriver_bidi,
script_metadata=self.script_metadata
)
for variant in self.test_variants
Expand Down Expand Up @@ -1026,6 +1054,7 @@ def manifest_items(self) -> Tuple[Text, List[ManifestItem]]:
url,
timeout=self.timeout,
pac=self.pac,
require_webdriver_bidi=self.require_webdriver_bidi,
testdriver=testdriver,
script_metadata=self.script_metadata
))
Expand Down
15 changes: 10 additions & 5 deletions tools/manifest/tests/test_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,21 +294,26 @@ def test_update_from_json_modified():
# Reload it from JSON
m = manifest.Manifest.from_json("/", json_str)

# Update it with timeout="long"
s2 = SourceFileWithTest("test1", "1"*40, item.TestharnessTest, timeout="long", pac="proxy.pac")
# Update timeout, pac and require_webdriver_bidi
s2 = SourceFileWithTest("test1", "1" * 40, item.TestharnessTest,
timeout="long", pac="proxy.pac",
require_webdriver_bidi="true")
tree, sourcefile_mock = tree_and_sourcefile_mocks([(s2, None, True)])
with mock.patch("tools.manifest.manifest.SourceFile", side_effect=sourcefile_mock):
with mock.patch("tools.manifest.manifest.SourceFile",
side_effect=sourcefile_mock):
m.update(tree)
json_str = m.to_json()
assert json_str == {
'items': {'testharness': {'test1': [
"1"*40,
(None, {'timeout': 'long', 'pac': 'proxy.pac'})
"1" * 40,
(None, {'timeout': 'long', 'pac': 'proxy.pac',
'require_webdriver_bidi': 'true'})
]}},
'url_base': '/',
'version': 8
}


def test_manifest_spec_to_json():
m = manifest.Manifest("")

Expand Down
92 changes: 92 additions & 0 deletions tools/manifest/tests/test_sourcefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,95 @@ def test_page_ranges_invalid(page_ranges):
def test_hash():
s = SourceFile("/", "foo", "/", contents=b"Hello, World!")
assert "b45ef6fec89518d314f546fd6c3025367b721684" == s.hash


REQUIRE_WEBDRIVER_BIDI_VALUES = [None, "true", "false", "SOME_NONSENSE"]


@pytest.mark.parametrize("require_webdriver_bidi_value",
REQUIRE_WEBDRIVER_BIDI_VALUES)
def test_worker_require_webdriver_bidi(require_webdriver_bidi_value):
if require_webdriver_bidi_value is not None:
contents = f"""// META: require_webdriver_bidi={require_webdriver_bidi_value}
importScripts('/resources/testharness.js')
test()""".encode("utf-8")
else:
contents = b"""importScripts('/resources/testharness.js')
test()"""

metadata = list(read_script_metadata(BytesIO(contents), js_meta_re))
assert metadata == ([("require_webdriver_bidi",
require_webdriver_bidi_value)] if require_webdriver_bidi_value is not None else [])

s = create("html/test.worker.js", contents=contents)
assert s.name_is_worker

item_type, items = s.manifest_items()
assert item_type == "testharness"

for item in items:
assert item.require_webdriver_bidi == require_webdriver_bidi_value


@pytest.mark.parametrize("require_webdriver_bidi_value",
REQUIRE_WEBDRIVER_BIDI_VALUES)
def test_window_require_webdriver_bidi(require_webdriver_bidi_value):
if require_webdriver_bidi_value is not None:
contents = f"""// META: require_webdriver_bidi={require_webdriver_bidi_value}
importScripts('/resources/testharness.js')
test()""".encode("utf-8")
else:
contents = b"""importScripts('/resources/testharness.js')
test()"""

metadata = list(read_script_metadata(BytesIO(contents), js_meta_re))
assert metadata == ([("require_webdriver_bidi",
require_webdriver_bidi_value)] if require_webdriver_bidi_value is not None else [])

s = create("html/test.window.js", contents=contents)
assert s.name_is_window

item_type, items = s.manifest_items()
assert item_type == "testharness"

for item in items:
assert item.require_webdriver_bidi == require_webdriver_bidi_value


@pytest.mark.parametrize("require_webdriver_bidi_value",
REQUIRE_WEBDRIVER_BIDI_VALUES)
def test_multi_global_require_webdriver_bidi(require_webdriver_bidi_value):
if require_webdriver_bidi_value is not None:
contents = f"""// META: require_webdriver_bidi={require_webdriver_bidi_value}
importScripts('/resources/testharness.js')
test()""".encode("utf-8")
else:
contents = b"""importScripts('/resources/testharness.js')
test()"""

metadata = list(read_script_metadata(BytesIO(contents), js_meta_re))
assert metadata == ([("require_webdriver_bidi",
require_webdriver_bidi_value)] if require_webdriver_bidi_value is not None else [])

s = create("html/test.any.js", contents=contents)
assert s.name_is_multi_global

item_type, items = s.manifest_items()
assert item_type == "testharness"

for item in items:
assert item.require_webdriver_bidi == require_webdriver_bidi_value


@pytest.mark.parametrize("require_webdriver_bidi_value",
REQUIRE_WEBDRIVER_BIDI_VALUES)
def test_html_require_webdriver_bidi(require_webdriver_bidi_value):
if require_webdriver_bidi_value is not None:
content = f"<meta name=require_webdriver_bidi content={require_webdriver_bidi_value} />".encode(
"utf-8")
else:
content = b""

s = create("test.html", content)

assert s.require_webdriver_bidi == require_webdriver_bidi_value
22 changes: 15 additions & 7 deletions tools/wptrunner/wptrunner/wpttest.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,18 @@ class Test(ABC):
default_timeout = 10 # seconds
long_timeout = 60 # seconds

def __init__(self, url_base, tests_root, url, inherit_metadata, test_metadata,
timeout=None, path=None, protocol="http", subdomain=False, pac=None):
def __init__(self, url_base, tests_root, url, inherit_metadata,
test_metadata,
timeout=None, path=None, protocol="http", subdomain=False, pac=None,
require_webdriver_bidi=None):
self.url_base = url_base
self.tests_root = tests_root
self.url = url
self._inherit_metadata = inherit_metadata
self._test_metadata = test_metadata
self.timeout = timeout if timeout is not None else self.default_timeout
self.path = path
self.require_webdriver_bidi = require_webdriver_bidi
self.subdomain = subdomain
self.environment = {"url_base": url_base,
"protocol": protocol,
Expand Down Expand Up @@ -480,11 +483,14 @@ class TestharnessTest(Test):
subtest_result_cls = TestharnessSubtestResult
test_type = "testharness"

def __init__(self, url_base, tests_root, url, inherit_metadata, test_metadata,
timeout=None, path=None, protocol="http", testdriver=False,
jsshell=False, scripts=None, subdomain=False, pac=None):
Test.__init__(self, url_base, tests_root, url, inherit_metadata, test_metadata, timeout,
path, protocol, subdomain, pac)
def __init__(self, url_base, tests_root, url, inherit_metadata,
test_metadata,
timeout=None, path=None, protocol="http", testdriver=False,
jsshell=False, scripts=None, subdomain=False, pac=None,
require_webdriver_bidi=None):
Test.__init__(self, url_base, tests_root, url, inherit_metadata,
test_metadata, timeout,
path, protocol, subdomain, pac, require_webdriver_bidi)

self.testdriver = testdriver
self.jsshell = jsshell
Expand All @@ -494,6 +500,7 @@ def __init__(self, url_base, tests_root, url, inherit_metadata, test_metadata,
def from_manifest(cls, manifest_file, manifest_item, inherit_metadata, test_metadata):
timeout = cls.long_timeout if manifest_item.timeout == "long" else cls.default_timeout
pac = manifest_item.pac
require_webdriver_bidi = manifest_item.require_webdriver_bidi
testdriver = manifest_item.testdriver if hasattr(manifest_item, "testdriver") else False
jsshell = manifest_item.jsshell if hasattr(manifest_item, "jsshell") else False
script_metadata = manifest_item.script_metadata or []
Expand All @@ -506,6 +513,7 @@ def from_manifest(cls, manifest_file, manifest_item, inherit_metadata, test_meta
test_metadata,
timeout=timeout,
pac=pac,
require_webdriver_bidi=require_webdriver_bidi,
path=os.path.join(manifest_file.tests_root, manifest_item.path),
protocol=server_protocol(manifest_item),
testdriver=testdriver,
Expand Down