diff --git a/tests/wpt/metadata-layout-2020/FileAPI/url/url-charset.window.js.ini b/tests/wpt/metadata-layout-2020/FileAPI/url/url-charset.window.js.ini deleted file mode 100644 index a9005e45d6e..00000000000 --- a/tests/wpt/metadata-layout-2020/FileAPI/url/url-charset.window.js.ini +++ /dev/null @@ -1,8 +0,0 @@ -[url-charset.window.html] - expected: TIMEOUT - [Blob charset should override any auto-detected charset.] - expected: TIMEOUT - - [Blob charset should override .] - expected: TIMEOUT - diff --git a/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini index 3605e8f3fc9..76b44d9e9cf 100644 --- a/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini +++ b/tests/wpt/metadata-layout-2020/FileAPI/url/url-in-tags-revoke.window.js.ini @@ -4,7 +4,7 @@ expected: TIMEOUT [Opening a blob URL in a new window immediately before revoking it works.] - expected: TIMEOUT + expected: FAIL [Fetching a blob URL immediately before revoking it works in an iframe.] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-backgrounds/border-image-slice-005.htm.ini b/tests/wpt/metadata-layout-2020/css/css-backgrounds/border-image-slice-005.htm.ini new file mode 100644 index 00000000000..df5cf5244c0 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-backgrounds/border-image-slice-005.htm.ini @@ -0,0 +1,2 @@ +[border-image-slice-005.htm] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-backgrounds/border-image-slice-007.htm.ini b/tests/wpt/metadata-layout-2020/css/css-backgrounds/border-image-slice-007.htm.ini new file mode 100644 index 00000000000..2670f31ca12 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-backgrounds/border-image-slice-007.htm.ini @@ -0,0 +1,2 @@ +[border-image-slice-007.htm] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPosition.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPosition.html.ini index 23c61ede1a1..c131078eace 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPosition.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPosition.html.ini @@ -17,6 +17,3 @@ [test the top of layer] expected: FAIL - [test some point of the element: top left corner] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/custom-elements/reactions/HTMLMediaElement.html.ini b/tests/wpt/metadata-layout-2020/custom-elements/reactions/HTMLMediaElement.html.ini deleted file mode 100644 index 2ca05f57bb0..00000000000 --- a/tests/wpt/metadata-layout-2020/custom-elements/reactions/HTMLMediaElement.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[HTMLMediaElement.html] - expected: TIMEOUT diff --git a/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini b/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini index cedba2e75d0..58aa7d286e3 100644 --- a/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini +++ b/tests/wpt/metadata-layout-2020/fetch/content-type/response.window.js.ini @@ -312,9 +312,6 @@ [Response: combined response Content-Type: text/html;" \\" text/plain ";charset=GBK] expected: NOTRUN - [ + diff --git a/tests/wpt/web-platform-tests/origin-isolation/resources/frame.html b/tests/wpt/web-platform-tests/origin-isolation/resources/frame.html index 8f35d2703e7..537de07b140 100644 --- a/tests/wpt/web-platform-tests/origin-isolation/resources/frame.html +++ b/tests/wpt/web-platform-tests/origin-isolation/resources/frame.html @@ -1,3 +1,12 @@ A frame included by a test page + + diff --git a/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js b/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js index 800c0a4a978..084d692ee0a 100644 --- a/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js +++ b/tests/wpt/web-platform-tests/resources/chromium/webxr-test.js @@ -13,6 +13,8 @@ const default_stage_parameters = { bounds: null }; +const default_framebuffer_scale = 0.7; + function getMatrixFromTransform(transform) { const x = transform.orientation[0]; const y = transform.orientation[1]; @@ -416,6 +418,8 @@ class MockRuntime { this.world_ = fakeDeviceInit.world; } + this.defaultFramebufferScale_ = default_framebuffer_scale; + // This appropriately handles if the coordinates are null this.setBoundsGeometry(fakeDeviceInit.boundsCoordinates); @@ -625,8 +629,7 @@ class MockRuntime { }), renderWidth: 20, renderHeight: 20 - }, - webxrDefaultFramebufferScale: 0.7, + } }; } @@ -1013,6 +1016,7 @@ class MockRuntime { clientReceiver: clientReceiver, displayInfo: this.displayInfo_, enabledFeatures: enabled_features, + defaultFramebufferScale: this.defaultFramebufferScale_, } }); } else { diff --git a/tests/wpt/web-platform-tests/tools/ci/run_tc.py b/tests/wpt/web-platform-tests/tools/ci/run_tc.py index 3a3b0d8090b..69bf72fb745 100755 --- a/tests/wpt/web-platform-tests/tools/ci/run_tc.py +++ b/tests/wpt/web-platform-tests/tools/ci/run_tc.py @@ -43,16 +43,10 @@ import subprocess import sys import tarfile import tempfile -import time import zipfile -from socket import error as SocketError # NOQA: N812 -import errno -try: - from urllib2 import urlopen -except ImportError: - # Python 3 case - from urllib.request import urlopen +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from wpt.utils import get_download_to_descriptor root = os.path.abspath( os.path.join(os.path.dirname(__file__), @@ -153,79 +147,12 @@ def install_chrome(channel): dest = os.path.join("/tmp", deb_archive) deb_url = "https://dl.google.com/linux/direct/%s" % deb_archive with open(dest, "w") as f: - download_url_to_descriptor(f, deb_url) + get_download_to_descriptor(f, deb_url) run(["sudo", "apt-get", "-qqy", "update"]) run(["sudo", "gdebi", "-qn", "/tmp/%s" % deb_archive]) -def install_webkitgtk_from_apt_repository(channel): - # Configure webkitgtk.org/debian repository for $channel and pin it with maximum priority - run(["sudo", "apt-key", "adv", "--fetch-keys", "https://webkitgtk.org/debian/apt.key"]) - with open("/tmp/webkitgtk.list", "w") as f: - f.write("deb [arch=amd64] https://webkitgtk.org/apt bionic-wpt-webkit-updates %s\n" % channel) - run(["sudo", "mv", "/tmp/webkitgtk.list", "/etc/apt/sources.list.d/"]) - with open("/tmp/99webkitgtk", "w") as f: - f.write("Package: *\nPin: origin webkitgtk.org\nPin-Priority: 1999\n") - run(["sudo", "mv", "/tmp/99webkitgtk", "/etc/apt/preferences.d/"]) - # Install webkit2gtk from the webkitgtk.org/apt repository for $channel - run(["sudo", "apt-get", "-qqy", "update"]) - run(["sudo", "apt-get", "-qqy", "upgrade"]) - run(["sudo", "apt-get", "-qqy", "-t", "bionic-wpt-webkit-updates", "install", "webkit2gtk-driver"]) - - -def download_url_to_descriptor(fd, url, max_retries=5): - """Download an URL in chunks and saves it to a file descriptor (truncating it) - It doesn't close the descriptor, but flushes it on success. - It retries the download in case of ECONNRESET up to max_retries.""" - if max_retries < 1: - max_retries = 1 - wait = 2 - for current_retry in range(1, max_retries+1): - try: - print("INFO: Downloading %s Try %d/%d" % (url, current_retry, max_retries)) - resp = urlopen(url) - # We may come here in a retry, ensure to truncate fd before start writing. - fd.seek(0) - fd.truncate(0) - while True: - chunk = resp.read(16*1024) - if not chunk: - break # Download finished - fd.write(chunk) - fd.flush() - # Success - return - except SocketError as e: - if current_retry < max_retries and e.errno == errno.ECONNRESET: - # Retry - print("ERROR: Connection reset by peer. Retrying after %ds..." % wait) - time.sleep(wait) - wait *= 2 - else: - # Maximum retries or unknown error - raise - - -def install_webkitgtk_from_tarball_bundle(channel): - with tempfile.NamedTemporaryFile(suffix=".tar.xz") as temp_tarball: - download_url = "https://webkitgtk.org/built-products/nightly/webkitgtk-nightly-build-last.tar.xz" - download_url_to_descriptor(temp_tarball, download_url) - run(["sudo", "tar", "xfa", temp_tarball.name, "-C", "/"]) - # Install dependencies - run(["sudo", "apt-get", "-qqy", "update"]) - run(["sudo", "/opt/webkitgtk/nightly/install-dependencies"]) - - -def install_webkitgtk(channel): - if channel in ("experimental", "dev", "nightly"): - install_webkitgtk_from_tarball_bundle(channel) - elif channel in ("beta", "stable"): - install_webkitgtk_from_apt_repository(channel) - else: - raise ValueError("Unrecognized release channel: %s" % channel) - - def start_xvfb(): start(["sudo", "Xvfb", os.environ["DISPLAY"], "-screen", "0", "%sx%sx%s" % (os.environ["SCREEN_WIDTH"], @@ -270,7 +197,7 @@ def download_artifacts(artifacts): base_url = task_url(artifact["task"]) if artifact["task"] not in artifact_list_by_task: with tempfile.TemporaryFile() as f: - download_url_to_descriptor(f, base_url + "/artifacts") + get_download_to_descriptor(f, base_url + "/artifacts") f.seek(0) artifacts_data = json.load(f) artifact_list_by_task[artifact["task"]] = artifacts_data @@ -290,7 +217,7 @@ def download_artifacts(artifacts): if not os.path.exists(dest_dir): os.makedirs(dest_dir) with open(dest_path, "wb") as f: - download_url_to_descriptor(f, url) + get_download_to_descriptor(f, url) if artifact.get("extract"): unpack(dest_path) @@ -327,9 +254,6 @@ def setup_environment(args): # later in taskcluster-run.py. if args.channel != "nightly": install_chrome(args.channel) - elif "webkitgtk_minibrowser" in args.browser: - assert args.channel is not None - install_webkitgtk(args.channel) if args.xvfb: start_xvfb() @@ -436,7 +360,7 @@ def fetch_event_data(): return None with tempfile.TemporaryFile() as f: - download_url_to_descriptor(f, task_url(task_id)) + get_download_to_descriptor(f, task_url(task_id)) f.seek(0) task_data = json.load(f) event_data = task_data.get("extra", {}).get("github_event") diff --git a/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py b/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py index 245ee7fa592..a4bd72a8c21 100755 --- a/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py +++ b/tests/wpt/web-platform-tests/tools/ci/taskcluster-run.py @@ -20,6 +20,8 @@ def get_browser_args(product, channel): return ["--install-browser", "--processes=12"] if product == "chrome" and channel == "nightly": return ["--install-browser", "--install-webdriver"] + if product == "webkitgtk_minibrowser": + return ["--install-browser"] return [] diff --git a/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml b/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml index 1b5c7acfd74..78891bf3023 100644 --- a/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml +++ b/tests/wpt/web-platform-tests/tools/ci/tc/tasks/test.yml @@ -206,6 +206,12 @@ tasks: use: - trigger-weekly - trigger-push + - vars: + browser: webkitgtk_minibrowser + channel: beta + use: + - trigger-weekly + - trigger-push - vars: browser: servo channel: nightly diff --git a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py index f817ec81a96..e836b19a158 100644 --- a/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py +++ b/tests/wpt/web-platform-tests/tools/webdriver/webdriver/transport.py @@ -2,6 +2,7 @@ import json import select from six import text_type, PY3 +from six.moves.collections_abc import Mapping from six.moves.http_client import HTTPConnection from six.moves.urllib import parse as urlparse @@ -10,6 +11,56 @@ from . import error """Implements HTTP transport for the WebDriver wire protocol.""" +missing = object() + + +class ResponseHeaders(Mapping): + """Read-only dictionary-like API for accessing response headers. + + This class: + * Normalizes the header keys it is built with to lowercase (such that + iterating the items will return lowercase header keys). + * Has case-insensitive header lookup. + * Always returns all header values that have the same name, separated by + commas. + + It does not ensure header types (e.g. binary vs string). + """ + def __init__(self, items): + self.headers_dict = {} + for key, value in items: + key = key.lower() + if key not in self.headers_dict: + self.headers_dict[key] = [] + self.headers_dict[key].append(value) + + def __getitem__(self, key): + """Get all headers of a certain (case-insensitive) name. If there is + more than one, the values are returned comma separated""" + values = self.headers_dict[key.lower()] + if len(values) == 1: + return values[0] + else: + return ", ".join(values) + + def get_list(self, key, default=missing): + """Get all the header values for a particular field name as a list""" + try: + return self.headers_dict[key.lower()] + except KeyError: + if default is not missing: + return default + else: + raise + + def __iter__(self): + for item in self.headers_dict: + yield item + + def __len__(self): + return len(self.headers_dict) + + class Response(object): """ Describes an HTTP response received from a remote end whose @@ -40,7 +91,7 @@ class Response(object): def from_http(cls, http_response, decoder=json.JSONDecoder, **kwargs): try: body = json.load(http_response, cls=decoder, **kwargs) - headers = dict(http_response.getheaders()) + headers = ResponseHeaders(http_response.getheaders()) except ValueError: raise ValueError("Failed to decode response body as JSON:\n" + http_response.read()) diff --git a/tests/wpt/web-platform-tests/tools/wpt/browser.py b/tests/wpt/web-platform-tests/tools/wpt/browser.py index 35f60d1620b..13ffa3f08b3 100644 --- a/tests/wpt/web-platform-tests/tools/wpt/browser.py +++ b/tests/wpt/web-platform-tests/tools/wpt/browser.py @@ -12,7 +12,7 @@ from distutils.spawn import find_executable from six.moves.urllib.parse import urlsplit import requests -from .utils import call, get, rmtree, untar, unzip +from .utils import call, get, rmtree, untar, unzip, get_download_to_descriptor, sha256sum uname = platform.uname() @@ -110,7 +110,7 @@ class Browser(object): return NotImplemented @abstractmethod - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): """Find the binary of the WebDriver.""" return NotImplemented @@ -297,7 +297,7 @@ class Firefox(Browser): return None return path - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("geckodriver") def get_version_and_channel(self, binary): @@ -506,7 +506,7 @@ class FirefoxAndroid(Browser): def find_binary(self, venv_path=None, channel=None): return self.apk_path - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): raise NotImplementedError def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -570,19 +570,21 @@ class Chrome(Browser): chrome_version = chrome_version.split(' ')[0] url = "https://storage.googleapis.com/chrome-wpt-mojom/%s/linux64/mojojs.zip" % chrome_version - last_url_file = os.path.join(dest, "mojojs", "gen", "DOWNLOADED_FROM") + extracted = os.path.join(dest, "mojojs", "gen") + last_url_file = os.path.join(extracted, "DOWNLOADED_FROM") if os.path.exists(last_url_file): with open(last_url_file, "rt") as f: last_url = f.read().strip() if last_url == url: self.logger.info("Mojo bindings already up to date") - return - rmtree(os.path.join(dest, "mojojs", "gen")) + return extracted + rmtree(extracted) self.logger.info("Downloading Mojo bindings from %s" % url) unzip(get(url).raw, dest) with open(last_url_file, "wt") as f: f.write(url) + return extracted def _chromedriver_platform_string(self): platform = self.platforms.get(uname[0]) @@ -656,7 +658,7 @@ class Chrome(Browser): self.logger.warning("Unable to find the browser binary.") return None - def find_webdriver(self, channel=None, browser_binary=None): + def find_webdriver(self, venv_path=None, channel=None, browser_binary=None): return find_executable("chromedriver") def webdriver_supports_browser(self, webdriver_binary, browser_binary): @@ -824,7 +826,7 @@ class ChromeAndroidBase(Browser): def find_binary(self, venv_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("chromedriver") def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -931,7 +933,7 @@ class ChromeiOS(Browser): def find_binary(self, venv_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): raise NotImplementedError def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -986,7 +988,7 @@ class Opera(Browser): def find_binary(self, venv_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("operadriver") def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -1063,7 +1065,7 @@ class EdgeChromium(Browser): return find_executable("Microsoft Edge Canary", os.pathsep.join(macpaths)) return binary - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("msedgedriver") def webdriver_supports_browser(self, webdriver_binary, browser_binary): @@ -1178,7 +1180,7 @@ class Edge(Browser): def find_binary(self, venv_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("MicrosoftWebDriver") def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -1212,7 +1214,7 @@ class InternetExplorer(Browser): def find_binary(self, venv_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("IEDriverServer.exe") def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -1240,7 +1242,7 @@ class Safari(Browser): def find_binary(self, venv_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): path = None if channel == "preview": path = "/Applications/Safari Technology Preview.app/Contents/MacOS" @@ -1332,7 +1334,7 @@ class Servo(Browser): path = find_executable("servo") return path - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return None def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -1365,7 +1367,7 @@ class Sauce(Browser): def find_binary(self, venev_path=None, channel=None): raise NotImplementedError - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): raise NotImplementedError def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -1390,7 +1392,7 @@ class WebKit(Browser): def find_binary(self, venv_path=None, channel=None): return None - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return None def install_webdriver(self, dest=None, channel=None, browser_binary=None): @@ -1402,7 +1404,101 @@ class WebKit(Browser): class WebKitGTKMiniBrowser(WebKit): + + def _get_osidversion(self): + with open('/etc/os-release', 'r') as osrelease_handle: + for line in osrelease_handle.readlines(): + if line.startswith('ID='): + os_id = line.split('=')[1].strip().strip('"') + if line.startswith('VERSION_ID='): + version_id = line.split('=')[1].strip().strip('"') + assert(os_id) + assert(version_id) + osidversion = os_id + '-' + version_id + assert(' ' not in osidversion) + assert(len(osidversion) > 3) + return osidversion.capitalize() + + + def download(self, dest=None, channel=None, rename=None): + base_dowload_uri = "https://webkitgtk.org/built-products/" + base_download_dir = base_dowload_uri + "x86_64/release/" + channel + "/" + self._get_osidversion() + "/MiniBrowser/" + try: + response = get(base_download_dir + "LAST-IS") + except requests.exceptions.HTTPError as e: + if e.response.status_code == 404: + raise RuntimeError("Can't find a WebKitGTK MiniBrowser %s bundle for %s at %s" + % (channel, self._get_osidversion(), base_dowload_uri)) + raise + + bundle_filename = response.text.strip() + bundle_url = base_download_dir + bundle_filename + + if dest is None: + dest = self._get_dest(None, channel) + bundle_file_path = os.path.join(dest, bundle_filename) + + self.logger.info("Downloading WebKitGTK MiniBrowser bundle from %s" % bundle_url) + with open(bundle_file_path, "w+b") as f: + get_download_to_descriptor(f, bundle_url) + + bundle_filename_no_ext, _ = os.path.splitext(bundle_filename) + bundle_hash_url = base_download_dir + bundle_filename_no_ext + ".sha256sum" + bundle_expected_hash = get(bundle_hash_url).text.strip().split(" ")[0] + bundle_computed_hash = sha256sum(bundle_file_path) + + if bundle_expected_hash != bundle_computed_hash: + self.logger.error("Calculated SHA256 hash is %s but was expecting %s" % (bundle_computed_hash,bundle_expected_hash)) + raise RuntimeError("The WebKitGTK MiniBrowser bundle at %s has incorrect SHA256 hash." % bundle_file_path) + return bundle_file_path + + def install(self, dest=None, channel=None, prompt=True): + dest = self._get_dest(dest, channel) + bundle_path = self.download(dest, channel) + bundle_uncompress_directory = os.path.join(dest, "webkitgtk_minibrowser") + + # Clean it from previous runs + if os.path.exists(bundle_uncompress_directory): + rmtree(bundle_uncompress_directory) + os.mkdir(bundle_uncompress_directory) + + with open(bundle_path, "rb") as f: + unzip(f, bundle_uncompress_directory) + + install_dep_script = os.path.join(bundle_uncompress_directory, "install-dependencies.sh") + if os.path.isfile(install_dep_script): + self.logger.info("Executing install-dependencies.sh script from bundle.") + install_dep_cmd = [install_dep_script] + if not prompt: + install_dep_cmd.append("--autoinstall") + # use subprocess.check_call() directly to display unbuffered stdout/stderr in real-time. + subprocess.check_call(install_dep_cmd) + + minibrowser_path = os.path.join(bundle_uncompress_directory, "MiniBrowser") + if not os.path.isfile(minibrowser_path): + raise RuntimeError("Can't find a MiniBrowser binary at %s" % minibrowser_path) + + os.remove(bundle_path) + install_ok_file = os.path.join(bundle_uncompress_directory, ".installation-ok") + open(install_ok_file, "w").close() # touch + self.logger.info("WebKitGTK MiniBrowser bundle for channel %s installed." % channel) + return minibrowser_path + + def _find_executable_in_channel_bundle(self, binary, venv_path=None, channel=None): + if venv_path: + venv_base_path = self._get_dest(venv_path, channel) + bundle_dir = os.path.join(venv_base_path, "webkitgtk_minibrowser") + install_ok_file = os.path.join(bundle_dir, ".installation-ok") + if os.path.isfile(install_ok_file): + return find_executable(binary, bundle_dir) + return None + + def find_binary(self, venv_path=None, channel=None): + minibrowser_path = self._find_executable_in_channel_bundle("MiniBrowser", venv_path, channel) + if minibrowser_path: + return minibrowser_path + libexecpaths = ["/usr/libexec/webkit2gtk-4.0"] # Fedora path triplet = "x86_64-linux-gnu" # Try to use GCC to detect this machine triplet @@ -1414,15 +1510,13 @@ class WebKitGTKMiniBrowser(WebKit): pass # Add Debian/Ubuntu path libexecpaths.append("/usr/lib/%s/webkit2gtk-4.0" % triplet) - if channel == "nightly": - libexecpaths.append("/opt/webkitgtk/nightly") return find_executable("MiniBrowser", os.pathsep.join(libexecpaths)) - def find_webdriver(self, channel=None): - path = os.environ['PATH'] - if channel == "nightly": - path = "%s:%s" % (path, "/opt/webkitgtk/nightly") - return find_executable("WebKitWebDriver", path) + def find_webdriver(self, venv_path=None, channel=None): + webdriver_path = self._find_executable_in_channel_bundle("WebKitWebDriver", venv_path, channel) + if not webdriver_path: + webdriver_path = find_executable("WebKitWebDriver") + return webdriver_path def version(self, binary=None, webdriver_binary=None): if binary is None: @@ -1456,7 +1550,7 @@ class Epiphany(Browser): def find_binary(self, venv_path=None, channel=None): return find_executable("epiphany") - def find_webdriver(self, channel=None): + def find_webdriver(self, venv_path=None, channel=None): return find_executable("WebKitWebDriver") def install_webdriver(self, dest=None, channel=None, browser_binary=None): diff --git a/tests/wpt/web-platform-tests/tools/wpt/install.py b/tests/wpt/web-platform-tests/tools/wpt/install.py index 81770225428..638065a5301 100644 --- a/tests/wpt/web-platform-tests/tools/wpt/install.py +++ b/tests/wpt/web-platform-tests/tools/wpt/install.py @@ -7,7 +7,8 @@ latest_channels = { 'chrome_android': 'dev', 'edgechromium': 'dev', 'safari': 'preview', - 'servo': 'nightly' + 'servo': 'nightly', + 'webkitgtk_minibrowser': 'nightly' } channel_by_name = { diff --git a/tests/wpt/web-platform-tests/tools/wpt/run.py b/tests/wpt/web-platform-tests/tools/wpt/run.py index f289e097753..dc130a16d11 100644 --- a/tests/wpt/web-platform-tests/tools/wpt/run.py +++ b/tests/wpt/web-platform-tests/tools/wpt/run.py @@ -322,16 +322,21 @@ class Chrome(BrowserSetup): kwargs["binary"] = binary else: raise WptrunError("Unable to locate Chrome binary") + + if kwargs["mojojs_path"]: + kwargs["enable_mojojs"] = True + logger.info("--mojojs-path is provided, enabling MojoJS") # TODO(Hexcles): Enable this everywhere when Chrome 86 becomes stable. - if browser_channel in self.experimental_channels: + elif browser_channel in self.experimental_channels: try: - self.browser.install_mojojs( + path = self.browser.install_mojojs( dest=self.venv.path, channel=browser_channel, browser_binary=kwargs["binary"], ) + kwargs["mojojs_path"] = path kwargs["enable_mojojs"] = True - logger.info("MojoJS enabled") + logger.info("MojoJS enabled automatically (mojojs_path: %s)" % path) except Exception as e: logger.error("Cannot enable MojoJS: %s" % e) @@ -662,18 +667,19 @@ class WebKitGTKMiniBrowser(BrowserSetup): browser_cls = browser.WebKitGTKMiniBrowser def install(self, channel=None): - raise NotImplementedError + if self.prompt_install(self.name): + return self.browser.install(self.venv.path, channel, self.prompt) def setup_kwargs(self, kwargs): if kwargs["binary"] is None: - binary = self.browser.find_binary(channel=kwargs["browser_channel"]) + binary = self.browser.find_binary(venv_path=self.venv.path, channel=kwargs["browser_channel"]) if binary is None: raise WptrunError("Unable to find MiniBrowser binary") kwargs["binary"] = binary if kwargs["webdriver_binary"] is None: - webdriver_binary = self.browser.find_webdriver(channel=kwargs["browser_channel"]) + webdriver_binary = self.browser.find_webdriver(venv_path=self.venv.path, channel=kwargs["browser_channel"]) if webdriver_binary is None: raise WptrunError("Unable to find WebKitWebDriver in PATH") diff --git a/tests/wpt/web-platform-tests/tools/wpt/utils.py b/tests/wpt/web-platform-tests/tools/wpt/utils.py index 6556ff48b36..61dcda5470c 100644 --- a/tests/wpt/web-platform-tests/tools/wpt/utils.py +++ b/tests/wpt/web-platform-tests/tools/wpt/utils.py @@ -5,8 +5,11 @@ import shutil import stat import subprocess import tarfile +import time import zipfile from io import BytesIO +from socket import error as SocketError # NOQA: N812 +from six.moves.urllib.request import urlopen MYPY = False if MYPY: @@ -100,6 +103,41 @@ def get(url): return resp +def get_download_to_descriptor(fd, url, max_retries=5): + """Download an URL in chunks and saves it to a file descriptor (truncating it) + It doesn't close the descriptor, but flushes it on success. + It retries the download in case of ECONNRESET up to max_retries. + This function is meant to download big files directly to the disk without + caching the whole file in memory. + """ + if max_retries < 1: + max_retries = 1 + wait = 2 + for current_retry in range(1, max_retries+1): + try: + logger.info("Downloading %s Try %d/%d" % (url, current_retry, max_retries)) + resp = urlopen(url) + # We may come here in a retry, ensure to truncate fd before start writing. + fd.seek(0) + fd.truncate(0) + while True: + chunk = resp.read(16*1024) + if not chunk: + break # Download finished + fd.write(chunk) + fd.flush() + # Success + return + except SocketError as e: + if current_retry < max_retries and e.errno == errno.ECONNRESET: + # Retry + logger.error("Connection reset by peer. Retrying after %ds..." % wait) + time.sleep(wait) + wait *= 2 + else: + # Maximum retries or unknown error + raise + def rmtree(path): # This works around two issues: # 1. Cannot delete read-only files owned by us (e.g. files extracted from tarballs) @@ -114,3 +152,13 @@ def rmtree(path): raise return shutil.rmtree(path, onerror=handle_remove_readonly) + + +def sha256sum(file_path): + """Computes the SHA256 hash sum of a file""" + from hashlib import sha256 + hash = sha256() + with open(file_path, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b''): + hash.update(chunk) + return hash.hexdigest() diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py index e1812b8740a..2527d26d391 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/environment.py @@ -55,7 +55,7 @@ class TestEnvironment(object): websockets servers""" def __init__(self, test_paths, testharness_timeout_multipler, pause_after_test, debug_info, options, ssl_config, env_extras, - enable_quic=False, serve_mojojs=False): + enable_quic=False, mojojs_path=None): self.test_paths = test_paths self.server = None self.config_ctx = None @@ -72,7 +72,7 @@ class TestEnvironment(object): self.env_extras_cms = None self.ssl_config = ssl_config self.enable_quic = enable_quic - self.serve_mojojs = serve_mojojs + self.mojojs_path = mojojs_path def __enter__(self): self.config_ctx = self.build_config() @@ -217,9 +217,8 @@ class TestEnvironment(object): if "/" not in self.test_paths: del route_builder.mountpoint_routes["/"] - if self.serve_mojojs: - # TODO(Hexcles): Properly pass venv.path in. - route_builder.add_mount_point("/gen/", "_venv2/mojojs/gen") + if self.mojojs_path: + route_builder.add_mount_point("/gen/", self.mojojs_path) return route_builder.get_routes() diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py index 532c795cd3c..9d1d4048095 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptcommandline.py @@ -314,8 +314,12 @@ scheme host and port.""") servo_group = parser.add_argument_group("Chrome-specific") servo_group.add_argument("--enable-mojojs", action="store_true", default=False, - help="Enable MojoJS for testing. Mojo bindings need to be available in " - "_venv2/mojojs.") + help="Enable MojoJS for testing. Note that this flag is usally " + "enabled automatically by `wpt run`, if it succeeds in downloading " + "the right version of mojojs.zip or if --mojojs-path is specified.") + servo_group.add_argument("--mojojs-path", + help="Path to mojojs gen/ directory. If it is not specified, `wpt run` " + "will download and extract mojojs.zip into _venv2/mojojs/gen.") sauce_group = parser.add_argument_group("Sauce Labs-specific") sauce_group.add_argument("--sauce-browser", dest="sauce_browser", diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py index 897b4a9f815..e1d9ef8b1a9 100644 --- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py +++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/wptrunner.py @@ -213,6 +213,8 @@ def run_tests(config, test_paths, product, **kwargs): run_info, **kwargs) + mojojs_path = kwargs["mojojs_path"] if kwargs["enable_mojojs"] else None + recording.set(["startup", "start_environment"]) with env.TestEnvironment(test_paths, testharness_timeout_multipler, @@ -222,7 +224,7 @@ def run_tests(config, test_paths, product, **kwargs): ssl_config, env_extras, kwargs["enable_quic"], - kwargs["enable_mojojs"]) as test_environment: + mojojs_path) as test_environment: recording.set(["startup", "ensure_environment"]) try: test_environment.ensure_started() diff --git a/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-basic-manual.html b/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-basic.html similarity index 79% rename from tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-basic-manual.html rename to tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-basic.html index c5a09f6cb4f..1a43022d292 100644 --- a/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-basic-manual.html +++ b/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-basic.html @@ -3,7 +3,7 @@ WheelEvent - basic wheel event + + + @@ -38,6 +41,7 @@ var wheelbox = document.getElementById("wheelbox"); var scrollbox = document.getElementById("scrollbox"); var test_wheel = async_test("wheel event test"); + var actions_promise; EventRecorder.configure({ mergeEventTypes: ['wheel'], @@ -56,7 +60,10 @@ e.stopPropagation(); this.className = "green"; endTest(); - test_wheel.done(); + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + test_wheel.done(); + }); }); function endTest() { @@ -73,6 +80,12 @@ } EventRecorder.start(); + + // Inject wheel inputs. + actions_promise = new test_driver.Actions() + .scroll(0, 0, 0, 10, {origin: wheelbox}) + .scroll(160, 50, 0, 20, {origin: scrollbox}) + .send(); - + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling-manual.html b/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling.html similarity index 93% rename from tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling-manual.html rename to tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling.html index cae4cf6523b..44e76bff6cb 100644 --- a/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling-manual.html +++ b/tests/wpt/web-platform-tests/uievents/order-of-events/mouse-events/wheel-scrolling.html @@ -13,6 +13,9 @@ + + + @@ -35,6 +38,7 @@
diff --git a/tests/wpt/web-platform-tests/url/resources/setters_tests.json b/tests/wpt/web-platform-tests/url/resources/setters_tests.json index d06fb2cfe62..8aa74d6b8a2 100644 --- a/tests/wpt/web-platform-tests/url/resources/setters_tests.json +++ b/tests/wpt/web-platform-tests/url/resources/setters_tests.json @@ -1672,8 +1672,8 @@ "href": "file://monkey/", "new_value": "\\\\", "expected": { - "href": "file://monkey/", - "pathname": "/" + "href": "file://monkey//", + "pathname": "//" } }, { @@ -1681,8 +1681,8 @@ "href": "file:///unicorn", "new_value": "//\\/", "expected": { - "href": "file:///", - "pathname": "/" + "href": "file://////", + "pathname": "////" } }, { @@ -1690,8 +1690,8 @@ "href": "file:///unicorn", "new_value": "//monkey/..//", "expected": { - "href": "file:///", - "pathname": "/" + "href": "file://///", + "pathname": "///" } }, { diff --git a/tests/wpt/web-platform-tests/url/resources/urltestdata.json b/tests/wpt/web-platform-tests/url/resources/urltestdata.json index 76a8b3a015d..dba7237d88a 100644 --- a/tests/wpt/web-platform-tests/url/resources/urltestdata.json +++ b/tests/wpt/web-platform-tests/url/resources/urltestdata.json @@ -5389,84 +5389,84 @@ { "input": "file:\\\\//", "base": "about:blank", - "href": "file:///", + "href": "file:////", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/", + "pathname": "//", "search": "", "hash": "" }, { "input": "file:\\\\\\\\", "base": "about:blank", - "href": "file:///", + "href": "file:////", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/", + "pathname": "//", "search": "", "hash": "" }, { "input": "file:\\\\\\\\?fox", "base": "about:blank", - "href": "file:///?fox", + "href": "file:////?fox", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/", + "pathname": "//", "search": "?fox", "hash": "" }, { "input": "file:\\\\\\\\#guppy", "base": "about:blank", - "href": "file:///#guppy", + "href": "file:////#guppy", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/", + "pathname": "//", "search": "", "hash": "#guppy" }, { "input": "file://spider///", "base": "about:blank", - "href": "file://spider/", + "href": "file://spider///", "protocol": "file:", "username": "", "password": "", "host": "spider", "hostname": "spider", "port": "", - "pathname": "/", + "pathname": "///", "search": "", "hash": "" }, { "input": "file:\\\\localhost//", "base": "about:blank", - "href": "file:///", + "href": "file:////", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/", + "pathname": "//", "search": "", "hash": "" }, @@ -5487,42 +5487,42 @@ { "input": "file://\\/localhost//cat", "base": "about:blank", - "href": "file:///localhost//cat", + "href": "file:////localhost//cat", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/localhost//cat", + "pathname": "//localhost//cat", "search": "", "hash": "" }, { "input": "file://localhost//a//../..//", "base": "about:blank", - "href": "file:///", + "href": "file://///", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/", + "pathname": "///", "search": "", "hash": "" }, { "input": "/////mouse", "base": "file:///elephant", - "href": "file:///mouse", + "href": "file://///mouse", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/mouse", + "pathname": "///mouse", "search": "", "hash": "" }, @@ -5543,42 +5543,42 @@ { "input": "\\/localhost//pig", "base": "file://lion/", - "href": "file:///pig", + "href": "file:////pig", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/pig", + "pathname": "//pig", "search": "", "hash": "" }, { "input": "//localhost//pig", "base": "file://lion/", - "href": "file:///pig", + "href": "file:////pig", "protocol": "file:", "username": "", "password": "", "host": "", "hostname": "", "port": "", - "pathname": "/pig", + "pathname": "//pig", "search": "", "hash": "" }, { "input": "/..//localhost//pig", "base": "file://lion/", - "href": "file://lion/localhost//pig", + "href": "file://lion//localhost//pig", "protocol": "file:", "username": "", "password": "", "host": "lion", "hostname": "lion", "port": "", - "pathname": "/localhost//pig", + "pathname": "//localhost//pig", "search": "", "hash": "" }, @@ -5629,12 +5629,12 @@ { "input": "C|", "base": "file://host/dir/file", - "href": "file:///C:", + "href": "file://host/C:", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/C:", "search": "", @@ -5643,12 +5643,12 @@ { "input": "C|#", "base": "file://host/dir/file", - "href": "file:///C:#", + "href": "file://host/C:#", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/C:", "search": "", @@ -5657,12 +5657,12 @@ { "input": "C|?", "base": "file://host/dir/file", - "href": "file:///C:?", + "href": "file://host/C:?", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/C:", "search": "", @@ -5671,12 +5671,12 @@ { "input": "C|/", "base": "file://host/dir/file", - "href": "file:///C:/", + "href": "file://host/C:/", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/C:/", "search": "", @@ -5685,12 +5685,12 @@ { "input": "C|\n/", "base": "file://host/dir/file", - "href": "file:///C:/", + "href": "file://host/C:/", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/C:/", "search": "", @@ -5699,12 +5699,12 @@ { "input": "C|\\", "base": "file://host/dir/file", - "href": "file:///C:/", + "href": "file://host/C:/", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/C:/", "search": "", @@ -5784,27 +5784,27 @@ { "input": "/c:/foo/bar", "base": "file://host/path", - "href": "file:///c:/foo/bar", + "href": "file://host/c:/foo/bar", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "host", + "hostname": "host", "port": "", "pathname": "/c:/foo/bar", "search": "", "hash": "" }, - "# Windows drive letter quirk with not empty host", + "# Do not drop the host in the presence of a drive letter", { "input": "file://example.net/C:/", "base": "about:blank", - "href": "file:///C:/", + "href": "file://example.net/C:/", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "example.net", + "hostname": "example.net", "port": "", "pathname": "/C:/", "search": "", @@ -5813,12 +5813,12 @@ { "input": "file://1.2.3.4/C:/", "base": "about:blank", - "href": "file:///C:/", + "href": "file://1.2.3.4/C:/", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "1.2.3.4", + "hostname": "1.2.3.4", "port": "", "pathname": "/C:/", "search": "", @@ -5827,12 +5827,12 @@ { "input": "file://[1::8]/C:/", "base": "about:blank", - "href": "file:///C:/", + "href": "file://[1::8]/C:/", "protocol": "file:", "username": "", "password": "", - "host": "", - "hostname": "", + "host": "[1::8]", + "hostname": "[1::8]", "port": "", "pathname": "/C:/", "search": "", @@ -6034,6 +6034,133 @@ "base": "about:blank", "failure": true }, + "# Additional file URL tetsts for (https://github.com/whatwg/url/issues/405)", + { + "input": "file://localhost//a//../..//foo", + "base": "about:blank", + "href": "file://///foo", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///foo", + "search": "", + "hash": "" + }, + { + "input": "file://localhost////foo", + "base": "about:blank", + "href": "file://////foo", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "////foo", + "search": "", + "hash": "" + }, + { + "input": "file:////foo", + "base": "about:blank", + "href": "file:////foo", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//foo", + "search": "", + "hash": "" + }, + { + "input": "file:///one/two", + "base": "file:///", + "href": "file:///one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/one/two", + "search": "", + "hash": "" + }, + { + "input": "file:////one/two", + "base": "file:///", + "href": "file:////one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//one/two", + "search": "", + "hash": "" + }, + { + "input": "//one/two", + "base": "file:///", + "href": "file://one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "one", + "hostname": "one", + "port": "", + "pathname": "/two", + "search": "", + "hash": "" + }, + { + "input": "///one/two", + "base": "file:///", + "href": "file:///one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/one/two", + "search": "", + "hash": "" + }, + { + "input": "////one/two", + "base": "file:///", + "href": "file:////one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//one/two", + "search": "", + "hash": "" + }, + { + "input": "file:///.//", + "base": "file:////", + "href": "file:////", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, "# IPv6 tests", { "input": "http://[1:0::]", diff --git a/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py b/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py index 5bd7f5b38e7..3c3d677c90e 100644 --- a/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py +++ b/tests/wpt/web-platform-tests/webdriver/tests/support/asserts.py @@ -2,7 +2,7 @@ import base64 import imghdr import struct -from six import ensure_binary, text_type, PY3 +from six import ensure_binary, text_type from webdriver import Element, NoSuchAlertException, WebDriverException @@ -83,15 +83,8 @@ def assert_response_headers(headers): """ assert 'cache-control' in headers assert 'no-cache' == headers['cache-control'] - # In Python 2, HTTPResponse normalizes header keys to lowercase, whereas - # Python 3 preserves the case. See - # https://github.com/web-platform-tests/wpt/pull/22858#issuecomment-612656097 - if PY3: - assert 'Content-Type' in headers - assert 'application/json; charset=utf-8' == headers['Content-Type'] - else: - assert 'content-type' in headers - assert 'application/json; charset=utf-8' == headers['content-type'] + assert 'content-type' in headers + assert 'application/json; charset=utf-8' == headers['content-type'] def assert_dialog_handled(session, expected_text, expected_retval): diff --git a/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceServers.html b/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceServers.html index 2ef99bf59c8..1cbf1d6c1da 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceServers.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCConfiguration-iceServers.html @@ -29,21 +29,14 @@ 4.2.2. RTCIceCredentialType Enum enum RTCIceCredentialType { - "password", - "oauth" - }; - - 4.2.3. RTCOAuthCredential Dictionary - dictionary RTCOAuthCredential { - required DOMString macKey; - required DOMString accessToken; + "password" }; 4.2.4. RTCIceServer Dictionary dictionary RTCIceServer { required (DOMString or sequence) urls; DOMString username; - (DOMString or RTCOAuthCredential) credential; + DOMString credential; RTCIceCredentialType credentialType = "password"; }; */ @@ -375,7 +368,7 @@ accessToken: '' } }] })); - }, 'with turns server, credentialType password, and RTCOauthCredential credential should throw InvalidAccessError'); + }, 'with turns server, credentialType password, and object credential should throw InvalidAccessError'); /* 4.3.2. To set a configuration @@ -393,102 +386,6 @@ }] })); }, 'with turns server, credentialType oauth, and string credential should throw InvalidAccessError'); - config_test(makePc => { - const pc = makePc({ iceServers: [{ - urls: 'turns:turn.example.org', - credentialType: 'oauth', - username: 'user', - credential: { - macKey: 'mac', - accessToken: 'token' - } - }] }); - - const { iceServers } = pc.getConfiguration(); - assert_equals(iceServers.length, 1); - - const server = iceServers[0]; - assert_array_equals(server.urls, ['turns:turn.example.org']); - assert_equals(server.credentialType, 'oauth'); - assert_equals(server.username, 'user'); - - const { credential } = server; - assert_equals(credential.macKey, 'mac'); - assert_equals(credential.accessToken, 'token'); - - }, `with turns server, credentialType oauth and RTCOAuthCredential credential should succeed`); - - config_test(makePc => { - const pc = makePc({ iceServers: [{ - urls: ['turns:turn.example.org', 'stun:stun1.example.net'], - credentialType: 'oauth', - username: 'user', - credential: { - macKey: 'mac', - accessToken: 'token' - } - }] }); - - const { iceServers } = pc.getConfiguration(); - assert_equals(iceServers.length, 1); - - const server = iceServers[0]; - assert_array_equals(server.urls, ['turns:turn.example.org', 'stun:stun1.example.net']); - assert_equals(server.credentialType, 'oauth'); - assert_equals(server.username, 'user'); - - const { credential } = server; - assert_equals(credential.macKey, 'mac'); - assert_equals(credential.accessToken, 'token'); - - }, `with both turns and stun server, credentialType oauth and RTCOAuthCredential credential should succeed`); - - // credential type validation is ignored when scheme name is stun - config_test(makePc => { - const pc = makePc({ iceServers: [{ - urls: 'stun:stun1.example.net', - credentialType: 'oauth', - username: 'user', - credential: 'cred' - }] }); - - const { iceServers } = pc.getConfiguration(); - assert_equals(iceServers.length, 1); - const server = iceServers[0]; - - assert_array_equals(server.urls, ['stun:stun1.example.net']); - assert_equals(server.credentialType, 'oauth'); - assert_equals(server.username, 'user'); - assert_equals(server.credential, 'cred'); - - }, 'with stun server, credentialType oauth, and string credential should succeed'); - - // credential type validation is ignored when scheme name is stun - config_test(makePc => { - const pc = makePc({ iceServers: [{ - urls: 'stun:stun1.example.net', - credentialType: 'password', - username: 'user', - credential: { - macKey: '', - accessToken: '' - } - }] }); - - const { iceServers } = pc.getConfiguration(); - assert_equals(iceServers.length, 1); - - const server = iceServers[0]; - assert_array_equals(server.urls, ['stun:stun1.example.net']); - assert_equals(server.credentialType, 'password'); - assert_equals(server.username, 'user'); - - const { credential } = server; - assert_equals(credential.macKey, ''); - assert_equals(credential.accessToken, ''); - - }, 'with stun server, credentialType password, and RTCOAuthCredential credential should succeed'); - /* Tested 4.3.2. To set a configuration diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getDefaultIceServers.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getDefaultIceServers.html deleted file mode 100644 index 4fdbdb8dec4..00000000000 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getDefaultIceServers.html +++ /dev/null @@ -1,98 +0,0 @@ - - -RTCPeerConnection.getDefaultIceServers - - - diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html index f39fd2c3137..ede0ab1efc1 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html @@ -82,7 +82,7 @@ const pc = new RTCPeerConnection(); t.add_cleanup(() => pc.close()); - const stream = await navigator.mediaDevices.getUserMedia({audio: true}); + const stream = await getNoiseStream({audio: true}); t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); const [track] = stream.getTracks(); pc.addTransceiver(track); @@ -292,9 +292,6 @@ 'Expect video track stats to be found'); assert_equals(videoTrackStats.kind, 'video'); - - assert_true(mediaStreamStats.trackIds.include(audioTrackStats.id)); - assert_true(mediaStreamStats.trackIds.include(videoTrackStats.id)); } const onConnected = t.step_func(() => { diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html index 50158d4cea0..7da14cd5e0f 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html @@ -24,12 +24,17 @@ const mandatory = { "packetsLost", "jitter", "packetsDiscarded", + "framesDropped" ], RTCInboundRtpStreamStats: [ - "trackId", "receiverId", "remoteId", "framesDecoded", + "nackCount", + "framesReceived", + "bytesReceived", + "totalAudioEnergy", + "totalSamplesDuration" ], RTCRemoteInboundRtpStreamStats: [ "localId", @@ -40,10 +45,11 @@ const mandatory = { "bytesSent" ], RTCOutboundRtpStreamStats: [ - "trackId", "senderId", "remoteId", "framesEncoded", + "nackCount", + "framesSent" ], RTCRemoteOutboundRtpStreamStats: [ "localId", @@ -54,6 +60,7 @@ const mandatory = { "dataChannelsClosed", ], RTCDataChannelStats: [ + "label", "protocol", "dataChannelIdentifier", "state", @@ -62,35 +69,34 @@ const mandatory = { "messagesReceived", "bytesReceived", ], - RTCMediaStreamStats: [ - "streamIdentifer", - "trackIds", + RTCMediaSourceStats: [ + "trackIdentifier", + "kind" + ], + RTCAudioSourceStats: [ + "totalAudioEnergy", + "totalSamplesDuration" + ], + RTCVideoSourceStats: [ + "width", + "height", + "framesPerSecond" ], RTCMediaHandlerStats: [ "trackIdentifier", - "remoteSource", - "ended", ], RTCAudioHandlerStats: [ - "audioLevel", ], RTCVideoHandlerStats: [ - "frameWidth", - "frameHeight", - "framesPerSecond", ], RTCVideoSenderStats: [ - "framesSent", ], RTCVideoReceiverStats: [ - "framesReceived", - "framesDecoded", - "framesDropped", - "partialFramesLost", ], RTCCodecStats: [ "payloadType", "codecType", + "mimeType", "clockRate", "channels", "sdpFmtpLine", @@ -98,7 +104,6 @@ const mandatory = { RTCTransportStats: [ "bytesSent", "bytesReceived", - "rtcpTransportStatsId", "selectedCandidatePairId", "localCertificateId", "remoteCertificateId", @@ -108,12 +113,11 @@ const mandatory = { "localCandidateId", "remoteCandidateId", "state", - "priority", "nominated", "bytesSent", "bytesReceived", "totalRoundTripTime", - "currentRoundTripTime", + "currentRoundTripTime" ], RTCIceCandidateStats: [ "address", @@ -141,7 +145,10 @@ const dictionaryNames = { "csrc": "RTCRtpContributingSourceStats", "peer-connection": "RTCPeerConnectionStats", "data-channel": "RTCDataChannelStats", - "stream": "RTCMediaStreamStats", + "media-source": { + audio: "RTCAudioSourceStats", + video: "RTCVideoSourceStats" + }, "track": { video: "RTCSenderVideoTrackAttachmentStats", audio: "RTCSenderAudioTrackAttachmentStats" @@ -166,10 +173,12 @@ const dictionaryNames = { const parents = { RTCVideoHandlerStats: "RTCMediaHandlerStats", RTCVideoSenderStats: "RTCVideoHandlerStats", + RTCVideoSourceStats: "RTCMediaSourceStats", RTCSenderVideoTrackAttachmentStats: "RTCVideoSenderStats", RTCVideoReceiverStats: "RTCVideoHandlerStats", RTCAudioHandlerStats: "RTCMediaHandlerStats", RTCAudioSenderStats: "RTCAudioHandlerStats", + RTCAudioSourceStats: "RTCMediaSourceStats", RTCSenderAudioTrackAttachmentStats: "RTCAudioSenderStats", RTCAudioReceiverStats: "RTCAudioHandlerStats", RTCReceivedRtpStreamStats: "RTCRtpStreamStats", diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-ondatachannel.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-ondatachannel.html index 46fe8e0f51b..034365508b6 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-ondatachannel.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-ondatachannel.html @@ -255,7 +255,7 @@ promise_test(async (t) => { const dc1 = pc1.createDataChannel('test', { ordered: false, maxRetransmits: 1, - protocol: 'custom', + protocol: 'custom' }); assert_equals(dc1.label, 'test'); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-track-stats.https.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-track-stats.https.html index 42054ad9e66..7c344223029 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-track-stats.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-track-stats.https.html @@ -48,29 +48,7 @@ async_test(t => { const pc = new RTCPeerConnection(); t.add_cleanup(() => pc.close()); - let stream; - getUserMediaTracksAndStreams(1) - .then(t.step_func(([tracks, streams]) => { - t.add_cleanup(() => tracks.forEach(track => track.stop())); - let track = tracks[0]; - stream = streams[0]; - pc.addTrack(track, stream); - return pc.getStats(); - })) - .then(t.step_func(report => { - let streamStats = findStatsByTypeAndId(report, 'stream', stream.id); - assert_true(streamStats != null, 'Has stats for stream'); - validateRtcStats(report, streamStats); - t.done(); - })) - .catch(t.step_func(reason => { - assert_unreached(reason); - })); - }, 'addTrack() without setLocalDescription() yields media stream stats'); - async_test(t => { - const pc = new RTCPeerConnection(); - t.add_cleanup(() => pc.close()); let track; getUserMediaTracksAndStreams(1) .then(t.step_func(([tracks, streams]) => { @@ -96,107 +74,6 @@ })); }, 'addTrack() with setLocalDescription() yields track stats'); - async_test(t => { - const pc = new RTCPeerConnection(); - t.add_cleanup(() => pc.close()); - let stream; - getUserMediaTracksAndStreams(1) - .then(t.step_func(([tracks, streams]) => { - t.add_cleanup(() => tracks.forEach(track => track.stop())); - let track = tracks[0]; - stream = streams[0]; - pc.addTrack(track, stream); - return pc.createOffer(); - })) - .then(t.step_func(offer => { - return pc.setLocalDescription(offer); - })) - .then(t.step_func(() => { - return pc.getStats(); - })) - .then(t.step_func(report => { - let streamStats = findStatsByTypeAndId(report, 'stream', stream.id); - assert_true(streamStats != null, 'Has stats for stream'); - validateRtcStats(report, streamStats); - t.done(); - })) - .catch(t.step_func(reason => { - assert_unreached(reason); - })); - }, 'addTrack() with setLocalDescription() yields media stream stats'); - - async_test(t => { - const pc = new RTCPeerConnection(); - t.add_cleanup(() => pc.close()); - let track; - let stream; - getUserMediaTracksAndStreams(1) - .then(t.step_func(([tracks, streams]) => { - t.add_cleanup(() => tracks.forEach(track => track.stop())); - track = tracks[0]; - stream = streams[0]; - pc.addTrack(track, stream); - return pc.createOffer(); - })) - .then(t.step_func(offer => { - return pc.setLocalDescription(offer); - })) - .then(t.step_func(() => { - return pc.getStats(); - })) - .then(t.step_func(report => { - let trackStats = findStatsByTypeAndId(report, 'track', track.id); - let streamStats = findStatsByTypeAndId(report, 'stream', stream.id); - assert_true(trackStats != null && streamStats != null, - 'Has stats for track and stream'); - assert_array_equals(streamStats.trackIds, [ trackStats.id ], - 'streamStats.trackIds == [ trackStats.id ]'); - validateRtcStats(report, trackStats); - validateRtcStats(report, streamStats); - t.done(); - })) - .catch(t.step_func(reason => { - assert_unreached(reason); - })); - }, 'addTrack(): Media stream stats references track stats'); - - async_test(t => { - const pc = new RTCPeerConnection(); - t.add_cleanup(() => pc.close()); - let track; - let stream; - getUserMediaTracksAndStreams(1) - .then(t.step_func(([tracks, streams]) => { - t.add_cleanup(() => tracks.forEach(track => track.stop())); - track = tracks[0]; - stream = streams[0]; - stream.addTrack(track); - for (const track of stream.getTracks()) - pc.addTrack(track, stream); - return pc.createOffer(); - })) - .then(t.step_func(offer => { - return pc.setLocalDescription(offer); - })) - .then(t.step_func(() => { - return pc.getStats(); - })) - .then(t.step_func(report => { - let trackStats = findStatsByTypeAndId(report, 'track', track.id); - let streamStats = findStatsByTypeAndId(report, 'stream', stream.id); - assert_true(trackStats != null && streamStats != null, - 'Has stats for track and stream'); - assert_array_equals(streamStats.trackIds, [ trackStats.id ], - 'streamStats.trackIds == [ trackStats.id ]'); - validateRtcStats(report, trackStats); - validateRtcStats(report, streamStats); - t.done(); - })) - .catch(t.step_func(reason => { - assert_unreached(reason); - })); - }, 'Media stream stats references track stats'); - async_test(t => { const caller = new RTCPeerConnection(); t.add_cleanup(() => caller.close()); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-encodings.html b/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-encodings.html index 539b2692806..e1a6e625379 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-encodings.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-encodings.html @@ -120,7 +120,6 @@ sendEncodings: [{ active: false, maxBitrate: 8, - maxFramerate: 25, rid: 'foo' }] }); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-helper.js b/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-helper.js index 17ecfbaf99e..d7653c3a8af 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-helper.js +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpParameters-helper.js @@ -50,6 +50,11 @@ async function doOfferAnswerExchange(t, caller) { function validateSenderRtpParameters(param) { validateRtpParameters(param); + assert_array_field(param, 'encodings'); + for(const encoding of param.encodings) { + validateEncodingParameters(encoding); + } + assert_not_equals(param.transactionId, undefined, 'Expect sender param.transactionId to be set'); @@ -101,20 +106,10 @@ function validateReceiverRtpParameters(param) { sequence codecs; }; - enum RTCDegradationPreference { - "maintain-framerate", - "maintain-resolution", - "balanced" - }; */ function validateRtpParameters(param) { assert_optional_string_field(param, 'transactionId'); - assert_array_field(param, 'encodings'); - for(const encoding of param.encodings) { - validateEncodingParameters(encoding); - } - assert_array_field(param, 'headerExtensions'); for(const headerExt of param.headerExtensions) { validateHeaderExtensionParameters(headerExt); @@ -131,13 +126,8 @@ function validateRtpParameters(param) { /* dictionary RTCRtpEncodingParameters { - RTCDtxStatus dtx; boolean active; - RTCPriorityType priority; - RTCPriorityType networkPriority; - unsigned long ptime; unsigned long maxBitrate; - double maxFramerate; [readonly] DOMString rid; @@ -145,31 +135,10 @@ function validateRtpParameters(param) { double scaleResolutionDownBy; }; - enum RTCDtxStatus { - "disabled", - "enabled" - }; - - enum RTCPriorityType { - "very-low", - "low", - "medium", - "high" - }; */ function validateEncodingParameters(encoding) { - assert_optional_enum_field(encoding, 'dtx', - ['disabled', 'enabled']); - assert_optional_boolean_field(encoding, 'active'); - assert_optional_enum_field(encoding, 'priority', - ['very-low', 'low', 'medium', 'high']); - assert_optional_enum_field(encoding, 'networkPriority', - ['very-low', 'low', 'medium', 'high']); - - assert_optional_unsigned_int_field(encoding, 'ptime'); assert_optional_unsigned_int_field(encoding, 'maxBitrate'); - assert_optional_number_field(encoding, 'maxFramerate'); assert_optional_string_field(encoding, 'rid'); assert_optional_number_field(encoding, 'scaleResolutionDownBy'); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpReceiver-getParameters.html b/tests/wpt/web-platform-tests/webrtc/RTCRtpReceiver-getParameters.html index 4be0e3b95ec..7047ce7d1f3 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpReceiver-getParameters.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpReceiver-getParameters.html @@ -36,12 +36,11 @@ t.add_cleanup(() => pc.close()); pc.addTransceiver('audio'); const callee = await doOfferAnswerExchange(t, pc); - const param = callee.getReceivers()[0].getParameters(); + const param = callee.getTransceivers()[0].receiver.getParameters(); validateReceiverRtpParameters(param); assert_greater_than(param.headerExtensions.length, 0); assert_greater_than(param.codecs.length, 0); - assert_equals(param.encodings.length, 1); }, 'getParameters() with audio receiver'); promise_test(async t => { @@ -49,12 +48,11 @@ t.add_cleanup(() => pc.close()); pc.addTransceiver('video'); const callee = await doOfferAnswerExchange(t, pc); - const param = callee.getReceivers()[0].getParameters(); + const param = callee.getTransceivers()[0].receiver.getParameters(); validateReceiverRtpParameters(param); assert_greater_than(param.headerExtensions.length, 0); assert_greater_than(param.codecs.length, 0); - assert_equals(param.encodings.length, 1); }, 'getParameters() with video receiver'); promise_test(async t => { @@ -67,15 +65,9 @@ ] }); const callee = await doOfferAnswerExchange(t, pc); - const param = callee.getReceivers()[0].getParameters(); + const param = callee.getTransceivers()[0].receiver.getParameters(); validateReceiverRtpParameters(param); - assert_greater_than(param.headerExtensions.length, 0); assert_greater_than(param.codecs.length, 0); - assert_equals(param.encodings.length, 2, 'layer count must match'); - assert_equals(param.encodings[0].rid, "rid1", - 'simulcast rids must match'); - assert_equals(param.encodings[1].rid, "rid2", - 'simulcast rids must match'); }, 'getParameters() with simulcast video receiver'); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver-stop.html b/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver-stop.html index 30cb6130d4f..4f3a9ce85fa 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver-stop.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver-stop.html @@ -59,8 +59,8 @@ promise_test(async (t)=> { const offer = await pc1.createOffer(); - assert_true(offer.sdp.includes("a=sendonly"), "The audio m-section should be sendonly"); -}, "A stopped sendonly transceiver should generate a sendonly m-section in the offer"); + assert_true(offer.sdp.includes("a=inactive"), "The audio m-section should be inactive"); +}, "A stopped sendonly transceiver should generate an inactive m-section in the offer"); promise_test(async (t)=> { const pc1 = new RTCPeerConnection(); @@ -90,7 +90,7 @@ promise_test(async (t) => { pc1.getTransceivers()[0].stop(); await exchangeOfferAnswer(pc1, pc2); await pc1.setLocalDescription(await pc1.createOffer()); -}, 'If a track is stopped locally, setting a locally generated answer should still work'); +}, 'If a transceiver is stopped locally, setting a locally generated answer should still work'); promise_test(async (t) => { const pc1 = new RTCPeerConnection(); @@ -102,6 +102,42 @@ promise_test(async (t) => { pc2.getTransceivers()[0].stop(); await exchangeOfferAnswer(pc2, pc1); await pc1.setLocalDescription(await pc1.createOffer()); -}, 'If a track is stopped remotely, setting a locally generated answer should still work'); +}, 'If a transceiver is stopped remotely, setting a locally generated answer should still work'); + +promise_test(async (t) => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1.addTransceiver("audio"); + await exchangeOfferAnswer(pc1, pc2); + assert_equals(pc1.getTransceivers().length, 1); + assert_equals(pc2.getTransceivers().length, 1); + pc1.getTransceivers()[0].stop(); + await exchangeOfferAnswer(pc1, pc2); + assert_equals(pc1.getTransceivers().length, 0); + assert_equals(pc2.getTransceivers().length, 0); + assert_equals(pc1.getSenders().length, 0, 'caller senders'); + assert_equals(pc1.getReceivers().length, 0, 'caller receivers'); + assert_equals(pc2.getSenders().length, 0, 'callee senders'); + assert_equals(pc2.getReceivers().length, 0, 'callee receivers'); +}, 'If a transceiver is stopped, transceivers, senders and receivers should disappear after offer/answer'); + +promise_test(async (t) => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1.addTransceiver("audio"); + await exchangeOfferAnswer(pc1, pc2); + assert_equals(pc1.getTransceivers().length, 1); + assert_equals(pc2.getTransceivers().length, 1); + pc1Transceiver = pc1.getTransceivers()[0]; + pc2Transceiver = pc2.getTransceivers()[0]; + pc1.getTransceivers()[0].stop(); + await exchangeOfferAnswer(pc1, pc2); + assert_equals('stopped', pc1Transceiver.direction); + assert_equals('stopped', pc2Transceiver.direction); +}, 'If a transceiver is stopped, transceivers should end up in state stopped'); diff --git a/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver.https.html b/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver.https.html index 2e1dcbb0d95..c9dce45d738 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver.https.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCRtpTransceiver.https.html @@ -1235,9 +1235,8 @@ stoppedTransceiver.receiver.track.onended = resolve; }); stoppedTransceiver.stop(); - assert_equals(pc1.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver'); - assert_equals(pc1.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver'); - + assert_equals(pc1.getReceivers().length, 1, 'getReceivers exposes a receiver of a stopped transceiver before negotiation'); + assert_equals(pc1.getSenders().length, 1, 'getSenders exposes a sender of a stopped transceiver before negotiation'); await onended; // The transceiver has [[stopping]] = true, [[stopped]] = false hasPropsAndUniqueMids(pc1.getTransceivers(), @@ -1273,30 +1272,38 @@ offer = await pc1.createOffer(); await pc1.setLocalDescription(offer); - stoppedTransceiver = pc2.getTransceivers()[0]; + const stoppedCalleeTransceiver = pc2.getTransceivers()[0]; onended = new Promise(resolve => { - stoppedTransceiver.receiver.track.onended = resolve; + stoppedCalleeTransceiver.receiver.track.onended = resolve; }); await pc2.setRemoteDescription(offer); await onended; - - // pc2's transceiver was stopped remotely, so has - // [[stopping]] = true, [[stopped]] = true. + // pc2's transceiver was stopped remotely. + // The track ends when setRemeoteDescription(offer) is set. hasProps(pc2.getTransceivers(), [ { sender: {track: {kind: "audio"}}, receiver: {track: {kind: "audio", readyState: "ended"}}, - mid: null, currentDirection: "stopped", - direction: "stopped" + direction: "sendrecv" } ]); + // After setLocalDescription(answer), the transceiver has + // [[stopping]] = true, [[stopped]] = true, and is removed from pc2. + const stoppingAnswer = await pc2.createAnswer(); + await pc2.setLocalDescription(stoppingAnswer); + assert_equals(pc2.getTransceivers().length, 0); + assert_equals(pc2.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver after negotiation'); + assert_equals(pc2.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver after negotiation'); // Shouldn't throw either stoppedTransceiver.stop(); + await pc1.setRemoteDescription(stoppingAnswer); + assert_equals(pc1.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver after negotiation'); + assert_equals(pc1.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver after negotiation'); pc1.close(); pc2.close(); @@ -1897,6 +1904,8 @@ // After all this SRD/rollback, we should still get the track event let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer); + + assert_equals(trackEvents.length, 1); hasProps(trackEvents, [ { @@ -1910,6 +1919,7 @@ // Make sure all this rollback hasn't messed up the signaling trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer); + assert_equals(trackEvents.length, 1); hasProps(trackEvents, [ { @@ -1939,6 +1949,8 @@ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, {type: "rollback"}); + + assert_equals(trackEvents.length, 1, 'track event from remote rollback'); hasProps(trackEvents, [ { diff --git a/tests/wpt/web-platform-tests/webxr/xrWebGLLayer_framebuffer_scale.https.html b/tests/wpt/web-platform-tests/webxr/xrWebGLLayer_framebuffer_scale.https.html index 7b5cedb1c83..3faab3bf6bc 100644 --- a/tests/wpt/web-platform-tests/webxr/xrWebGLLayer_framebuffer_scale.https.html +++ b/tests/wpt/web-platform-tests/webxr/xrWebGLLayer_framebuffer_scale.https.html @@ -26,7 +26,7 @@ let testFunction = assert_greater_than(nativeScale, 0); // The native scale should be the inverse for the default framebuffer scale. - assert_approx_equals(nativeScale, 1/fakeDeviceController.displayInfo_.webxrDefaultFramebufferScale, FLOAT_EPSILON); + assert_approx_equals(nativeScale, 1/fakeDeviceController.defaultFramebufferScale_, FLOAT_EPSILON); }); webglLayer = new XRWebGLLayer(session, gl, { framebufferScaleFactor: nativeScale });