diff options
Diffstat (limited to 'testing/web-platform/mozilla/tests/workers')
11 files changed, 513 insertions, 0 deletions
diff --git a/testing/web-platform/mozilla/tests/workers/2-mib-file.py b/testing/web-platform/mozilla/tests/workers/2-mib-file.py new file mode 100644 index 0000000000..cfb563ff21 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/2-mib-file.py @@ -0,0 +1,7 @@ +import random +import string + + +def main(request, response): + r = "".join(random.choice(string.ascii_letters) for _ in range(2 * 1024 * 1024)) + return r diff --git a/testing/web-platform/mozilla/tests/workers/bug1674278-crash.html b/testing/web-platform/mozilla/tests/workers/bug1674278-crash.html new file mode 100644 index 0000000000..2b037e5b37 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/bug1674278-crash.html @@ -0,0 +1,6 @@ +<html class='test-wait'> +<script> +var worker = new Worker('bug1674278.js'); +worker.postMessage('', []); +</script> +</html> diff --git a/testing/web-platform/mozilla/tests/workers/bug1674278.js b/testing/web-platform/mozilla/tests/workers/bug1674278.js new file mode 100644 index 0000000000..56105cb76e --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/bug1674278.js @@ -0,0 +1,6 @@ +self.onmessage = async function(e) { + var a = await self.fetch('2-mib-file.py'); + var b = await a.blob(); + self.close() + await b.arrayBuffer(); +} diff --git a/testing/web-platform/mozilla/tests/workers/modules/dedicated-worker-import-csp.html b/testing/web-platform/mozilla/tests/workers/modules/dedicated-worker-import-csp.html new file mode 100644 index 0000000000..ed38ecb3e5 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/modules/dedicated-worker-import-csp.html @@ -0,0 +1,115 @@ +<!DOCTYPE html> +<title>DedicatedWorker: CSP for ES Modules</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +async function openWindow(url) { + const win = window.open(url, '_blank'); + add_result_callback(() => win.close()); + const msg_event = await new Promise(resolve => window.onmessage = resolve); + assert_equals(msg_event.data, 'LOADED'); + return win; +} + +function import_csp_test( + cspHeader, importType, expectedImportedModules, description) { + // Append CSP header to windowURL for static import tests since static import + // scripts should obey Window's CSP. + const windowURL = `resources/new-worker-window.html`; + // Append CSP header to scriptURL for dynamic import tests since dynamic + // import scripts should obey Worker script's response's CSP. + const scriptURL = `${importType}-import-remote-origin-script-worker.sub.js` + + `?pipe=header(Content-Security-Policy, ${cspHeader})`; + promise_test(async () => { + const win = await openWindow(windowURL); + // Ask the window to start a dedicated worker. + win.postMessage(scriptURL, '*'); + const msg_event = await new Promise(resolve => window.onmessage = resolve); + assert_array_equals(msg_event.data, expectedImportedModules); + }, description); +} + +// Tests for static import. +// +// Static import should obey the worker-src directive and the script-src +// directive. If the both directives are specified, the worker-src directive +// should be prioritized. +// +// Step 1: "If the result of executing 6.6.1.11 Get the effective directive for +// request on request is "worker-src", and policy contains a directive whose +// name is "worker-src", return "Allowed"." +// "Note: If worker-src is present, we’ll defer to it when handling worker +// requests." +// https://w3c.github.io/webappsec-csp/#script-src-pre-request + +import_csp_test( + "worker-src 'self' 'unsafe-inline'", + "static", + ['ERROR'], + "worker-src 'self' directive should disallow cross origin static import."); + +import_csp_test( + "worker-src * 'unsafe-inline'", + "static", + ["export-on-load-script.js"], + "worker-src * directive should allow cross origin static import.") + +import_csp_test( + "script-src 'self' 'unsafe-inline'", + "static", + ['ERROR'], + "script-src 'self' directive should disallow cross origin static import."); + +import_csp_test( + "script-src * 'unsafe-inline'", + "static", + ["export-on-load-script.js"], + "script-src * directive should allow cross origin static import.") + +import_csp_test( + "worker-src *; script-src 'self' 'unsafe-inline'", + "static", + ["export-on-load-script.js"], + "worker-src * directive should override script-src 'self' directive and " + + "allow cross origin static import."); + +import_csp_test( + "worker-src 'self'; script-src * 'unsafe-inline'", + "static", + ['ERROR'], + "worker-src 'self' directive should override script-src * directive and " + + "disallow cross origin static import."); + +// Tests for dynamic import. +// +// Dynamic import should obey the script-src directive instead of the worker-src +// directive according to the specs: +// +// Dynamic import has the "script" destination. +// Step 2.4: "Fetch a module script graph given url, ..., "script", ..." +// https://html.spec.whatwg.org/multipage/webappapis.html#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability) +// +// The "script" destination should obey the script-src CSP directive. +// Step 2: "If request's destination is script-like:" +// https://w3c.github.io/webappsec-csp/#script-src-pre-request + +import_csp_test( + "script-src 'self' 'unsafe-inline'", + "dynamic", + ['ERROR'], + "script-src 'self' directive should disallow cross origin dynamic import."); + +import_csp_test( + "script-src * 'unsafe-inline'", + "dynamic", + ["export-on-load-script.js"], + "script-src * directive should allow cross origin dynamic import.") + +import_csp_test( + "worker-src 'self' 'unsafe-inline'", + "dynamic", + ["export-on-load-script.js"], + "worker-src 'self' directive should not take effect on dynamic import."); + +</script> diff --git a/testing/web-platform/mozilla/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js b/testing/web-platform/mozilla/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js new file mode 100644 index 0000000000..7ed6543890 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/modules/resources/dynamic-import-remote-origin-script-worker.sub.js @@ -0,0 +1,17 @@ +// Import a remote origin script. +const importUrl = + 'https://{{domains[www1]}}:{{ports[https][0]}}/workers/modules/resources/export-on-load-script.js'; +if ('DedicatedWorkerGlobalScope' in self && + self instanceof DedicatedWorkerGlobalScope) { + import(importUrl) + .then(module => postMessage(module.importedModules)) + .catch(e => postMessage(['ERROR'])); +} else if ( + 'SharedWorkerGlobalScope' in self && + self instanceof SharedWorkerGlobalScope) { + onconnect = e => { + import(importUrl) + .then(module => e.ports[0].postMessage(module.importedModules)) + .catch(error => e.ports[0].postMessage(['ERROR'])); + }; +} diff --git a/testing/web-platform/mozilla/tests/workers/modules/resources/new-shared-worker-window.html b/testing/web-platform/mozilla/tests/workers/modules/resources/new-shared-worker-window.html new file mode 100644 index 0000000000..84564fd7b6 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/modules/resources/new-shared-worker-window.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>SharedWorker: new SharedWorker()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +let worker; + +// Create a new shared worker for a given script url. +window.onmessage = e => { + worker = new SharedWorker(e.data.scriptURL, + { name: e.data.name, type: 'module' }); + worker.port.onmessage = msg => window.opener.postMessage(msg.data, '*'); + worker.onerror = err => { + window.opener.postMessage(['ERROR'], '*'); + err.preventDefault(); + }; +} +window.opener.postMessage('LOADED', '*'); +</script> diff --git a/testing/web-platform/mozilla/tests/workers/modules/resources/new-worker-window.html b/testing/web-platform/mozilla/tests/workers/modules/resources/new-worker-window.html new file mode 100644 index 0000000000..32a89fae0e --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/modules/resources/new-worker-window.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>DedicatedWorker: new Worker()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +let worker; + +// Creates a new dedicated worker for a given script url. +window.onmessage = e => { + worker = new Worker(e.data, { type: 'module' }); + worker.postMessage('start'); + worker.onmessage = msg => window.opener.postMessage(msg.data, '*'); + worker.onerror = err => { + window.opener.postMessage(['ERROR'], '*'); + err.preventDefault(); + }; +}; +window.opener.postMessage('LOADED', '*'); +</script> diff --git a/testing/web-platform/mozilla/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js b/testing/web-platform/mozilla/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js new file mode 100644 index 0000000000..6432dd5d80 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/modules/resources/static-import-remote-origin-script-worker.sub.js @@ -0,0 +1,20 @@ +// Import a remote origin script. +import * as module from 'https://{{domains[www1]}}:{{ports[https][0]}}/workers/modules/resources/export-on-load-script.py'; +if ('DedicatedWorkerGlobalScope' in self && + self instanceof DedicatedWorkerGlobalScope) { + self.onmessage = e => { + e.target.postMessage(module.importedModules); + }; +} else if ( + 'SharedWorkerGlobalScope' in self && + self instanceof SharedWorkerGlobalScope) { + self.onconnect = e => { + e.ports[0].postMessage(module.importedModules); + }; +} else if ( + 'ServiceWorkerGlobalScope' in self && + self instanceof ServiceWorkerGlobalScope) { + self.onmessage = e => { + e.source.postMessage(module.importedModules); + }; +} diff --git a/testing/web-platform/mozilla/tests/workers/modules/shared-worker-import-csp.html b/testing/web-platform/mozilla/tests/workers/modules/shared-worker-import-csp.html new file mode 100644 index 0000000000..707b6fb020 --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/modules/shared-worker-import-csp.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<title>SharedWorker: CSP for ES Modules</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +// This Set is for checking a shared worker in each test is newly created. +const existingWorkers = new Set(); + +async function openWindow(url) { + const win = window.open(url, '_blank'); + add_result_callback(() => win.close()); + const msgEvent = await new Promise(resolve => window.onmessage = resolve); + assert_equals(msgEvent.data, 'LOADED'); + return win; +} + +function import_csp_test( + cspHeader, importType, expectedImportedModules, description) { + // Append CSP header to windowURL for static import tests since static import + // scripts should obey Window's CSP. + const windowURL = "resources/new-shared-worker-window.html" + // Append CSP header to scriptURL as scripts should obey SharedWorker + // script's responce's CSP. + const scriptURL = `${importType}-import-remote-origin-script-worker.sub.js` + + `?pipe=header(Content-Security-Policy, ${cspHeader})`; + promise_test(async () => { + // Open a window that has the given CSP header. + const win = await openWindow(windowURL); + // Construct a unique name for SharedWorker. + const name = `${cspHeader}_${importType}`; + const workerProperties = { scriptURL, name }; + // Check if this shared worker is newly created. + assert_false(existingWorkers.has(workerProperties)); + existingWorkers.add(workerProperties); + + // Ask the window to start a shared worker with the given CSP header. + // The shared worker doesn't inherits the window's CSP header. + // https://w3c.github.io/webappsec-csp/#initialize-global-object-csp + win.postMessage(workerProperties, '*'); + const msg_event = await new Promise(resolve => window.onmessage = resolve); + assert_array_equals(msg_event.data, expectedImportedModules); + }, description); +} + +// Tests for static import. +// +// Static import should obey the worker-src directive and the script-src +// directive. If the both directives are specified, the worker-src directive +// should be prioritized. +// +// "The script-src directive acts as a default fallback for all script-like +// destinations (including worker-specific destinations if worker-src is not +// present)." +// https://w3c.github.io/webappsec-csp/#directive-script-src + +import_csp_test( + "worker-src 'self' 'unsafe-inline'", "static", + ['ERROR'], + "worker-src 'self' directive should disallow cross origin static import."); + +import_csp_test( + "worker-src * 'unsafe-inline'", "static", + ["export-on-load-script.js"], + "worker-src * directive should allow cross origin static import."); + +import_csp_test( + "script-src 'self' 'unsafe-inline'", "static", + ['ERROR'], + "script-src 'self' directive should disallow cross origin static import."); + +import_csp_test( + "script-src * 'unsafe-inline'", "static", + ["export-on-load-script.js"], + "script-src * directive should allow cross origin static import."); + +import_csp_test( + "worker-src *; script-src 'self' 'unsafe-inline'", "static", + ["export-on-load-script.js"], + "worker-src * directive should override script-src 'self' directive and " + + "allow cross origin static import."); + +import_csp_test( + "worker-src 'self'; script-src * 'unsafe-inline'", "static", + ['ERROR'], + "worker-src 'self' directive should override script-src * directive and " + + "disallow cross origin static import."); + +// Tests for dynamic import. +// +// Dynamic import should obey SharedWorker script's CSP instead of parent +// Window's CSP. +// +// Dynamic import should obey the script-src directive instead of the worker-src +// directive according to the specs: +// +// Dynamic import has the "script" destination. +// Step 3: "Fetch a single module script graph given url, ..., "script", ..." +// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-an-import()-module-script-graph +// +// The "script" destination should obey the script-src CSP directive. +// "The script-src directive acts as a default fallback for all script-like +// destinations (including worker-specific destinations if worker-src is not +// present)." +// https://w3c.github.io/webappsec-csp/#directive-script-src + +import_csp_test( + "script-src 'self' 'unsafe-inline'", "dynamic", + ['ERROR'], + "script-src 'self' directive should disallow cross origin dynamic import."); + +import_csp_test( + "script-src * 'unsafe-inline'", "dynamic", + ["export-on-load-script.js"], + "script-src * directive should allow cross origin dynamic import."); + +import_csp_test( + "worker-src 'self' 'unsafe-inline'", "dynamic", + ["export-on-load-script.js"], + "worker-src 'self' directive should not take effect on dynamic import."); + +</script> diff --git a/testing/web-platform/mozilla/tests/workers/resources/worker.js b/testing/web-platform/mozilla/tests/workers/resources/worker.js new file mode 100644 index 0000000000..cc1692eb9c --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/resources/worker.js @@ -0,0 +1,129 @@ +const maxNestingLevel = 5; +let expectedNestingLevel = 1; +let timer; +let isInterval = false; +let testStage = "ScriptLoaded"; +let stopIncreaseExpectedLevel = false; +let startClampedTimeStamp = 0; +let startRepeatingClamped = false; +let repeatCount = 0; +let maxRepeatTimes = 10; + +let timerCallback = async () => { + let now = Date.now(); + if (WorkerTestUtils.currentTimerNestingLevel() !== expectedNestingLevel) { + postMessage({ + stage: testStage, + status: "FAIL", + msg: `current timer nesting level is ${WorkerTestUtils.currentTimerNestingLevel()}, expected ${expectedNestingLevel}`, + }); + if (isInterval) { + clearInterval(timer); + } + return; + } + + if (!stopIncreaseExpectedLevel) { + if (expectedNestingLevel === maxNestingLevel) { + stopIncreaseExpectedLevel = true; + startClampedTimeStamp = now; + } else { + expectedNestingLevel = expectedNestingLevel + 1; + } + if (!isInterval) { + setTimeout(timerCallback, 0); + } + return; + } + + // This is the first time the timeout is clamped, checking if it is clamped + // to at least 2ms. + if (repeatCount === 0) { + await Promise.resolve(true).then(() => { + if (WorkerTestUtils.currentTimerNestingLevel() !== expectedNestingLevel) { + postMessage({ + stage: testStage, + status: "FAIL", + msg: `Timer nesting level should be in effect for immediately resolved micro-tasks`, + }); + } + }); + if (now - startClampedTimeStamp < 2 ) { + startRepeatingClamped = true; + } else { + postMessage({ stage: testStage, status: "PASS", msg: "" }); + } + } + + // If the first clamped timeout is less than 2ms, start to repeat the clamped + // timeout for 10 times. Then checking if total clamped time should be at least + // 25ms. + if (startRepeatingClamped) { + if (repeatCount === 10) { + if (now - startClampedTimeStamp < 25) { + postMessage({ + stage: testStage, + status: "FAIL", + msg: `total clamped time of repeating ten times should be at least 25ms(${now - startClampedTimeStamp})`, + }); + } else { + postMessage({ stage: testStage, status: "PASS", msg: "" }); + } + } else { + repeatCount = repeatCount + 1; + if (!isInterval) { + setTimeout(timerCallback, 0); + } + return; + } + } + + // reset testing variables + repeatCount = 0; + startRepeatingClamped = false; + stopIncreaseExpectedLevel = false; + if (isInterval) { + clearInterval(timer); + } +}; + +onmessage = async e => { + testStage = e.data; + switch (e.data) { + case "CheckInitialValue": + if (WorkerTestUtils.currentTimerNestingLevel() === 0) { + postMessage({ stage: testStage, status: "PASS", msg: "" }); + } else { + postMessage({ + stage: testStage, + status: "FAIL", + msg: `current timer nesting level should be 0(${WorkerTestUtils.currentTimerNestingLevel()}) after top level script loaded.`, + }); + } + break; + case "TestSetInterval": + expectedNestingLevel = 1; + isInterval = true; + timer = setInterval(timerCallback, 0); + break; + case "TestSetTimeout": + expectedNestingLevel = 1; + isInterval = false; + setTimeout(timerCallback, 0); + break; + case "CheckNoTimer": + if (WorkerTestUtils.currentTimerNestingLevel() === 0) { + postMessage({ stage: testStage, status: "PASS", msg: "" }); + } else { + postMessage({ + stage: testStage, + status: "FAIL", + msg: `current timer nesting level should be 0(${WorkerTestUtils.currentTimerNestingLevel()}) when there is no timer in queue.`, + }); + } + + break; + } +}; + +postMessage({ stage: testStage, status: "PASS" }); diff --git a/testing/web-platform/mozilla/tests/workers/worker_timer_nesting_level.html b/testing/web-platform/mozilla/tests/workers/worker_timer_nesting_level.html new file mode 100644 index 0000000000..e39f9e1b0e --- /dev/null +++ b/testing/web-platform/mozilla/tests/workers/worker_timer_nesting_level.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<title>Worker: Timer Nesting Level</title> +<Script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +'use strict' + +/** + * This test includes following four test stages. + * 1. CheckInitialValue: Checking the initial value of worker's current timer + * nesting level after the worker's top level script is loaded. The result + * is expected as 0. + * 2. TestSetInterval: Checking the worker's current timer nesting level with + * setInterval with following steps + * 1. call setInterval(callback, 0) to create a repeating timer. + * 2. checking the current timer nesting level in the callback. The value + * should increase every time executing the callback until it reaches the + * maximun nesting level(5). + * 3. Checking the worker's current timer nesting level with immediately + * resolved promise. + * 4. Checking the the time duration between two callback launching. + * 3. TestSetTimeout: Checking the worker's current timer nesting level with + * setTimeout. This stage has similar test steps with TestSetInterval. + * The difference is this stage using the recursive setTimeout to accumulate + * the timer nesting level. + * 4. CheckNoTimer: Checking the situation which the worker has no pending + * timer. The result is expected as 0. + */ + +let testStages = ["CheckInitialValue", + "TestSetInterval", + "TestSetTimeout", + "CheckNoTimer"]; + +promise_test(async function(t) { + let result = await new Promise( (resolve, reject) => { + let worker = new Worker("resources/worker.js"); + worker.onmessage = (e) => { + if (e.data.status === "FAIL") { + resolve(e.data); + return; + } + if (testStages.length !== 0) { + worker.postMessage(testStages.shift()); + } else { + resolve({status: "PASS", msg: "Timer nesting level for workers"}); + } + }; + }); + assert_true(result.status === "PASS", result.msg); +}, 'Worker timer nesting level'); +</script> |