summaryrefslogtreecommitdiffstats
path: root/dom/quota/test/modules
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/test/modules')
-rw-r--r--dom/quota/test/modules/content/Assert.mjs14
-rw-r--r--dom/quota/test/modules/content/ModuleLoader.mjs65
-rw-r--r--dom/quota/test/modules/content/StorageUtils.mjs71
-rw-r--r--dom/quota/test/modules/content/Utils.mjs18
-rw-r--r--dom/quota/test/modules/content/UtilsParent.mjs21
-rw-r--r--dom/quota/test/modules/content/WorkerDriver.mjs68
-rw-r--r--dom/quota/test/modules/content/worker/Assert.js22
-rw-r--r--dom/quota/test/modules/content/worker/ModuleLoader.js52
-rw-r--r--dom/quota/test/modules/content/worker/Utils.js27
-rw-r--r--dom/quota/test/modules/content/worker/UtilsChild.mjs22
-rw-r--r--dom/quota/test/modules/content/worker/head.js57
-rw-r--r--dom/quota/test/modules/system/ModuleLoader.sys.mjs63
-rw-r--r--dom/quota/test/modules/system/StorageUtils.sys.mjs97
-rw-r--r--dom/quota/test/modules/system/Utils.sys.mjs38
-rw-r--r--dom/quota/test/modules/system/UtilsParent.sys.mjs32
-rw-r--r--dom/quota/test/modules/system/WorkerDriver.sys.mjs68
-rw-r--r--dom/quota/test/modules/system/worker/.eslintrc.js21
-rw-r--r--dom/quota/test/modules/system/worker/Assert.js22
-rw-r--r--dom/quota/test/modules/system/worker/ModuleLoader.js52
-rw-r--r--dom/quota/test/modules/system/worker/Utils.js41
-rw-r--r--dom/quota/test/modules/system/worker/UtilsChild.mjs52
-rw-r--r--dom/quota/test/modules/system/worker/head.js56
22 files changed, 979 insertions, 0 deletions
diff --git a/dom/quota/test/modules/content/Assert.mjs b/dom/quota/test/modules/content/Assert.mjs
new file mode 100644
index 0000000000..c9b8a11d1a
--- /dev/null
+++ b/dom/quota/test/modules/content/Assert.mjs
@@ -0,0 +1,14 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This file expectes the simpletest environment to be available in the scope
+// it is loaded into.
+/* eslint-env mozilla/simpletest */
+
+// Just a wrapper around SimpleTest related functions for now.
+export const Assert = {
+ ok,
+ equal: is,
+};
diff --git a/dom/quota/test/modules/content/ModuleLoader.mjs b/dom/quota/test/modules/content/ModuleLoader.mjs
new file mode 100644
index 0000000000..db8a04277d
--- /dev/null
+++ b/dom/quota/test/modules/content/ModuleLoader.mjs
@@ -0,0 +1,65 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This file expectes the SpecialPowers to be available in the scope
+// it is loaded into.
+/* global SpecialPowers */
+
+export function ModuleLoader(base, depth, proto) {
+ const modules = {};
+
+ const principal = SpecialPowers.wrap(document).nodePrincipal;
+
+ const sharedGlobalSandbox = SpecialPowers.Cu.Sandbox(principal, {
+ invisibleToDebugger: true,
+ sandboxName: "FS Module Loader",
+ sandboxPrototype: proto,
+ wantComponents: false,
+ wantGlobalProperties: [],
+ wantXrays: false,
+ });
+
+ const require = async function (id) {
+ if (modules[id]) {
+ return modules[id].exported_symbols;
+ }
+
+ const url = new URL(depth + id, base);
+
+ const module = Object.create(null, {
+ exported_symbols: {
+ configurable: false,
+ enumerable: true,
+ value: Object.create(null),
+ writable: true,
+ },
+ });
+
+ modules[id] = module;
+
+ const properties = {
+ require_module: require,
+ exported_symbols: module.exported_symbols,
+ };
+
+ // Create a new object in this sandbox, that will be used as the scope
+ // object for this particular module.
+ const sandbox = sharedGlobalSandbox.Object();
+ Object.assign(sandbox, properties);
+
+ SpecialPowers.Services.scriptloader.loadSubScript(url.href, sandbox);
+
+ return module.exported_symbols;
+ };
+
+ const returnObj = {
+ require: {
+ enumerable: true,
+ value: require,
+ },
+ };
+
+ return Object.create(null, returnObj);
+}
diff --git a/dom/quota/test/modules/content/StorageUtils.mjs b/dom/quota/test/modules/content/StorageUtils.mjs
new file mode 100644
index 0000000000..f369484972
--- /dev/null
+++ b/dom/quota/test/modules/content/StorageUtils.mjs
@@ -0,0 +1,71 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This file expectes the SpecialPowers to be available in the scope
+// it is loaded into.
+/* global SpecialPowers */
+
+class RequestError extends Error {
+ constructor(resultCode, resultName) {
+ super(`Request failed (code: ${resultCode}, name: ${resultName})`);
+ this.name = "RequestError";
+ this.resultCode = resultCode;
+ this.resultName = resultName;
+ }
+}
+
+export async function setStoragePrefs(optionalPrefsToSet) {
+ const prefsToSet = [
+ // Not needed right now, but might be needed in future.
+ // ["dom.quotaManager.testing", true],
+ ];
+
+ if (SpecialPowers.Services.appinfo.OS === "WINNT") {
+ prefsToSet.push(["dom.quotaManager.useDOSDevicePathSyntax", true]);
+ }
+
+ if (optionalPrefsToSet) {
+ prefsToSet.push(...optionalPrefsToSet);
+ }
+
+ await SpecialPowers.pushPrefEnv({ set: prefsToSet });
+}
+
+export async function getUsageForOrigin(principal, fromMemory) {
+ const request = SpecialPowers.Services.qms.getUsageForPrincipal(
+ principal,
+ function () {},
+ fromMemory
+ );
+
+ await new Promise(function (resolve) {
+ request.callback = SpecialPowers.wrapCallback(function () {
+ resolve();
+ });
+ });
+
+ if (request.resultCode != SpecialPowers.Cr.NS_OK) {
+ throw new RequestError(request.resultCode, request.resultName);
+ }
+
+ return request.result;
+}
+
+export async function clearStoragesForOrigin(principal) {
+ const request =
+ SpecialPowers.Services.qms.clearStoragesForPrincipal(principal);
+
+ await new Promise(function (resolve) {
+ request.callback = SpecialPowers.wrapCallback(function () {
+ resolve();
+ });
+ });
+
+ if (request.resultCode != SpecialPowers.Cr.NS_OK) {
+ throw new RequestError(request.resultCode, request.resultName);
+ }
+
+ return request.result;
+}
diff --git a/dom/quota/test/modules/content/Utils.mjs b/dom/quota/test/modules/content/Utils.mjs
new file mode 100644
index 0000000000..c6a7415dba
--- /dev/null
+++ b/dom/quota/test/modules/content/Utils.mjs
@@ -0,0 +1,18 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This file expectes the SpecialPowers to be available in the scope
+// it is loaded into.
+/* global SpecialPowers */
+
+import { getUsageForOrigin } from "./StorageUtils.mjs";
+
+export const Utils = {
+ async getCachedOriginUsage() {
+ const principal = SpecialPowers.wrap(document).nodePrincipal;
+ const result = await getUsageForOrigin(principal, true);
+ return result.usage;
+ },
+};
diff --git a/dom/quota/test/modules/content/UtilsParent.mjs b/dom/quota/test/modules/content/UtilsParent.mjs
new file mode 100644
index 0000000000..f7ebde3c34
--- /dev/null
+++ b/dom/quota/test/modules/content/UtilsParent.mjs
@@ -0,0 +1,21 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import { Utils } from "./Utils.mjs";
+
+export const UtilsParent = {
+ async OnMessageReceived(worker, msg) {
+ switch (msg.op) {
+ case "getCachedOriginUsage": {
+ const result = await Utils.getCachedOriginUsage();
+ worker.postMessage(result);
+ break;
+ }
+
+ default:
+ throw new Error(`Unknown op ${msg.op}`);
+ }
+ },
+};
diff --git a/dom/quota/test/modules/content/WorkerDriver.mjs b/dom/quota/test/modules/content/WorkerDriver.mjs
new file mode 100644
index 0000000000..0ba74b65f7
--- /dev/null
+++ b/dom/quota/test/modules/content/WorkerDriver.mjs
@@ -0,0 +1,68 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+export async function runTestInWorker(script, base, listener) {
+ return new Promise(function (resolve) {
+ const globalHeadUrl = new URL(
+ "/tests/dom/quota/test/modules/worker/head.js",
+ base
+ );
+
+ let modules = {};
+
+ const worker = new Worker(globalHeadUrl.href);
+
+ worker.onmessage = async function (event) {
+ const data = event.data;
+ const moduleName = data.moduleName;
+ const objectName = data.objectName;
+
+ if (moduleName && objectName) {
+ if (!modules[moduleName]) {
+ // eslint-disable-next-line no-unsanitized/method
+ modules[moduleName] = await import(
+ "/tests/dom/quota/test/modules/" + moduleName + ".mjs"
+ );
+ }
+ await modules[moduleName][objectName].OnMessageReceived(worker, data);
+ return;
+ }
+
+ switch (data.op) {
+ case "ok":
+ listener.onOk(data.value, data.message);
+ break;
+
+ case "is":
+ listener.onIs(data.a, data.b, data.message);
+ break;
+
+ case "info":
+ listener.onInfo(data.message);
+ break;
+
+ case "finish":
+ resolve();
+ break;
+
+ case "failure":
+ listener.onOk(false, "Worker had a failure: " + data.message);
+ resolve();
+ break;
+ }
+ };
+
+ worker.onerror = function (event) {
+ listener.onOk(false, "Worker had an error: " + event.data);
+ resolve();
+ };
+
+ const scriptUrl = new URL(script, base);
+
+ const localHeadUrl = new URL("head.js", scriptUrl);
+
+ worker.postMessage([localHeadUrl.href, scriptUrl.href]);
+ });
+}
diff --git a/dom/quota/test/modules/content/worker/Assert.js b/dom/quota/test/modules/content/worker/Assert.js
new file mode 100644
index 0000000000..7c7e2683ea
--- /dev/null
+++ b/dom/quota/test/modules/content/worker/Assert.js
@@ -0,0 +1,22 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const Assert = {
+ ok(value, message) {
+ postMessage({
+ op: "ok",
+ value: !!value,
+ message,
+ });
+ },
+ equal(a, b, message) {
+ postMessage({
+ op: "is",
+ a,
+ b,
+ message,
+ });
+ },
+};
diff --git a/dom/quota/test/modules/content/worker/ModuleLoader.js b/dom/quota/test/modules/content/worker/ModuleLoader.js
new file mode 100644
index 0000000000..5354c26e34
--- /dev/null
+++ b/dom/quota/test/modules/content/worker/ModuleLoader.js
@@ -0,0 +1,52 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function ModuleLoader(base, depth) {
+ const modules = {};
+
+ const require = async function (id) {
+ if (modules[id]) {
+ return modules[id].exported_symbols;
+ }
+
+ const url = new URL(depth + id, base);
+
+ const module = Object.create(null, {
+ exported_symbols: {
+ configurable: false,
+ enumerable: true,
+ value: Object.create(null),
+ writable: true,
+ },
+ });
+
+ modules[id] = module;
+
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", url.href, false);
+ xhr.responseType = "text";
+ xhr.send();
+
+ let source = xhr.responseText;
+
+ let code = new Function(
+ "require_module",
+ "exported_symbols",
+ `eval(arguments[2] + "\\n//# sourceURL=" + arguments[3] + "\\n")`
+ );
+ code(require, module.exported_symbols, source, url.href);
+
+ return module.exported_symbols;
+ };
+
+ const returnObj = {
+ require: {
+ enumerable: true,
+ value: require,
+ },
+ };
+
+ return Object.create(null, returnObj);
+}
diff --git a/dom/quota/test/modules/content/worker/Utils.js b/dom/quota/test/modules/content/worker/Utils.js
new file mode 100644
index 0000000000..0f8888fc00
--- /dev/null
+++ b/dom/quota/test/modules/content/worker/Utils.js
@@ -0,0 +1,27 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+let UtilsChild;
+
+async function ensureUtilsChild() {
+ if (UtilsChild) {
+ return;
+ }
+
+ const { UtilsChild: importedUtilsChild } = await import(
+ "/tests/dom/quota/test/modules/worker/UtilsChild.mjs"
+ );
+
+ UtilsChild = importedUtilsChild;
+}
+
+const Utils = {
+ async getCachedOriginUsage() {
+ await ensureUtilsChild();
+
+ const result = await UtilsChild.getCachedOriginUsage();
+ return result;
+ },
+};
diff --git a/dom/quota/test/modules/content/worker/UtilsChild.mjs b/dom/quota/test/modules/content/worker/UtilsChild.mjs
new file mode 100644
index 0000000000..db5757bff0
--- /dev/null
+++ b/dom/quota/test/modules/content/worker/UtilsChild.mjs
@@ -0,0 +1,22 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+export const UtilsChild = {
+ async getCachedOriginUsage() {
+ postMessage({
+ moduleName: "UtilsParent",
+ objectName: "UtilsParent",
+ op: "getCachedOriginUsage",
+ });
+
+ return new Promise(function (resolve) {
+ addEventListener("message", async function onMessage(event) {
+ removeEventListener("message", onMessage);
+ const data = event.data;
+ resolve(data);
+ });
+ });
+ },
+};
diff --git a/dom/quota/test/modules/content/worker/head.js b/dom/quota/test/modules/content/worker/head.js
new file mode 100644
index 0000000000..c43d784596
--- /dev/null
+++ b/dom/quota/test/modules/content/worker/head.js
@@ -0,0 +1,57 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* eslint-env worker */
+
+const Cr = {
+ NS_ERROR_NOT_IMPLEMENTED: 2147500033,
+};
+
+function add_task(func) {
+ if (!add_task.tasks) {
+ add_task.tasks = [];
+ add_task.index = 0;
+ }
+
+ add_task.tasks.push(func);
+}
+
+addEventListener("message", async function onMessage(event) {
+ function info(message) {
+ postMessage({ op: "info", message });
+ }
+
+ function executeSoon(callback) {
+ const channel = new MessageChannel();
+ channel.port1.postMessage("");
+ channel.port2.onmessage = function () {
+ callback();
+ };
+ }
+
+ function runNextTest() {
+ if (add_task.index < add_task.tasks.length) {
+ const task = add_task.tasks[add_task.index++];
+ info("add_task | Entering test " + task.name);
+ task()
+ .then(function () {
+ executeSoon(runNextTest);
+ info("add_task | Leaving test " + task.name);
+ })
+ .catch(function (ex) {
+ postMessage({ op: "failure", message: "" + ex });
+ });
+ } else {
+ postMessage({ op: "finish" });
+ }
+ }
+
+ removeEventListener("message", onMessage);
+
+ const data = event.data;
+ importScripts(...data);
+
+ executeSoon(runNextTest);
+});
diff --git a/dom/quota/test/modules/system/ModuleLoader.sys.mjs b/dom/quota/test/modules/system/ModuleLoader.sys.mjs
new file mode 100644
index 0000000000..d4f8f51c11
--- /dev/null
+++ b/dom/quota/test/modules/system/ModuleLoader.sys.mjs
@@ -0,0 +1,63 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+export function ModuleLoader(base, depth, proto) {
+ const modules = {};
+
+ const principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
+ Ci.nsIPrincipal
+ );
+
+ const sharedGlobalsandbox = Cu.Sandbox(principal, {
+ invisibleToDebugger: true,
+ sandboxName: "FS Module Loader",
+ sandboxPrototype: proto,
+ wantComponents: false,
+ wantGlobalProperties: [],
+ wantXrays: false,
+ });
+
+ const require = async function (id) {
+ if (modules[id]) {
+ return modules[id].exported_symbols;
+ }
+
+ const url = new URL(depth + id, base);
+
+ const module = Object.create(null, {
+ exported_symbols: {
+ configurable: false,
+ enumerable: true,
+ value: Object.create(null),
+ writable: true,
+ },
+ });
+
+ modules[id] = module;
+
+ const properties = {
+ require_module: require,
+ exported_symbols: module.exported_symbols,
+ };
+
+ // Create a new object in this sandbox, that will be used as the scope
+ // object for this particular module.
+ const sandbox = sharedGlobalsandbox.Object();
+ Object.assign(sandbox, properties);
+
+ Services.scriptloader.loadSubScript(url.href, sandbox);
+
+ return module.exported_symbols;
+ };
+
+ const returnObj = {
+ require: {
+ enumerable: true,
+ value: require,
+ },
+ };
+
+ return Object.create(null, returnObj);
+}
diff --git a/dom/quota/test/modules/system/StorageUtils.sys.mjs b/dom/quota/test/modules/system/StorageUtils.sys.mjs
new file mode 100644
index 0000000000..ddd17e2875
--- /dev/null
+++ b/dom/quota/test/modules/system/StorageUtils.sys.mjs
@@ -0,0 +1,97 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+class RequestError extends Error {
+ constructor(resultCode, resultName) {
+ super(`Request failed (code: ${resultCode}, name: ${resultName})`);
+ this.name = "RequestError";
+ this.resultCode = resultCode;
+ this.resultName = resultName;
+ }
+}
+
+export function setStoragePrefs(optionalPrefsToSet) {
+ const prefsToSet = [["dom.quotaManager.testing", true]];
+
+ if (Services.appinfo.OS === "WINNT") {
+ prefsToSet.push(["dom.quotaManager.useDOSDevicePathSyntax", true]);
+ }
+
+ if (optionalPrefsToSet) {
+ prefsToSet.push(...optionalPrefsToSet);
+ }
+
+ for (const pref of prefsToSet) {
+ Services.prefs.setBoolPref(pref[0], pref[1]);
+ }
+}
+
+export function clearStoragePrefs(optionalPrefsToClear) {
+ const prefsToClear = ["dom.quotaManager.testing", "dom.simpleDB.enabled"];
+
+ if (Services.appinfo.OS === "WINNT") {
+ prefsToClear.push("dom.quotaManager.useDOSDevicePathSyntax");
+ }
+
+ if (optionalPrefsToClear) {
+ prefsToClear.push(...optionalPrefsToClear);
+ }
+
+ for (const pref of prefsToClear) {
+ Services.prefs.clearUserPref(pref);
+ }
+}
+
+export async function getUsageForOrigin(principal, fromMemory) {
+ const request = Services.qms.getUsageForPrincipal(
+ principal,
+ function () {},
+ fromMemory
+ );
+
+ await new Promise(function (resolve) {
+ request.callback = function () {
+ resolve();
+ };
+ });
+
+ if (request.resultCode != Cr.NS_OK) {
+ throw new RequestError(request.resultCode, request.resultName);
+ }
+
+ return request.result;
+}
+
+export async function clearStoragesForOrigin(principal) {
+ const request = Services.qms.clearStoragesForPrincipal(principal);
+
+ await new Promise(function (resolve) {
+ request.callback = function () {
+ resolve();
+ };
+ });
+
+ if (request.resultCode != Cr.NS_OK) {
+ throw new RequestError(request.resultCode, request.resultName);
+ }
+
+ return request.result;
+}
+
+export async function resetStorage() {
+ const request = Services.qms.reset();
+
+ await new Promise(function (resolve) {
+ request.callback = function () {
+ resolve();
+ };
+ });
+
+ if (request.resultCode != Cr.NS_OK) {
+ throw new RequestError(request.resultCode, request.resultName);
+ }
+
+ return request.result;
+}
diff --git a/dom/quota/test/modules/system/Utils.sys.mjs b/dom/quota/test/modules/system/Utils.sys.mjs
new file mode 100644
index 0000000000..8c5430aa06
--- /dev/null
+++ b/dom/quota/test/modules/system/Utils.sys.mjs
@@ -0,0 +1,38 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import {
+ getUsageForOrigin,
+ resetStorage,
+} from "resource://testing-common/dom/quota/test/modules/StorageUtils.sys.mjs";
+
+export const Utils = {
+ async getCachedOriginUsage() {
+ const principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
+ Ci.nsIPrincipal
+ );
+ const result = await getUsageForOrigin(principal, true);
+ return result.usage;
+ },
+
+ async shrinkStorageSize(size) {
+ Services.prefs.setIntPref(
+ "dom.quotaManager.temporaryStorage.fixedLimit",
+ size
+ );
+
+ const result = await resetStorage();
+ return result;
+ },
+
+ async restoreStorageSize() {
+ Services.prefs.clearUserPref(
+ "dom.quotaManager.temporaryStorage.fixedLimit"
+ );
+
+ const result = await resetStorage();
+ return result;
+ },
+};
diff --git a/dom/quota/test/modules/system/UtilsParent.sys.mjs b/dom/quota/test/modules/system/UtilsParent.sys.mjs
new file mode 100644
index 0000000000..41ca7e2940
--- /dev/null
+++ b/dom/quota/test/modules/system/UtilsParent.sys.mjs
@@ -0,0 +1,32 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import { Utils } from "resource://testing-common/dom/quota/test/modules/Utils.sys.mjs";
+
+export const UtilsParent = {
+ async OnMessageReceived(worker, msg) {
+ switch (msg.op) {
+ case "getCachedOriginUsage": {
+ const result = await Utils.getCachedOriginUsage();
+ worker.postMessage(result);
+ break;
+ }
+ case "shrinkStorageSize": {
+ const result = await Utils.shrinkStorageSize(msg.size);
+ worker.postMessage(result);
+ break;
+ }
+
+ case "restoreStorageSize": {
+ const result = await Utils.restoreStorageSize();
+ worker.postMessage(result);
+ break;
+ }
+
+ default:
+ throw new Error(`Unknown op ${msg.op}`);
+ }
+ },
+};
diff --git a/dom/quota/test/modules/system/WorkerDriver.sys.mjs b/dom/quota/test/modules/system/WorkerDriver.sys.mjs
new file mode 100644
index 0000000000..60e6790760
--- /dev/null
+++ b/dom/quota/test/modules/system/WorkerDriver.sys.mjs
@@ -0,0 +1,68 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+export async function runTestInWorker(script, base, listener) {
+ return new Promise(function (resolve) {
+ const globalHeadUrl = new URL(
+ "resource://testing-common/dom/quota/test/modules/worker/head.js"
+ );
+
+ let modules = {};
+
+ const worker = new Worker(globalHeadUrl.href);
+
+ worker.onmessage = async function (event) {
+ const data = event.data;
+ const moduleName = data.moduleName;
+ const objectName = data.objectName;
+
+ if (moduleName && objectName) {
+ if (!modules[moduleName]) {
+ modules[moduleName] = ChromeUtils.importESModule(
+ "resource://testing-common/dom/quota/test/modules/" +
+ moduleName +
+ ".sys.mjs"
+ );
+ }
+ await modules[moduleName][objectName].OnMessageReceived(worker, data);
+ return;
+ }
+
+ switch (data.op) {
+ case "ok":
+ listener.onOk(data.value, data.message);
+ break;
+
+ case "is":
+ listener.onIs(data.a, data.b, data.message);
+ break;
+
+ case "info":
+ listener.onInfo(data.message);
+ break;
+
+ case "finish":
+ resolve();
+ break;
+
+ case "failure":
+ listener.onOk(false, "Worker had a failure: " + data.message);
+ resolve();
+ break;
+ }
+ };
+
+ worker.onerror = function (event) {
+ listener.onOk(false, "Worker had an error: " + event.data);
+ resolve();
+ };
+
+ const scriptUrl = new URL(script, base);
+
+ const localHeadUrl = new URL("head.js", scriptUrl);
+
+ worker.postMessage([localHeadUrl.href, scriptUrl.href]);
+ });
+}
diff --git a/dom/quota/test/modules/system/worker/.eslintrc.js b/dom/quota/test/modules/system/worker/.eslintrc.js
new file mode 100644
index 0000000000..505e079c57
--- /dev/null
+++ b/dom/quota/test/modules/system/worker/.eslintrc.js
@@ -0,0 +1,21 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+module.exports = {
+ env: {
+ worker: true,
+ },
+
+ overrides: [
+ {
+ files: ["head.js"],
+ env: {
+ worker: true,
+ },
+ },
+ ],
+};
diff --git a/dom/quota/test/modules/system/worker/Assert.js b/dom/quota/test/modules/system/worker/Assert.js
new file mode 100644
index 0000000000..7c7e2683ea
--- /dev/null
+++ b/dom/quota/test/modules/system/worker/Assert.js
@@ -0,0 +1,22 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const Assert = {
+ ok(value, message) {
+ postMessage({
+ op: "ok",
+ value: !!value,
+ message,
+ });
+ },
+ equal(a, b, message) {
+ postMessage({
+ op: "is",
+ a,
+ b,
+ message,
+ });
+ },
+};
diff --git a/dom/quota/test/modules/system/worker/ModuleLoader.js b/dom/quota/test/modules/system/worker/ModuleLoader.js
new file mode 100644
index 0000000000..b79f3ff5b9
--- /dev/null
+++ b/dom/quota/test/modules/system/worker/ModuleLoader.js
@@ -0,0 +1,52 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function ModuleLoader(base, depth, proto) {
+ const modules = {};
+
+ const require = async function (id) {
+ if (modules[id]) {
+ return modules[id].exported_symbols;
+ }
+
+ const url = new URL(depth + id, base);
+
+ const module = Object.create(null, {
+ exported_symbols: {
+ configurable: false,
+ enumerable: true,
+ value: Object.create(null),
+ writable: true,
+ },
+ });
+
+ modules[id] = module;
+
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", url.href, false);
+ xhr.responseType = "text";
+ xhr.send();
+
+ let source = xhr.responseText;
+
+ let code = new Function(
+ "require_module",
+ "exported_symbols",
+ `eval(arguments[2] + "\\n//# sourceURL=" + arguments[3] + "\\n")`
+ );
+ code(require, module.exported_symbols, source, url.href);
+
+ return module.exported_symbols;
+ };
+
+ const returnObj = {
+ require: {
+ enumerable: true,
+ value: require,
+ },
+ };
+
+ return Object.create(null, returnObj);
+}
diff --git a/dom/quota/test/modules/system/worker/Utils.js b/dom/quota/test/modules/system/worker/Utils.js
new file mode 100644
index 0000000000..b8e6224bf4
--- /dev/null
+++ b/dom/quota/test/modules/system/worker/Utils.js
@@ -0,0 +1,41 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+let UtilsChild;
+
+async function ensureUtilsChild() {
+ if (UtilsChild) {
+ return;
+ }
+
+ const { UtilsChild: importedUtilsChild } = await import(
+ "/dom/quota/test/modules/worker/UtilsChild.mjs"
+ );
+
+ UtilsChild = importedUtilsChild;
+}
+
+const Utils = {
+ async getCachedOriginUsage() {
+ await ensureUtilsChild();
+
+ const result = await UtilsChild.getCachedOriginUsage();
+ return result;
+ },
+
+ async shrinkStorageSize(size) {
+ await ensureUtilsChild();
+
+ const result = await UtilsChild.shrinkStorageSize(size);
+ return result;
+ },
+
+ async restoreStorageSize() {
+ await ensureUtilsChild();
+
+ const result = await UtilsChild.restoreStorageSize();
+ return result;
+ },
+};
diff --git a/dom/quota/test/modules/system/worker/UtilsChild.mjs b/dom/quota/test/modules/system/worker/UtilsChild.mjs
new file mode 100644
index 0000000000..d3b5455a59
--- /dev/null
+++ b/dom/quota/test/modules/system/worker/UtilsChild.mjs
@@ -0,0 +1,52 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function _sendMessage(messageBody) {
+ const messageHeader = {
+ moduleName: "UtilsParent",
+ objectName: "UtilsParent",
+ };
+
+ const message = { ...messageHeader, ...messageBody };
+
+ postMessage(message);
+}
+
+function _recvMessage() {
+ return new Promise(function (resolve) {
+ addEventListener("message", async function onMessage(event) {
+ removeEventListener("message", onMessage);
+ const data = event.data;
+ resolve(data);
+ });
+ });
+}
+
+export const UtilsChild = {
+ async getCachedOriginUsage() {
+ _sendMessage({
+ op: "getCachedOriginUsage",
+ });
+
+ return _recvMessage();
+ },
+
+ async shrinkStorageSize(size) {
+ _sendMessage({
+ op: "shrinkStorageSize",
+ size,
+ });
+
+ return _recvMessage();
+ },
+
+ async restoreStorageSize() {
+ _sendMessage({
+ op: "restoreStorageSize",
+ });
+
+ return _recvMessage();
+ },
+};
diff --git a/dom/quota/test/modules/system/worker/head.js b/dom/quota/test/modules/system/worker/head.js
new file mode 100644
index 0000000000..c415e0c56b
--- /dev/null
+++ b/dom/quota/test/modules/system/worker/head.js
@@ -0,0 +1,56 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// eslint-disable-next-line mozilla/no-define-cc-etc
+const Cr = {
+ NS_ERROR_NOT_IMPLEMENTED: 2147500033,
+};
+
+function add_task(func) {
+ if (!add_task.tasks) {
+ add_task.tasks = [];
+ add_task.index = 0;
+ }
+
+ add_task.tasks.push(func);
+}
+
+addEventListener("message", async function onMessage(event) {
+ function info(message) {
+ postMessage({ op: "info", message });
+ }
+
+ function executeSoon(callback) {
+ const channel = new MessageChannel();
+ channel.port1.postMessage("");
+ channel.port2.onmessage = function () {
+ callback();
+ };
+ }
+
+ function runNextTest() {
+ if (add_task.index < add_task.tasks.length) {
+ const task = add_task.tasks[add_task.index++];
+ info("add_task | Entering test " + task.name);
+ task()
+ .then(function () {
+ executeSoon(runNextTest);
+ info("add_task | Leaving test " + task.name);
+ })
+ .catch(function (ex) {
+ postMessage({ op: "failure", message: "" + ex });
+ });
+ } else {
+ postMessage({ op: "finish" });
+ }
+ }
+
+ removeEventListener("message", onMessage);
+
+ const data = event.data;
+ importScripts(...data);
+
+ executeSoon(runNextTest);
+});