Bug 1750933 - Add testing infrastructure for OPFS; r=dom-storage-reviewers,jari

Differential Revision: https://phabricator.services.mozilla.com/D136317
This commit is contained in:
Jan Varga 2022-05-03 11:38:15 +00:00
Родитель a7af2dc794
Коммит 2b350c618a
29 изменённых файлов: 787 добавлений и 1 удалений

Просмотреть файл

@ -330,7 +330,10 @@ module.exports = {
"dom/payments/**",
"dom/performance/**",
"dom/permission/**",
"dom/quota/**",
"dom/quota/test/browser/**",
"dom/quota/test/common/**",
"dom/quota/test/mochitest/**",
"dom/quota/test/xpcshell/**",
"dom/security/test/cors/**",
"dom/security/test/csp/**",
"dom/security/test/mixedcontentblocker/**",

Просмотреть файл

@ -4,6 +4,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_DIRS += ["test"]
EXPORTS.mozilla.dom += [
"FileSystemDirectoryHandle.h",
"FileSystemDirectoryIterator.h",

Просмотреть файл

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
module.exports = {
globals: {
Assert: true,
exported_symbols: true,
require_module: true,
},
};

Просмотреть файл

@ -0,0 +1,9 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const nsresult = {
NS_ERROR_NOT_IMPLEMENTED: Cr.NS_ERROR_NOT_IMPLEMENTED,
};
exported_symbols.nsresult = nsresult;

Просмотреть файл

@ -0,0 +1,21 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function test1() {
const { nsresult } = await require_module("dom/fs/test/common/nsresult.js");
try {
await navigator.storage.getDirectory();
Assert.ok(false, "Should have thrown");
} catch (e) {
Assert.ok(true, "Should have thrown");
Assert.ok(
e.result === nsresult.NS_ERROR_NOT_IMPLEMENTED,
"Threw right result code"
);
}
}
exported_symbols.test1 = test1;

Просмотреть файл

@ -0,0 +1,51 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function require_module(id) {
if (!require_module.moduleLoader) {
const { ModuleLoader } = await import(
"/tests/dom/quota/test/modules/ModuleLoader.js"
);
const base = window.location.href;
const depth = "../../../../";
const { Assert } = await import("/tests/dom/quota/test/modules/Assert.js");
const proto = {
Assert,
Cr: SpecialPowers.Cr,
navigator,
};
require_module.moduleLoader = new ModuleLoader(base, depth, proto);
}
return require_module.moduleLoader.require(id);
}
async function run_test_in_worker(script) {
const { runTestInWorker } = await import(
"/tests/dom/quota/test/modules/WorkerDriver.js"
);
await runTestInWorker(script);
}
// XXX It would be nice if we could call add_setup here (xpcshell-test and
// browser-test support it.
add_task(async function() {
const { setStoragePrefs, clearStoragesForOrigin } = await import(
"/tests/dom/quota/test/modules/StorageUtils.js"
);
const optionalPrefsToSet = [["dom.fs.enabled", true]];
await setStoragePrefs(optionalPrefsToSet);
SimpleTest.registerCleanupFunction(async function() {
await clearStoragesForOrigin(SpecialPowers.wrap(document).nodePrincipal);
});
});

Просмотреть файл

@ -0,0 +1,12 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
support-files =
head.js
[test_basics.html]
scheme=https
[test_basics_worker.html]
scheme=https

Просмотреть файл

@ -0,0 +1,24 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>File System Test</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="head.js"></script>
<script type="text/javascript">
add_task(async function test_1() {
const { test1 } = await require_module("dom/fs/test/common/test_basics.js");
await test1();
});
</script>
</head>
<body></body>
</html>

Просмотреть файл

@ -0,0 +1,22 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>File System Test</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="head.js"></script>
<script type="text/javascript">
add_task(async function worker() {
await run_test_in_worker("worker/test_basics_worker.js");
});
</script>
</head>
<body></body>
</html>

Просмотреть файл

@ -0,0 +1,12 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
module.exports = {
env: {
worker: true,
},
};

Просмотреть файл

@ -0,0 +1,20 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function require_module(id) {
if (!require_module.moduleLoader) {
importScripts("/tests/dom/quota/test/modules/worker/ModuleLoader.js");
const base = location.href;
const depth = "../../../../../";
importScripts("/tests/dom/quota/test/modules/worker/Assert.js");
require_module.moduleLoader = new globalThis.ModuleLoader(base, depth);
}
return require_module.moduleLoader.require(id);
}

Просмотреть файл

@ -0,0 +1,10 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
add_task(async function test_1() {
const { test1 } = await require_module("dom/fs/test/common/test_basics.js");
await test1();
});

28
dom/fs/test/moz.build Normal file
Просмотреть файл

@ -0,0 +1,28 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOCHITEST_MANIFESTS += [
"mochitest/mochitest.ini",
]
XPCSHELL_TESTS_MANIFESTS += [
"xpcshell/xpcshell.ini",
]
TEST_HARNESS_FILES.testing.mochitest.tests.dom.fs.test.common += [
"common/nsresult.js",
"common/test_basics.js",
]
TEST_HARNESS_FILES.testing.mochitest.tests.dom.fs.test.mochitest.worker += [
"mochitest/worker/head.js",
"mochitest/worker/test_basics_worker.js",
]
TEST_HARNESS_FILES.xpcshell.dom.fs.test.common += [
"common/nsresult.js",
"common/test_basics.js",
]

Просмотреть файл

@ -0,0 +1,60 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
async function require_module(id) {
if (!require_module.moduleLoader) {
const { ModuleLoader } = ChromeUtils.import(
"resource://testing-common/dom/quota/test/modules/ModuleLoader.jsm"
);
const base = Services.io.newFileURI(do_get_file("")).spec;
const depth = "../../../../";
Cu.importGlobalProperties(["storage"]);
const proto = {
Assert,
Cr,
navigator: {
storage,
},
};
require_module.moduleLoader = new ModuleLoader(base, depth, proto);
}
return require_module.moduleLoader.require(id);
}
add_setup(async function() {
const {
setStoragePrefs,
clearStoragePrefs,
clearStoragesForOrigin,
} = ChromeUtils.import(
"resource://testing-common/dom/quota/test/modules/StorageUtils.jsm"
);
const optionalPrefsToSet = [["dom.fs.enabled", true]];
setStoragePrefs(optionalPrefsToSet);
registerCleanupFunction(async function() {
const principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
Ci.nsIPrincipal
);
await clearStoragesForOrigin(principal);
const optionalPrefsToClear = ["dom.fs.enabled"];
clearStoragePrefs(optionalPrefsToClear);
});
do_get_profile();
});

Просмотреть файл

@ -0,0 +1,10 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
add_task(async function test_1() {
const { test1 } = await require_module("dom/fs/test/common/test_basics.js");
await test1();
});

Просмотреть файл

@ -0,0 +1,8 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
head = head.js
[test_basics.js]

Просмотреть файл

@ -8526,6 +8526,15 @@ nsresult QuotaClient::AboutToClearOrigins(
return NS_OK;
}
// There can be no data for the system principal in the archive or the shadow
// database. This early return silences potential warnings caused by failed
// `CreateAerchivedOriginScope` because it calls `GenerateOriginKey2` which
// doesn't support the system principal.
if (aOriginScope.IsOrigin() &&
aOriginScope.GetOrigin() == QuotaManager::GetOriginForChrome()) {
return NS_OK;
}
const bool shadowWrites = gShadowWrites;
QM_TRY_INSPECT(const auto& archivedOriginScope,

Просмотреть файл

@ -0,0 +1,24 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
module.exports = {
extends: ["plugin:mozilla/mochitest-test"],
overrides: [
{
files: [
"Assert.js",
"ModuleLoader.js",
"StorageUtils.js",
"WorkerDriver.js",
],
parserOptions: {
sourceType: "module",
},
},
],
};

Просмотреть файл

@ -0,0 +1,11 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Just a wrapper around SimpleTest related functions for now.
export const Assert = {
ok(value, message) {
ok(value, message);
},
};

Просмотреть файл

@ -0,0 +1,61 @@
/**
* 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 = 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);
}

Просмотреть файл

@ -0,0 +1,48 @@
/**
* 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 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 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;
}

Просмотреть файл

@ -0,0 +1,44 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
export async function runTestInWorker(script) {
return new Promise(function(resolve) {
const globalHeadUrl = new URL(
"/tests/dom/quota/test/modules/worker/head.js",
window.location.href
);
const worker = new Worker(globalHeadUrl.href);
worker.onmessage = function(event) {
const data = event.data;
switch (data.op) {
case "ok":
ok(data.value, data.message);
break;
case "info":
info(data.message);
break;
case "finish":
resolve();
break;
}
};
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
resolve();
};
const scriptUrl = new URL(script, window.location.href);
const localHeadUrl = new URL("head.js", scriptUrl);
worker.postMessage([localHeadUrl.href, scriptUrl.href]);
});
}

Просмотреть файл

@ -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: ["Assert.js", "ModuleLoader.js"],
parserOptions: {
sourceType: "script",
},
},
],
};

Просмотреть файл

@ -0,0 +1,14 @@
/**
* 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,
});
},
};

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -0,0 +1,36 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const Cr = {
NS_ERROR_NOT_IMPLEMENTED: 2147500033,
};
function add_task(func) {
if (!add_task.tasks) {
add_task.tasks = [];
}
add_task.tasks.push(func);
}
addEventListener("message", async function onMessage(event) {
function info(message) {
postMessage({ op: "info", message });
}
removeEventListener("message", onMessage);
const data = event.data;
importScripts(...data);
let task;
while ((task = add_task.tasks.shift())) {
info("add_task | Entering test " + task.name);
await task();
info("add_task | Leaving test " + task.name);
}
postMessage({ op: "finish" });
});

Просмотреть файл

@ -0,0 +1,67 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
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);
}
const EXPORTED_SYMBOLS = ["ModuleLoader"];

Просмотреть файл

@ -0,0 +1,76 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class RequestError extends Error {
constructor(resultCode, resultName) {
super(`Request failed (code: ${resultCode}, name: ${resultName})`);
this.name = "RequestError";
this.resultCode = resultCode;
this.resultName = resultName;
}
}
function setStoragePrefs(optionalPrefsToSet) {
const prefsToSet = [
// Not needed right now, but might be needed in future.
// ["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]);
}
}
function clearStoragePrefs(optionalPrefsToClear) {
const prefsToClear = [
"dom.quotaManager.testing",
"dom.simpleDB.enabled",
"dom.storageManager.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);
}
}
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;
}
const EXPORTED_SYMBOLS = [
"setStoragePrefs",
"clearStoragePrefs",
"clearStoragesForOrigin",
];

Просмотреть файл

@ -37,6 +37,19 @@ TEST_HARNESS_FILES.testing.mochitest.tests.dom.quota.test.common += [
"common/test_storage_manager_persisted.js",
]
TEST_HARNESS_FILES.testing.mochitest.tests.dom.quota.test.modules += [
"modules/content/Assert.js",
"modules/content/ModuleLoader.js",
"modules/content/StorageUtils.js",
"modules/content/WorkerDriver.js",
]
TEST_HARNESS_FILES.testing.mochitest.tests.dom.quota.test.modules.worker += [
"modules/content/worker/Assert.js",
"modules/content/worker/head.js",
"modules/content/worker/ModuleLoader.js",
]
TEST_HARNESS_FILES.xpcshell.dom.quota.test.common += [
"common/file.js",
"common/global.js",
@ -49,3 +62,8 @@ TEST_HARNESS_FILES.xpcshell.dom.quota.test.xpcshell.common += [
"xpcshell/common/head.js",
"xpcshell/common/utils.js",
]
TESTING_JS_MODULES.dom.quota.test.modules += [
"modules/system/ModuleLoader.jsm",
"modules/system/StorageUtils.jsm",
]