From 65887fb7efe174363ed57e0134ffe6c9c0e10420 Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 4 May 2023 01:09:28 -0400 Subject: [PATCH] update wpts (#2108) --- CONTRIBUTING.md | 9 +- test/wpt/status/fetch.status.json | 8 + test/wpt/tests/.azure-pipelines.yml | 37 +++ test/wpt/tests/.gitignore | 1 - test/wpt/tests/.taskcluster.yml | 2 +- test/wpt/tests/CODEOWNERS | 3 - .../tests/fetch/api/basic/keepalive.any.js | 10 - .../wpt/tests/fetch/api/body/mime-type.any.js | 87 ++++++++ .../api/redirect/redirect-keepalive.any.js | 118 ++++++---- .../fetch/api/resources/keepalive-helper.js | 8 +- .../resources/keepalive-redirect-window.html | 18 +- .../fetch/api/response/response-clone.any.js | 16 +- .../tests/fetch/data-urls/navigate.window.js | 75 +++++++ ...fetch-from-treat-as-public.https.window.js | 20 +- .../iframe.tentative.https.window.js | 19 +- .../redirect.https.window.js | 187 +++++++++++++++- .../resources/support.sub.js | 2 + .../service-worker-fetch.https.window.js | 21 +- .../service-worker-update.https.window.js | 23 +- .../service-worker.https.window.js | 29 +-- .../shared-worker-blob-fetch.https.window.js | 25 ++- .../shared-worker-fetch.https.window.js | 21 +- .../shared-worker.https.window.js | 24 -- .../worker.https.window.js | 34 +-- .../xhr-from-treat-as-public.https.window.js | 15 +- test/wpt/tests/lint.ignore | 210 +----------------- .../chromium/mock-pressure-service.js | 18 +- .../partitioned-cookies.tentative.https.html | 85 +++++++ ...ioned-cookies-3p-credentialless-frame.html | 69 ++++++ .../partitioned-cookies-3p-frame.html | 67 ++++++ .../resources/partitioned-cookies-3p-sw.js | 30 +++ .../partitioned-cookies-3p-window.html | 35 +++ .../resources/partitioned-cookies-sw.js | 30 +++ ...kets_storage_policy.tentative.https.any.js | 25 +++ .../buckets/resources/cached-resource.txt | 1 + .../tests/storage/buckets/resources/util.js | 42 ++++ .../storage/estimate-indexeddb.https.any.js | 58 +---- 37 files changed, 1024 insertions(+), 458 deletions(-) create mode 100644 test/wpt/tests/fetch/data-urls/navigate.window.js create mode 100644 test/wpt/tests/service-workers/service-worker/partitioned-cookies.tentative.https.html create mode 100644 test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html create mode 100644 test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html create mode 100644 test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js create mode 100644 test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html create mode 100644 test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js create mode 100644 test/wpt/tests/storage/buckets/resources/cached-resource.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6e8b57f357..2d67ba7f9e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,14 +91,17 @@ Here are the steps to update them. ```bash git clone --depth 1 --single-branch --branch epochs/daily --filter=blob:none --sparse https://github.com/web-platform-tests/wpt.git test/wpt/tests cd test/wpt/tests + +git sparse-checkout add /resources +git sparse-checkout add /interfaces +git sparse-checkout add /common git sparse-checkout add /fetch git sparse-checkout add /FileAPI git sparse-checkout add /xhr git sparse-checkout add /websockets -git sparse-checkout add /resources -git sparse-checkout add /common git sparse-checkout add /mimesniff -git sparse-checkout add /interfaces +git sparse-checkout add /storage +git sparse-checkout add /service-workers ``` diff --git a/test/wpt/status/fetch.status.json b/test/wpt/status/fetch.status.json index 72930388cb3..cb5949579cf 100644 --- a/test/wpt/status/fetch.status.json +++ b/test/wpt/status/fetch.status.json @@ -99,6 +99,14 @@ ] } }, + "body": { + "mime-type.any.js": { + "note": "fails on all platforms, https://wpt.fyi/results/fetch/api/body/mime-type.any.html?label=master&label=experimental&product=chrome&product=firefox&product=safari&product=node.js&product=deno&aligned", + "fail": [ + "Response: Extract a MIME type with clone" + ] + } + }, "cors": { "note": "undici doesn't implement CORs", "skip": true diff --git a/test/wpt/tests/.azure-pipelines.yml b/test/wpt/tests/.azure-pipelines.yml index aacd78815ad..20d5ec0f431 100644 --- a/test/wpt/tests/.azure-pipelines.yml +++ b/test/wpt/tests/.azure-pipelines.yml @@ -541,3 +541,40 @@ jobs: parameters: dependsOn: results_safari_preview artifactName: safari-preview-results + +- job: results_wktr_preview + displayName: 'all tests: WebKitTestRunner' + condition: | + or(eq(variables['Build.SourceBranch'], 'refs/heads/triggers/wktr_preview'), + and(eq(variables['Build.Reason'], 'Manual'), variables['run_all_wktr_preview'])) + strategy: + parallel: 8 # chosen to make runtime ~2h + timeoutInMinutes: 180 + pool: + vmImage: 'macOS-12' + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.10' + - template: tools/ci/azure/checkout.yml + - template: tools/ci/azure/pip_install.yml + parameters: + packages: virtualenv + - template: tools/ci/azure/install_certs.yml + - template: tools/ci/azure/update_hosts.yml + - template: tools/ci/azure/update_manifest.yml + - script: | + set -eux -o pipefail + export SYSTEM_VERSION_COMPAT=0 + ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel main --install-browser wktr + displayName: 'Run tests' + - task: PublishBuildArtifacts@1 + displayName: 'Publish results' + inputs: + artifactName: 'wktr-preview-results' + - template: tools/ci/azure/publish_logs.yml + - template: tools/ci/azure/sysdiagnose.yml +- template: tools/ci/azure/fyi_hook.yml + parameters: + dependsOn: results_wktr_preview + artifactName: wktr-preview-results diff --git a/test/wpt/tests/.gitignore b/test/wpt/tests/.gitignore index 23f0370c4d0..061700a9604 100644 --- a/test/wpt/tests/.gitignore +++ b/test/wpt/tests/.gitignore @@ -45,7 +45,6 @@ scratch /css/build-temp /css/dist /css/dist_last -/css/tools/cache /url/tools/IdnaTestV2.txt /webaudio/idl/* diff --git a/test/wpt/tests/.taskcluster.yml b/test/wpt/tests/.taskcluster.yml index f830bff668f..c80e92af204 100644 --- a/test/wpt/tests/.taskcluster.yml +++ b/test/wpt/tests/.taskcluster.yml @@ -57,7 +57,7 @@ tasks: owner: ${owner} source: ${event.repository.clone_url} payload: - image: webplatformtests/wpt:0.52 + image: webplatformtests/wpt:0.53 maxRunTime: 7200 artifacts: public/results: diff --git a/test/wpt/tests/CODEOWNERS b/test/wpt/tests/CODEOWNERS index 2372633782e..140e0c6545b 100644 --- a/test/wpt/tests/CODEOWNERS +++ b/test/wpt/tests/CODEOWNERS @@ -1,6 +1,3 @@ -# Prevent accidentially touching CSS subtree -/css/tools/apiclient/ @plinss @web-platform-tests/wpt-core-team - # Require review for changes that often need an RFC /resources/testdriver* @web-platform-tests/wpt-core-team /resources/testharness* @web-platform-tests/wpt-core-team diff --git a/test/wpt/tests/fetch/api/basic/keepalive.any.js b/test/wpt/tests/fetch/api/basic/keepalive.any.js index 047f1ed2348..4f33284d0c7 100644 --- a/test/wpt/tests/fetch/api/basic/keepalive.any.js +++ b/test/wpt/tests/fetch/api/basic/keepalive.any.js @@ -27,13 +27,3 @@ for (const method of ['GET', 'POST']) { assertStashedTokenAsync(`simple ${method} request: no payload`, token1); }, `simple ${method} request: no payload; setting up`); } - -promise_test(async (test) => { - const w = window.open(`${ - HTTP_NOTSAMESITE_ORIGIN}/fetch/api/resources/keepalive-redirect-window.html`); - const token = await getTokenFromMessage(); - w.close(); - - assertStashedTokenAsync( - 'keepalive in onunload in nested frame in another window', token); -}, 'keepalive in onunload in nested frame in another window; setting up'); diff --git a/test/wpt/tests/fetch/api/body/mime-type.any.js b/test/wpt/tests/fetch/api/body/mime-type.any.js index a0f90a0abdf..67c9af7da2d 100644 --- a/test/wpt/tests/fetch/api/body/mime-type.any.js +++ b/test/wpt/tests/fetch/api/body/mime-type.any.js @@ -38,3 +38,90 @@ assert_equals(blob.type, newMIMEType); }, `${bodyContainer.constructor.name}: setting missing Content-Type`); }); + +[ + () => new Request("about:blank", { method: "POST" }), + () => new Response(), +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + promise_test(async t => { + const blob = await bodyContainer.blob(); + assert_equals(blob.type, ""); + }, `${bodyContainer.constructor.name}: MIME type for Blob from empty body`); +}); + +[ + () => new Request("about:blank", { method: "POST", headers: [["Content-Type", "Mytext/Plain"]] }), + () => new Response("", { headers: [["Content-Type", "Mytext/Plain"]] }) +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + promise_test(async t => { + const blob = await bodyContainer.blob(); + assert_equals(blob.type, 'mytext/plain'); + }, `${bodyContainer.constructor.name}: MIME type for Blob from empty body with Content-Type`); +}); + +[ + () => new Request("about:blank", { body: new Blob([""]), method: "POST" }), + () => new Response(new Blob([""])) +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + promise_test(async t => { + const blob = await bodyContainer.blob(); + assert_equals(blob.type, ""); + assert_equals(bodyContainer.headers.get("Content-Type"), null); + }, `${bodyContainer.constructor.name}: MIME type for Blob`); +}); + +[ + () => new Request("about:blank", { body: new Blob([""], { type: "Text/Plain" }), method: "POST" }), + () => new Response(new Blob([""], { type: "Text/Plain" })) +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + promise_test(async t => { + const blob = await bodyContainer.blob(); + assert_equals(blob.type, "text/plain"); + assert_equals(bodyContainer.headers.get("Content-Type"), "text/plain"); + }, `${bodyContainer.constructor.name}: MIME type for Blob with non-empty type`); +}); + +[ + () => new Request("about:blank", { method: "POST", body: new Blob([""], { type: "Text/Plain" }), headers: [["Content-Type", "Text/Html"]] }), + () => new Response(new Blob([""], { type: "Text/Plain" }, { headers: [["Content-Type", "Text/Html"]] })) +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + const cloned = bodyContainer.clone(); + promise_test(async t => { + const blobs = [await bodyContainer.blob(), await cloned.blob()]; + assert_equals(blobs[0].type, "text/html"); + assert_equals(blobs[1].type, "text/html"); + assert_equals(bodyContainer.headers.get("Content-Type"), "Text/Html"); + assert_equals(cloned.headers.get("Content-Type"), "Text/Html"); + }, `${bodyContainer.constructor.name}: Extract a MIME type with clone`); +}); + +[ + () => new Request("about:blank", { body: new Blob([], { type: "text/plain" }), method: "POST", headers: [["Content-Type", "text/html"]] }), + () => new Response(new Blob([], { type: "text/plain" }), { headers: [["Content-Type", "text/html"]] }), +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + promise_test(async t => { + assert_equals(bodyContainer.headers.get("Content-Type"), "text/html"); + const blob = await bodyContainer.blob(); + assert_equals(blob.type, "text/html"); + }, `${bodyContainer.constructor.name}: Content-Type in headers wins Blob"s type`); +}); + +[ + () => new Request("about:blank", { body: new Blob([], { type: "text/plain" }), method: "POST" }), + () => new Response(new Blob([], { type: "text/plain" })), +].forEach(bodyContainerCreator => { + const bodyContainer = bodyContainerCreator(); + promise_test(async t => { + assert_equals(bodyContainer.headers.get("Content-Type"), "text/plain"); + const newMIMEType = "text/html"; + bodyContainer.headers.set("Content-Type", newMIMEType); + const blob = await bodyContainer.blob(); + assert_equals(blob.type, newMIMEType); + }, `${bodyContainer.constructor.name}: setting missing Content-Type in headers and it wins Blob"s type`); +}); diff --git a/test/wpt/tests/fetch/api/redirect/redirect-keepalive.any.js b/test/wpt/tests/fetch/api/redirect/redirect-keepalive.any.js index 9f7cca7dbf7..bcfc444f5a6 100644 --- a/test/wpt/tests/fetch/api/redirect/redirect-keepalive.any.js +++ b/test/wpt/tests/fetch/api/redirect/redirect-keepalive.any.js @@ -14,43 +14,81 @@ const { HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT } = get_host_info(); -promise_test(async (test) => { - const token1 = token(); - const iframe = document.createElement('iframe'); - iframe.src = getKeepAliveAndRedirectIframeUrl( - token1, '', '', /*withPreflight=*/ false); - document.body.appendChild(iframe); - await iframeLoaded(iframe); - assert_equals(await getTokenFromMessage(), token1); - iframe.remove(); - - assertStashedTokenAsync('same-origin redirect', token1); -}, 'same-origin redirect; setting up'); - -promise_test(async (test) => { - const token1 = token(); - const iframe = document.createElement('iframe'); - iframe.src = getKeepAliveAndRedirectIframeUrl( - token1, HTTP_REMOTE_ORIGIN, HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, - /*withPreflight=*/ false); - document.body.appendChild(iframe); - await iframeLoaded(iframe); - assert_equals(await getTokenFromMessage(), token1); - iframe.remove(); - - assertStashedTokenAsync('cross-origin redirect', token1); -}, 'cross-origin redirect; setting up'); - -promise_test(async (test) => { - const token1 = token(); - const iframe = document.createElement('iframe'); - iframe.src = getKeepAliveAndRedirectIframeUrl( - token1, HTTP_REMOTE_ORIGIN, HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, - /*withPreflight=*/ true); - document.body.appendChild(iframe); - await iframeLoaded(iframe); - assert_equals(await getTokenFromMessage(), token1); - iframe.remove(); - - assertStashedTokenAsync('cross-origin redirect with preflight', token1); -}, 'cross-origin redirect with preflight; setting up'); +/** + * In an iframe, test to fetch a keepalive URL that involves in redirect to + * another URL. + */ +function keepaliveRedirectTest( + desc, {origin1 = '', origin2 = '', withPreflight = false} = {}) { + desc = `[keepalive] ${desc}`; + promise_test(async (test) => { + const tokenToStash = token(); + const iframe = document.createElement('iframe'); + iframe.src = getKeepAliveAndRedirectIframeUrl( + tokenToStash, origin1, origin2, withPreflight); + document.body.appendChild(iframe); + await iframeLoaded(iframe); + assert_equals(await getTokenFromMessage(), tokenToStash); + iframe.remove(); + + assertStashedTokenAsync(desc, tokenToStash); + }, `${desc}; setting up`); +} + +/** + * Opens a different site window, and in `unload` event handler, test to fetch + * a keepalive URL that involves in redirect to another URL. + */ +function keepaliveRedirectInUnloadTest(desc, { + origin1 = '', + origin2 = '', + url2 = '', + withPreflight = false, + shouldPass = true +} = {}) { + desc = `[keepalive][new window][unload] ${desc}`; + + promise_test(async (test) => { + const targetUrl = + `${HTTP_NOTSAMESITE_ORIGIN}/fetch/api/resources/keepalive-redirect-window.html?` + + `origin1=${origin1}&` + + `origin2=${origin2}&` + + `url2=${url2}&` + (withPreflight ? `with-headers` : ``); + const w = window.open(targetUrl); + const token = await getTokenFromMessage(); + w.close(); + + assertStashedTokenAsync(desc, token, {shouldPass}); + }, `${desc}; setting up`); +} + +keepaliveRedirectTest(`same-origin redirect`); +keepaliveRedirectTest( + `same-origin redirect + preflight`, {withPreflight: true}); +keepaliveRedirectTest(`cross-origin redirect`, { + origin1: HTTP_REMOTE_ORIGIN, + origin2: HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT +}); +keepaliveRedirectTest(`cross-origin redirect + preflight`, { + origin1: HTTP_REMOTE_ORIGIN, + origin2: HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, + withPreflight: true +}); + +keepaliveRedirectInUnloadTest('same-origin redirect'); +keepaliveRedirectInUnloadTest( + 'same-origin redirect + preflight', {withPreflight: true}); +keepaliveRedirectInUnloadTest('cross-origin redirect', { + origin1: HTTP_REMOTE_ORIGIN, + origin2: HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT +}); +keepaliveRedirectInUnloadTest('cross-origin redirect + preflight', { + origin1: HTTP_REMOTE_ORIGIN, + origin2: HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, + withPreflight: true +}); +keepaliveRedirectInUnloadTest( + 'redirect to file URL', {url2: 'file://tmp/bar.txt', shouldPass: false}); +keepaliveRedirectInUnloadTest( + 'redirect to data URL', + {url2: 'data:text/plain;base64,cmVzcG9uc2UncyBib2R5', shouldPass: false}); diff --git a/test/wpt/tests/fetch/api/resources/keepalive-helper.js b/test/wpt/tests/fetch/api/resources/keepalive-helper.js index 42f20ac30af..c7048d1ff33 100644 --- a/test/wpt/tests/fetch/api/resources/keepalive-helper.js +++ b/test/wpt/tests/fetch/api/resources/keepalive-helper.js @@ -60,7 +60,7 @@ async function queryToken(token) { // for the rest of the work. Note that we want the serialized behavior // for the steps so far, so we don't want to make the entire test case // an async_test. -function assertStashedTokenAsync(testName, token) { +function assertStashedTokenAsync(testName, token, {shouldPass = true} = {}) { async_test((test) => { new Promise((resolve) => test.step_timeout(resolve, 3000)) .then(() => { @@ -73,7 +73,11 @@ function assertStashedTokenAsync(testName, token) { test.done(); }) .catch(test.step_func((e) => { - assert_unreached(e); + if (shouldPass) { + assert_unreached(e); + } else { + test.done(); + } })); }, testName); } diff --git a/test/wpt/tests/fetch/api/resources/keepalive-redirect-window.html b/test/wpt/tests/fetch/api/resources/keepalive-redirect-window.html index 6ccf484644c..c18650796cc 100644 --- a/test/wpt/tests/fetch/api/resources/keepalive-redirect-window.html +++ b/test/wpt/tests/fetch/api/resources/keepalive-redirect-window.html @@ -10,20 +10,28 @@ HTTP_REMOTE_ORIGIN, HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT } = get_host_info(); -const REDIRECT_DESTINATION = - `${HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT}/fetch/api/resources/stash-put.py` + + +const SEARCH_PARAMS = new URL(location.href).searchParams; +const WITH_HEADERS = !!SEARCH_PARAMS.has('with-headers'); +const ORIGIN1 = SEARCH_PARAMS.get('origin1') || ''; +const ORIGIN2 = SEARCH_PARAMS.get('origin2') || ''; +const URL2 = SEARCH_PARAMS.get('url2') || ''; + +const REDIRECT_DESTINATION = URL2 ? URL2 : + `${ORIGIN2}/fetch/api/resources/stash-put.py` + `?key=${TOKEN}&value=on`; -const URL = - `${HTTP_REMOTE_ORIGIN}/fetch/api/resources/redirect.py?` + +const FROM_URL = + `${ORIGIN1}/fetch/api/resources/redirect.py?` + `delay=500&` + `allow_headers=foo&` + `location=${encodeURIComponent(REDIRECT_DESTINATION)}`; addEventListener('load', () => { + const headers = WITH_HEADERS ? {'foo': 'bar'} : undefined; const iframe = document.createElement('iframe'); document.body.appendChild(iframe); iframe.contentWindow.addEventListener('unload', () => { - iframe.contentWindow.fetch(URL, {keepalive: true, headers: {foo: 'bar'}}); + iframe.contentWindow.fetch(FROM_URL, {keepalive: true, headers}); }); window.opener.postMessage(TOKEN, '*'); diff --git a/test/wpt/tests/fetch/api/response/response-clone.any.js b/test/wpt/tests/fetch/api/response/response-clone.any.js index 9f4f36ed2d1..f5cda75149e 100644 --- a/test/wpt/tests/fetch/api/response/response-clone.any.js +++ b/test/wpt/tests/fetch/api/response/response-clone.any.js @@ -103,7 +103,21 @@ function testReadableStreamClone(initialBuffer, bufferType) return stream2.getReader().read(); }).then(function(data) { assert_false(data.done); - assert_array_equals(data.value, initialBuffer, "Cloned buffer chunks have the same content"); + if (initialBuffer instanceof ArrayBuffer) { + assert_true(data.value instanceof ArrayBuffer, "Cloned buffer is ArrayBufer"); + assert_equals(initialBuffer.byteLength, data.value.byteLength, "Length equal"); + assert_array_equals(new Uint8Array(data.value), new Uint8Array(initialBuffer), "Cloned buffer chunks have the same content"); + } else if (initialBuffer instanceof DataView) { + assert_true(data.value instanceof DataView, "Cloned buffer is DataView"); + assert_equals(initialBuffer.byteLength, data.value.byteLength, "Lengths equal"); + assert_equals(initialBuffer.byteOffset, data.value.byteOffset, "Offsets equal"); + for (let i = 0; i < initialBuffer.byteLength; ++i) { + assert_equals( + data.value.getUint8(i), initialBuffer.getUint8(i), "Mismatch at byte ${i}"); + } + } else { + assert_array_equals(data.value, initialBuffer, "Cloned buffer chunks have the same content"); + } assert_equals(Object.getPrototypeOf(data.value), Object.getPrototypeOf(initialBuffer), "Cloned buffers have the same type"); assert_not_equals(data.value, initialBuffer, "Buffer of cloned response stream is a clone of the original buffer"); }); diff --git a/test/wpt/tests/fetch/data-urls/navigate.window.js b/test/wpt/tests/fetch/data-urls/navigate.window.js new file mode 100644 index 00000000000..b532a006830 --- /dev/null +++ b/test/wpt/tests/fetch/data-urls/navigate.window.js @@ -0,0 +1,75 @@ +// META: timeout=long +// +// Test some edge cases around navigation to data: URLs to ensure they use the same code path + +[ + { + input: "data:text/html,", + result: 1, + name: "Nothing fancy", + }, + { + input: "data:text/html;base64,PHNjcmlwdD5wYXJlbnQucG9zdE1lc3NhZ2UoMiwgJyonKTwvc2NyaXB0Pg==", + result: 2, + name: "base64", + }, + { + input: "data:text/html;base64,PHNjcmlwdD5wYXJlbnQucG9zdE1lc3NhZ2UoNCwgJyonKTwvc2NyaXB0Pr+/", + result: 4, + name: "base64 with code points that differ from base64url" + }, + { + input: "data:text/html;base64,PHNjcml%09%20%20%0A%0C%0DwdD5wYXJlbnQucG9zdE1lc3NhZ2UoNiwgJyonKTwvc2NyaXB0Pg==", + result: 6, + name: "ASCII whitespace in the input is removed" + } +].forEach(({ input, result, name }) => { + // Use promise_test so they go sequentially + promise_test(async t => { + const event = await new Promise((resolve, reject) => { + self.addEventListener("message", t.step_func(resolve), { once: true }); + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + + // The assumption is that postMessage() is quicker + t.step_timeout(reject, 500); + frame.src = input; + }); + assert_equals(event.data, result); + }, name); +}); + +// Failure cases +[ + { + input: "data:text/html;base64,PHNjcmlwdD5wYXJlbnQucG9zdE1lc3NhZ2UoMywgJyonKTwvc2NyaXB0Pg=", + name: "base64 with incorrect padding", + }, + { + input: "data:text/html;base64,PHNjcmlwdD5wYXJlbnQucG9zdE1lc3NhZ2UoNSwgJyonKTwvc2NyaXB0Pr-_", + name: "base64url is not supported" + }, + { + input: "data:text/html;base64,%0BPHNjcmlwdD5wYXJlbnQucG9zdE1lc3NhZ2UoNywgJyonKTwvc2NyaXB0Pg==", + name: "Vertical tab in the input leads to an error" + } +].forEach(({ input, name }) => { + // Continue to use promise_test so they go sequentially + promise_test(async t => { + const event = await new Promise((resolve, reject) => { + self.addEventListener("message", t.step_func(reject), { once: true }); + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + + // The assumption is that postMessage() is quicker + t.step_timeout(resolve, 500); + frame.src = input; + }); + }, name); +}); + +// I found some of the interesting code point cases above through brute force: +// +// for (i = 0; i < 256; i++) { +// w(btoa(" + + + + + + + + + + + \ No newline at end of file diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html new file mode 100644 index 00000000000..ff24bf3670c --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html @@ -0,0 +1,69 @@ + + + + +Service Worker: Partitioned Cookies 3P Credentialless Iframe + + + + + + + + + \ No newline at end of file diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html new file mode 100644 index 00000000000..d3962d2e600 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html @@ -0,0 +1,67 @@ + + + + +Service Worker: Partitioned Cookies 3P Iframe + + + + + + + + \ No newline at end of file diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js new file mode 100644 index 00000000000..2f54a984b19 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js @@ -0,0 +1,30 @@ +self.addEventListener('message', ev => ev.waitUntil(onMessage(ev))); + +async function onMessage(event) { + if (!event.data) + return; + switch (event.data.type) { + case 'test_message': + return onTestMessage(event); + case 'echo_cookies': + return onEchoCookies(event); + default: + return; + } +} + +// test_message just verifies that the message passing is working. +async function onTestMessage(event) { + event.source.postMessage({ok: true}); +} + +// echo_cookies returns the names of all of the cookies available to the worker. +async function onEchoCookies(event) { + try { + const cookie_objects = await self.cookieStore.getAll(); + const cookies = cookie_objects.map(c => c.name); + event.source.postMessage({ok: true, cookies}); + } catch (err) { + event.source.postMessage({ok: false}); + } +} diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html new file mode 100644 index 00000000000..8e90609da22 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html @@ -0,0 +1,35 @@ + + + + +Service Worker: Partitioned Cookies 3P Window + + + + + + + diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js new file mode 100644 index 00000000000..2f54a984b19 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js @@ -0,0 +1,30 @@ +self.addEventListener('message', ev => ev.waitUntil(onMessage(ev))); + +async function onMessage(event) { + if (!event.data) + return; + switch (event.data.type) { + case 'test_message': + return onTestMessage(event); + case 'echo_cookies': + return onEchoCookies(event); + default: + return; + } +} + +// test_message just verifies that the message passing is working. +async function onTestMessage(event) { + event.source.postMessage({ok: true}); +} + +// echo_cookies returns the names of all of the cookies available to the worker. +async function onEchoCookies(event) { + try { + const cookie_objects = await self.cookieStore.getAll(); + const cookies = cookie_objects.map(c => c.name); + event.source.postMessage({ok: true, cookies}); + } catch (err) { + event.source.postMessage({ok: false}); + } +} diff --git a/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js b/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js index d6dce3675d0..a66fd81cd43 100644 --- a/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js +++ b/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js @@ -19,3 +19,28 @@ promise_test(async testCase => { navigator.storageBuckets.open( 'above_max', {quota: Number.MAX_SAFE_INTEGER + 1})); }, 'The open promise should reject with a TypeError when quota is requested outside the range of 1 to Number.MAX_SAFE_INTEGER.'); + + +promise_test(async testCase => { + await prepareForBucketTest(testCase); + + // IndexedDB + { + const quota = 1; + const bucket = await navigator.storageBuckets.open('idb', {quota}); + + const objectStoreName = 'store'; + const db = await indexedDbOpenRequest( + testCase, bucket.indexedDB, 'db', (db_to_upgrade) => { + db_to_upgrade.createObjectStore(objectStoreName); + }); + + const overflowBuffer = new Uint8Array(quota + 1); + + const txn = db.transaction(objectStoreName, 'readwrite'); + txn.objectStore(objectStoreName).add('', overflowBuffer); + + await promise_rejects_dom( + testCase, 'QuotaExceededError', transactionPromise(txn)); + } +}, 'A QuotaExceededError is thrown when a storage API exceeds the quota of the bucket its in.'); diff --git a/test/wpt/tests/storage/buckets/resources/cached-resource.txt b/test/wpt/tests/storage/buckets/resources/cached-resource.txt new file mode 100644 index 00000000000..c57eff55ebc --- /dev/null +++ b/test/wpt/tests/storage/buckets/resources/cached-resource.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/test/wpt/tests/storage/buckets/resources/util.js b/test/wpt/tests/storage/buckets/resources/util.js index 50abce14cdc..425303ce2c9 100644 --- a/test/wpt/tests/storage/buckets/resources/util.js +++ b/test/wpt/tests/storage/buckets/resources/util.js @@ -13,3 +13,45 @@ async function prepareForBucketTest(test) { } }); } + +function indexedDbOpenRequest(t, idb, dbname, upgrade_func) { + return new Promise((resolve, reject) => { + const openRequest = idb.open(dbname); + t.add_cleanup(() => { + indexedDbDeleteRequest(idb, dbname); + }); + + openRequest.onerror = () => { + reject(openRequest.error); + }; + openRequest.onsuccess = () => { + resolve(openRequest.result); + }; + openRequest.onupgradeneeded = event => { + upgrade_func(openRequest.result); + }; + }); +} + +function indexedDbDeleteRequest(idb, name) { + return new Promise((resolve, reject) => { + const deleteRequest = idb.deleteDatabase(name); + deleteRequest.onerror = () => { + reject(deleteRequest.error); + }; + deleteRequest.onsuccess = () => { + resolve(); + }; + }); +} + +function transactionPromise(txn) { + return new Promise((resolve, reject) => { + txn.onabort = () => { + reject(txn.error); + }; + txn.oncomplete = () => { + resolve(); + }; + }); +} diff --git a/test/wpt/tests/storage/estimate-indexeddb.https.any.js b/test/wpt/tests/storage/estimate-indexeddb.https.any.js index b0c6b944dd6..f0b82b9fa09 100644 --- a/test/wpt/tests/storage/estimate-indexeddb.https.any.js +++ b/test/wpt/tests/storage/estimate-indexeddb.https.any.js @@ -1,46 +1,5 @@ // META: title=StorageManager: estimate() for indexeddb - -function indexedDbOpenRequest(t, dbname, upgrade_func) { - return new Promise((resolve, reject) => { - const openRequest = indexedDB.open(dbname); - t.add_cleanup(() => { - indexedDbDeleteRequest(dbname); - }); - - openRequest.onerror = () => { - reject(openRequest.error); - }; - openRequest.onsuccess = () => { - resolve(openRequest.result); - }; - openRequest.onupgradeneeded = event => { - upgrade_func(openRequest.result); - }; - }); -} - -function indexedDbDeleteRequest(name) { - return new Promise((resolve, reject) => { - const deleteRequest = indexedDB.deleteDatabase(name); - deleteRequest.onerror = () => { - reject(deleteRequest.error); - }; - deleteRequest.onsuccess = () => { - resolve(); - }; - }); -} - -function transactionPromise(txn) { - return new Promise((resolve, reject) => { - txn.onabort = () => { - reject(txn.error); - }; - txn.oncomplete = () => { - resolve(); - }; - }); -} +// META: script=/storage/buckets/resources/util.js test(t => { assert_true('estimate' in navigator.storage); @@ -60,16 +19,17 @@ promise_test(async t => { promise_test(async t => { const arraySize = 1e6; const objectStoreName = "storageManager"; - const dbname = this.window ? window.location.pathname : - "estimate-worker.https.html"; + const dbname = + this.window ? window.location.pathname : 'estimate-worker.https.html'; - await indexedDbDeleteRequest(dbname); + await indexedDbDeleteRequest(indexedDB, dbname); let estimate = await navigator.storage.estimate(); const usageBeforeCreate = estimate.usage; - const db = await indexedDbOpenRequest(t, dbname, (db_to_upgrade) => { - db_to_upgrade.createObjectStore(objectStoreName); - }); + const db = + await indexedDbOpenRequest(t, indexedDB, dbname, (db_to_upgrade) => { + db_to_upgrade.createObjectStore(objectStoreName); + }); estimate = await navigator.storage.estimate(); const usageAfterCreate = estimate.usage; @@ -86,7 +46,7 @@ promise_test(async t => { view[i] = Math.floor(Math.random() * 255); } - const testBlob = new Blob([buffer], {type: "binary/random"}); + const testBlob = new Blob([buffer], {type: 'binary/random'}); txn.objectStore(objectStoreName).add(testBlob, 1); await transactionPromise(txn);