diff options
Diffstat (limited to 'devtools/shared/worker/tests')
4 files changed, 265 insertions, 0 deletions
diff --git a/devtools/shared/worker/tests/browser/browser.ini b/devtools/shared/worker/tests/browser/browser.ini new file mode 100644 index 0000000000..a64916dfff --- /dev/null +++ b/devtools/shared/worker/tests/browser/browser.ini @@ -0,0 +1,9 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +support-files = + ../../../../server/tests/browser/head.js + +[browser_worker-01.js] +[browser_worker-02.js] +[browser_worker-03.js] diff --git a/devtools/shared/worker/tests/browser/browser_worker-01.js b/devtools/shared/worker/tests/browser/browser_worker-01.js new file mode 100644 index 0000000000..a8dafcf4cb --- /dev/null +++ b/devtools/shared/worker/tests/browser/browser_worker-01.js @@ -0,0 +1,110 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the devtools/shared/worker communicates properly +// as both CommonJS module and as a JSM. + +const BUFFER_SIZE = 8; + +registerCleanupFunction(function () { + Services.prefs.clearUserPref("security.allow_parent_unrestricted_js_loads"); +}); + +add_task(async function () { + // Test both CJS and JSM versions + + await testWorker("JSM", () => + ChromeUtils.import("resource://devtools/shared/worker/worker.js") + ); + await testWorker("CommonJS", () => + require("resource://devtools/shared/worker/worker.js") + ); + await testTransfer(); +}); + +async function testWorker(context, workerFactory) { + // Needed for blob:null + Services.prefs.setBoolPref( + "security.allow_parent_unrestricted_js_loads", + true + ); + const { DevToolsWorker, workerify } = workerFactory(); + + const blob = new Blob( + [ + ` +importScripts("resource://gre/modules/workers/require.js"); +const { createTask } = require("resource://devtools/shared/worker/helper.js"); + +createTask(self, "groupByField", function({ + items, + groupField +}) { + const groups = {}; + for (const item of items) { + if (!groups[item[groupField]]) { + groups[item[groupField]] = []; + } + groups[item[groupField]].push(item); + } + return { groups }; +}); + `, + ], + { type: "application/javascript" } + ); + + const WORKER_URL = URL.createObjectURL(blob); + const worker = new DevToolsWorker(WORKER_URL); + + const results = await worker.performTask("groupByField", { + items: [ + { name: "Paris", country: "France" }, + { name: "Lagos", country: "Nigeria" }, + { name: "Lyon", country: "France" }, + ], + groupField: "country", + }); + + is( + Object.keys(results.groups).join(","), + "France,Nigeria", + `worker should have returned the expected result in ${context}` + ); + + URL.revokeObjectURL(WORKER_URL); + + const fn = workerify(x => x * x); + is(await fn(5), 25, `workerify works in ${context}`); + fn.destroy(); + + worker.destroy(); +} + +async function testTransfer() { + Services.prefs.setBoolPref( + "security.allow_parent_unrestricted_js_loads", + true + ); + const { workerify } = ChromeUtils.import( + "resource://devtools/shared/worker/worker.js" + ); + const workerFn = workerify(({ buf }) => buf.byteLength); + const buf = new ArrayBuffer(BUFFER_SIZE); + + is( + buf.byteLength, + BUFFER_SIZE, + "Size of the buffer before transfer is correct." + ); + + is(await workerFn({ buf }), 8, "Sent array buffer to worker"); + is(buf.byteLength, 8, "Array buffer was copied, not transferred."); + + is(await workerFn({ buf }, [buf]), 8, "Sent array buffer to worker"); + is(buf.byteLength, 0, "Array buffer was transferred, not copied."); + + workerFn.destroy(); +} diff --git a/devtools/shared/worker/tests/browser/browser_worker-02.js b/devtools/shared/worker/tests/browser/browser_worker-02.js new file mode 100644 index 0000000000..80c50cf887 --- /dev/null +++ b/devtools/shared/worker/tests/browser/browser_worker-02.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests errors are handled properly by the DevToolsWorker. + +const { + DevToolsWorker, +} = require("resource://devtools/shared/worker/worker.js"); + +const blob = new Blob( + [ + ` +importScripts("resource://gre/modules/workers/require.js"); +const { createTask } = require("resource://devtools/shared/worker/helper.js"); + +createTask(self, "myTask", function({ + shouldThrow, +} = {}) { + if (shouldThrow) { + throw new Error("err"); + } + + return "OK"; +}); + `, + ], + { type: "application/javascript" } +); + +add_task(async function () { + try { + new DevToolsWorker("resource://i/dont/exist.js"); + ok(false, "Creating a DevToolsWorker with an invalid URL throws"); + } catch (e) { + ok(true, "Creating a DevToolsWorker with an invalid URL throws"); + } + + const WORKER_URL = URL.createObjectURL(blob); + const worker = new DevToolsWorker(WORKER_URL); + try { + await worker.performTask("myTask", { shouldThrow: true }); + ok( + false, + "DevToolsWorker returns a rejected promise when an error occurs in the worker" + ); + } catch (e) { + ok( + true, + "DevToolsWorker returns a rejected promise when an error occurs in the worker" + ); + } + + try { + await worker.performTask("not a real task"); + ok( + false, + "DevToolsWorker returns a rejected promise when task does not exist" + ); + } catch (e) { + ok( + true, + "DevToolsWorker returns a rejected promise when task does not exist" + ); + } + + worker.destroy(); + try { + await worker.performTask("myTask"); + ok( + false, + "DevToolsWorker rejects when performing a task on a destroyed worker" + ); + } catch (e) { + ok( + true, + "DevToolsWorker rejects when performing a task on a destroyed worker" + ); + } + + URL.revokeObjectURL(WORKER_URL); +}); diff --git a/devtools/shared/worker/tests/browser/browser_worker-03.js b/devtools/shared/worker/tests/browser/browser_worker-03.js new file mode 100644 index 0000000000..185ba92d5e --- /dev/null +++ b/devtools/shared/worker/tests/browser/browser_worker-03.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the devtools/shared/worker can handle: +// returned primitives (or promise or Error) +// +// And tests `workerify` by doing so. + +const { workerify } = require("resource://devtools/shared/worker/worker.js"); +function square(x) { + return x * x; +} + +function squarePromise(x) { + return new Promise(resolve => resolve(x * x)); +} + +function squareError(x) { + return new Error("Nope"); +} + +function squarePromiseReject(x) { + return new Promise((_, reject) => reject("Nope")); +} + +registerCleanupFunction(function () { + Services.prefs.clearUserPref("security.allow_parent_unrestricted_js_loads"); +}); + +add_task(async function () { + // Needed for blob:null + Services.prefs.setBoolPref( + "security.allow_parent_unrestricted_js_loads", + true + ); + let fn = workerify(square); + is(await fn(5), 25, "return primitives successful"); + fn.destroy(); + + fn = workerify(squarePromise); + is(await fn(5), 25, "promise primitives successful"); + fn.destroy(); + + fn = workerify(squareError); + try { + await fn(5); + ok(false, "return error should reject"); + } catch (e) { + ok(true, "return error should reject"); + } + fn.destroy(); + + fn = workerify(squarePromiseReject); + try { + await fn(5); + ok(false, "returned rejected promise rejects"); + } catch (e) { + ok(true, "returned rejected promise rejects"); + } + fn.destroy(); +}); |