-
Notifications
You must be signed in to change notification settings - Fork 3.6k
feat(serve): Add server-side handlers for Test262 tests [pt 2/5] #56841
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
base: feat/test262-manifest-tooling
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,11 +19,12 @@ | |
| from io import IOBase | ||
| from itertools import chain, product | ||
| from html5lib import html5parser | ||
| from typing import ClassVar, List, Optional, Set, Tuple | ||
| from typing import ClassVar, List, Optional, Set, Tuple, Union | ||
|
|
||
| from localpaths import repo_root # type: ignore | ||
|
|
||
| from manifest.sourcefile import read_script_metadata, js_meta_re, parse_variants # type: ignore | ||
| from manifest.test262 import parse as test262_parse # type: ignore | ||
| from wptserve import server as wptserve, handlers | ||
| from wptserve import stash | ||
| from wptserve import config | ||
|
|
@@ -327,6 +328,75 @@ class ExtensionHandler(HtmlWrapperHandler): | |
| """ | ||
|
|
||
|
|
||
| class Test262WindowHandler(HtmlWrapperHandler): | ||
| path_replace = [(".test262.html", ".js", ".test262-test.html")] | ||
| wrapper = """<!doctype html> | ||
| <meta charset=utf-8> | ||
| <title>Test</title> | ||
| <script src="/resources/test262/testharness.js"></script> | ||
| <script src="/resources/testharnessreport.js"></script> | ||
| %(meta)s | ||
| %(script)s | ||
| <div id=log></div> | ||
| <iframe id="test262-iframe" src="%(path)s"></iframe>""" | ||
|
|
||
|
|
||
| class Test262WindowTestHandler(HtmlWrapperHandler): | ||
| # For SHAB | ||
| headers = [('Cross-Origin-Opener-Policy', 'same-origin'), | ||
| ('Cross-Origin-Embedder-Policy', 'require-corp')] | ||
|
|
||
| path_replace: Union[List[Tuple[str, str]], List[Tuple[str, str, str]]] = [(".test262-test.html", ".js")] | ||
|
|
||
| pre_wrapper = """<!doctype html> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is split into multiple variables so we can reuse this part in subclasses? Would be good to mention that in a comment, otherwise it looks rather strange.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
| <meta charset=utf-8> | ||
| <title>Test</title> | ||
| <script src="/resources/test262/testharness-client.js"></script> | ||
| <script src="/third_party/test262/harness/assert.js"></script> | ||
| <script src="/third_party/test262/harness/sta.js"></script> | ||
| <script src="/resources/test262/harness-adapter.js"></script> | ||
| %(meta)s | ||
| %(script)s""" | ||
| wrapper = pre_wrapper + """<script>test262Setup()</script> | ||
| <script src="%(path)s"></script> | ||
| <script>test262Done()</script>""" | ||
|
|
||
| def _get_metadata(self, request): | ||
| path = self._get_filesystem_path(request) | ||
| with open(path, encoding='utf-8') as f: | ||
| test_record = test262_parse(logging.getLogger(), f.read(), path) | ||
| yield from (('script', "/third_party/test262/harness/%s" % filename) | ||
| for filename in (test_record.includes or [])) | ||
|
|
||
| expected_error = (test_record.negative or {}).get('type', None) | ||
| if expected_error is not None: | ||
| yield ('negative', expected_error) | ||
|
|
||
| def _meta_replacement(self, key: str, value: str) -> Optional[str]: | ||
| if key == 'negative': | ||
| return """<script>test262Negative('%s')</script>""" % value | ||
| return None | ||
|
|
||
|
|
||
| class Test262WindowModuleHandler(Test262WindowHandler): | ||
| path_replace = [(".test262-module.html", ".js", ".test262-module-test.html")] | ||
|
|
||
| class Test262WindowModuleTestHandler(Test262WindowTestHandler): | ||
| path_replace = [(".test262-module-test.html", ".js")] | ||
| wrapper = Test262WindowTestHandler.pre_wrapper + """<script type="module"> | ||
| test262Setup(); | ||
| import {} from "%(path)s"; | ||
| test262Done(); | ||
| </script>""" | ||
|
|
||
|
|
||
| class Test262StrictWindowHandler(Test262WindowHandler): | ||
| path_replace = [(".test262.strict.html", ".js", ".test262-test.strict.html")] | ||
|
|
||
| class Test262StrictWindowTestHandler(Test262WindowTestHandler): | ||
| path_replace = [(".test262-test.strict.html", ".js", ".test262.strict.js")] | ||
|
|
||
|
|
||
| class WindowModulesHandler(HtmlWrapperHandler): | ||
| global_type = "window-module" | ||
| path_replace = [(".any.window-module.html", ".any.js")] | ||
|
|
@@ -574,6 +644,31 @@ class ShadowRealmInAudioWorkletHandler(HtmlWrapperHandler): | |
| """ | ||
|
|
||
|
|
||
| class Test262StrictHandler(WrapperHandler): | ||
| path_replace = [(".test262.strict.js", ".js")] | ||
| headers = [('Content-Type', 'text/javascript')] | ||
| wrapper = """ | ||
| "use strict"; | ||
| %(script)s | ||
| """ | ||
|
|
||
| def _meta_replacement(self, key, value): | ||
| return None | ||
|
|
||
| def _get_metadata(self, request): | ||
| # Abuse the script metadata to inline the script content so as to | ||
| # prepend "use strict". | ||
| path = self._get_filesystem_path(request) | ||
| try: | ||
| with open(path, encoding='utf-8') as f: | ||
| yield ('script', f.read()) | ||
| except OSError: | ||
| raise HTTPException(404) | ||
|
|
||
| def _script_replacement(self, key, value): | ||
|
||
| return value | ||
|
|
||
|
|
||
| class BaseWorkerHandler(WrapperHandler): | ||
| headers = [("Content-Type", "text/javascript")] | ||
|
|
||
|
|
@@ -787,6 +882,13 @@ def add_mount_point(self, url_base, path): | |
| ("GET", "*.worker.html", WorkersHandler), | ||
| ("GET", "*.worker-module.html", WorkerModulesHandler), | ||
| ("GET", "*.window.html", WindowHandler), | ||
| ("GET", "*.test262.html", Test262WindowHandler), | ||
| ("GET", "*.test262-test.html", Test262WindowTestHandler), | ||
| ("GET", "*.test262-module.html", Test262WindowModuleHandler), | ||
| ("GET", "*.test262-module-test.html", Test262WindowModuleTestHandler), | ||
| ("GET", "*.test262.strict.html", Test262StrictWindowHandler), | ||
| ("GET", "*.test262-test.strict.html", Test262StrictWindowTestHandler), | ||
| ("GET", "*.test262.strict.js", Test262StrictHandler), | ||
| ("GET", "*.extension.html", ExtensionHandler), | ||
| ("GET", "*.any.html", AnyHtmlHandler), | ||
| ("GET", "*.any.sharedworker.html", SharedWorkersHandler), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have a type annotation here but nowhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! Initially,
Test262WindowTestHandlerdefinedpath_replacewith 2-element tuples, but its subclass,Test262StrictWindowTestHandler, needed 3-element tuples. This caused amypyerror because the subclass was essentially trying to override a parent attribute with a different type signature.My first thought was to use a
Uniontype hint on the parent'spath_replaceto tellmypyit could handle both 2-tuple and 3-tuple lists.Now, I will create a new base class,
Test262WindowTestBaseHandler. This new base class now holds all the shared logic, and bothTest262WindowTestHandlerandTest262StrictWindowTestHandlerdefine their ownpath_replaceattributes independently.