MSE-in-Workers: Increase wpt coverage of MediaSourceHandle transfer draft
authorMatt Wolenetz <wolenetz@chromium.org>
Fri, 01 Jul 2022 23:36:28 +0000
changeset 4480204 722089597104de38f6abc1db747ffa0bbe62eec9
parent 4480203 dfedcc4c1375cd23ad56a8d1f4c2c2626a839e77
child 4480205 614bd150613eb56693a912459f1c6ca59d53530f
push id827486
push userwptsync@mozilla.com
push dateSat, 02 Jul 2022 02:04:09 +0000
treeherdertry@16a4e1535415 [default view] [failures only]
bugs878133, 1338956, 3739665, 1020233
milestone104.0a1
MSE-in-Workers: Increase wpt coverage of MediaSourceHandle transfer Adds wpt test cases that verify expected transfer-only semantics for a (worker MediaSource generated) MediaSourceHandle: * MediaSourceHandle serialization without transfer must fail, tested in window context * Same MediaSourceHandle transferred multiple times in single postMessage must fail, tested in window context * Attempt to transfer detached MediaSourceHandle must fail, tested in window context * MediaSourceHandle cannot be transferred, immediately after set as srcObject, even if srcObject immediately reset to null * MediaSourceHandle cannot be transferred, if it was srcObject when asynchronous load starts (loadstart), even if srcObject is then immediately reset to null * MediaSourceHandle serialization without transfer must fail, tested in worker * Same MediaSourceHandle transferred multiple times in single postMessage must fail, tested in worker BUG=878133,1338956 Change-Id: Ia90ef1c9db92be252cefb813544e0a450bd85965 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3739665 Reviewed-by: Will Cassella <cassew@chromium.org> Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1020233} wpt-commit: 244c1fcc12bc76d5bb9a3b24c642ab2cfec66134 wpt-type: dependency
testing/web-platform/tests/media-source/dedicated-worker/mediasource-worker-handle-transfer-to-main.js
testing/web-platform/tests/media-source/dedicated-worker/mediasource-worker-handle-transfer.html
testing/web-platform/tests/media-source/dedicated-worker/mediasource-worker-handle-transfer.js
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/media-source/dedicated-worker/mediasource-worker-handle-transfer-to-main.js
@@ -0,0 +1,10 @@
+importScripts('mediasource-message-util.js');
+
+// Note, we do not use testharness.js utilities within the worker context
+// because it also communicates using postMessage to the main HTML document's
+// harness, and would confuse the test case message parsing there.
+
+// Just obtain a MediaSourceHandle and transfer it to creator of our context.
+let handle = new MediaSource().getHandle();
+postMessage(
+    {subject: messageSubject.HANDLE, info: handle}, {transfer: [handle]});
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/media-source/dedicated-worker/mediasource-worker-handle-transfer.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<html>
+<title>Test MediaSourceHandle transfer characteristics</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="mediasource-message-util.js"></script>
+<body>
+<script>
+
+function assert_mseiw_supported() {
+  // Fail fast if MSE-in-Workers is not supported.
+  assert_true(
+      MediaSource.hasOwnProperty('canConstructInDedicatedWorker'),
+      'MediaSource hasOwnProperty \'canConstructInDedicatedWorker\'');
+  assert_true(
+      MediaSource.canConstructInDedicatedWorker,
+      'MediaSource.canConstructInDedicatedWorker');
+  assert_true(
+      window.hasOwnProperty('MediaSourceHandle'),
+      'window must have MediaSourceHandle visibility');
+}
+
+function get_handle_from_new_worker(t) {
+  return new Promise((r) => {
+    let worker = new Worker('mediasource-worker-handle-transfer-to-main.js');
+    worker.addEventListener(
+        'message', t.step_func(e => {
+          let subject = e.data.subject;
+          assert_true(
+              subject != undefined, 'message must have a subject field');
+          switch (subject) {
+            case messageSubject.ERROR:
+              assert_unreached('Worker error: ' + e.data.info);
+              break;
+            case messageSubject.HANDLE:
+              const handle = e.data.info;
+              assert_not_equals(
+                  handle, null, 'must have a non-null MediaSourceHandle');
+              r({worker, handle});
+              break;
+            default:
+              assert_unreached('Unexpected message subject: ' + subject);
+          }
+        }),
+        {once: true});
+  });
+}
+
+promise_test(async t => {
+  assert_mseiw_supported();
+  let {worker, handle} = await get_handle_from_new_worker(t);
+  assert_true(
+      handle instanceof MediaSourceHandle, 'must be a MediaSourceHandle');
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle);
+  }, 'serializing handle without transfer');
+}, 'MediaSourceHandle serialization without transfer must fail, tested in window context');
+
+promise_test(async t => {
+  assert_mseiw_supported();
+  let {worker, handle} = await get_handle_from_new_worker(t);
+  assert_true(
+      handle instanceof MediaSourceHandle, 'must be a MediaSourceHandle');
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle, [handle, handle]);
+  }, 'transferring same handle more than once in same postMessage');
+}, 'Same MediaSourceHandle transferred multiple times in single postMessage must fail, tested in window context');
+
+promise_test(async t => {
+  assert_mseiw_supported();
+  let {worker, handle} = await get_handle_from_new_worker(t);
+  assert_true(
+      handle instanceof MediaSourceHandle, 'must be a MediaSourceHandle');
+
+  // Transferring handle to worker without including it in the message is still
+  // a valid transfer, though the recipient will not be able to obtain the
+  // handle itself. Regardless, the handle in this sender's context will be
+  // detached.
+  worker.postMessage(null, [handle]);
+
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(null, [handle]);
+  }, 'transferring handle that was already detached should fail');
+
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle, [handle]);
+  }, 'transferring handle that was already detached should fail, even if this time it\'s included in the message');
+}, 'Attempt to transfer detached MediaSourceHandle must fail, tested in window context');
+
+promise_test(async t => {
+  assert_mseiw_supported();
+  let {worker, handle} = await get_handle_from_new_worker(t);
+  assert_true(
+      handle instanceof MediaSourceHandle, 'must be a MediaSourceHandle');
+
+  let video = document.createElement('video');
+  document.body.appendChild(video);
+  video.srcObject = handle;
+
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle, [handle]);
+  }, 'transferring handle that is currently srcObject fails');
+  assert_equals(video.srcObject, handle);
+
+  // Clear |handle| from being the srcObject value.
+  video.srcObject = null;
+
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle, [handle]);
+  }, 'transferring handle that was briefly srcObject before srcObject was reset to null should also fail');
+  assert_equals(video.srcObject, null);
+}, 'MediaSourceHandle cannot be transferred, immediately after set as srcObject, even if srcObject immediately reset to null');
+
+promise_test(async t => {
+  assert_mseiw_supported();
+  let {worker, handle} = await get_handle_from_new_worker(t);
+  assert_true(
+      handle instanceof MediaSourceHandle, 'must be a MediaSourceHandle');
+
+  let video = document.createElement('video');
+  document.body.appendChild(video);
+  video.srcObject = handle;
+  assert_not_equals(video.networkState, HTMLMediaElement.NETWORK_LOADING);
+  // Initial step of resource selection algorithm sets networkState to
+  // NETWORK_NO_SOURCE. networkState only becomes NETWORK_LOADING after stable
+  // state awaited and resource selection algorithm continues with, in this
+  // case, an assigned media provider object (which is the MediaSource
+  // underlying the handle).
+  assert_equals(video.networkState, HTMLMediaElement.NETWORK_NO_SOURCE);
+
+  // Wait until 'loadstart' media element event is dispatched.
+  await new Promise((r) => {
+    video.addEventListener(
+        'loadstart', t.step_func(e => {
+          r();
+        }),
+        {once: true});
+  });
+  assert_equals(video.networkState, HTMLMediaElement.NETWORK_LOADING);
+
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle, [handle]);
+  }, 'transferring handle that is currently srcObject, after loadstart, fails');
+  assert_equals(video.srcObject, handle);
+
+  // Clear |handle| from being the srcObject value.
+  video.srcObject = null;
+
+  assert_throws_dom('DataCloneError', function() {
+    worker.postMessage(handle, [handle]);
+  }, 'transferring handle that was srcObject until \'loadstart\' when srcObject was reset to null should also fail');
+  assert_equals(video.srcObject, null);
+}, 'MediaSourceHandle cannot be transferred, if it was srcObject when asynchronous load starts (loadstart), even if srcObject is then immediately reset to null');
+
+fetch_tests_from_worker(new Worker('mediasource-worker-handle-transfer.js'));
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/media-source/dedicated-worker/mediasource-worker-handle-transfer.js
@@ -0,0 +1,19 @@
+importScripts('/resources/testharness.js');
+
+test(t => {
+  let handle = new MediaSource().getHandle();
+  assert_true(handle instanceof MediaSourceHandle);
+  assert_throws_dom('DataCloneError', function() {
+    postMessage(handle);
+  }, 'serializing handle without transfer');
+}, 'MediaSourceHandle serialization without transfer must fail, tested in worker');
+
+test(t => {
+  let handle = new MediaSource().getHandle();
+  assert_true(handle instanceof MediaSourceHandle);
+  assert_throws_dom('DataCloneError', function() {
+    postMessage(handle, [handle, handle]);
+  }, 'transferring same handle more than once in same postMessage');
+}, 'Same MediaSourceHandle transferred multiple times in single postMessage must fail, tested in worker');
+
+done();