343 lines
8 KiB
JavaScript
343 lines
8 KiB
JavaScript
/**
|
|
* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
|
|
// Tests are expected to define testSteps.
|
|
/* globals testSteps */
|
|
|
|
const NS_ERROR_DOM_QUOTA_EXCEEDED_ERR = 22;
|
|
|
|
function is(a, b, msg) {
|
|
Assert.equal(a, b, msg);
|
|
}
|
|
|
|
function ok(cond, msg) {
|
|
Assert.ok(!!cond, msg);
|
|
}
|
|
|
|
add_setup(function () {
|
|
do_get_profile();
|
|
|
|
const { ProcessUtils } = ChromeUtils.importESModule(
|
|
"resource://testing-common/dom/quota/test/modules/ProcessUtils.sys.mjs"
|
|
);
|
|
|
|
if (ProcessUtils.isInParentProcess()) {
|
|
enableTesting();
|
|
|
|
registerCleanupFunction(resetTesting);
|
|
}
|
|
});
|
|
|
|
function returnToEventLoop() {
|
|
return new Promise(function (resolve) {
|
|
executeSoon(resolve);
|
|
});
|
|
}
|
|
|
|
function enableTesting() {
|
|
Services.prefs.setBoolPref("dom.simpleDB.enabled", true);
|
|
Services.prefs.setBoolPref("dom.storage.testing", true);
|
|
|
|
// xpcshell globals don't have associated clients in the Clients API sense, so
|
|
// we need to disable client validation so that the unit tests are allowed to
|
|
// use LocalStorage.
|
|
Services.prefs.setBoolPref("dom.storage.client_validation", false);
|
|
|
|
Services.prefs.setBoolPref("dom.quotaManager.testing", true);
|
|
}
|
|
|
|
function resetTesting() {
|
|
Services.prefs.clearUserPref("dom.quotaManager.testing");
|
|
Services.prefs.clearUserPref("dom.storage.client_validation");
|
|
Services.prefs.clearUserPref("dom.storage.testing");
|
|
Services.prefs.clearUserPref("dom.simpleDB.enabled");
|
|
}
|
|
|
|
function setGlobalLimit(globalLimit) {
|
|
Services.prefs.setIntPref(
|
|
"dom.quotaManager.temporaryStorage.fixedLimit",
|
|
globalLimit
|
|
);
|
|
}
|
|
|
|
function resetGlobalLimit() {
|
|
Services.prefs.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
|
|
}
|
|
|
|
function setOriginLimit(originLimit) {
|
|
Services.prefs.setIntPref("dom.storage.default_quota", originLimit);
|
|
}
|
|
|
|
function resetOriginLimit() {
|
|
Services.prefs.clearUserPref("dom.storage.default_quota");
|
|
}
|
|
|
|
function setTimeout(callback, timeout) {
|
|
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
timer.initWithCallback(
|
|
{
|
|
notify() {
|
|
callback();
|
|
},
|
|
},
|
|
timeout,
|
|
Ci.nsITimer.TYPE_ONE_SHOT
|
|
);
|
|
|
|
return timer;
|
|
}
|
|
|
|
function initStorage() {
|
|
return Services.qms.init();
|
|
}
|
|
|
|
function initTemporaryStorage() {
|
|
return Services.qms.initTemporaryStorage();
|
|
}
|
|
|
|
function initPersistentOrigin(principal) {
|
|
return Services.qms.initializePersistentOrigin(principal);
|
|
}
|
|
|
|
function initTemporaryOrigin(
|
|
persistence,
|
|
principal,
|
|
createIfNonExistent = true
|
|
) {
|
|
return Services.qms.initializeTemporaryOrigin(
|
|
persistence,
|
|
principal,
|
|
createIfNonExistent
|
|
);
|
|
}
|
|
|
|
function getOriginUsage(principal) {
|
|
let request = Services.qms.getUsageForPrincipal(principal, function () {});
|
|
|
|
return request;
|
|
}
|
|
|
|
function getCachedOriginUsage(principal) {
|
|
let request = Services.qms.getCachedUsageForPrincipal(
|
|
principal,
|
|
function () {}
|
|
);
|
|
|
|
return request;
|
|
}
|
|
|
|
function clear() {
|
|
let request = Services.qms.clear();
|
|
|
|
return request;
|
|
}
|
|
|
|
function clearOriginsByPattern(pattern) {
|
|
let request = Services.qms.clearStoragesForOriginAttributesPattern(pattern);
|
|
|
|
return request;
|
|
}
|
|
|
|
function clearOriginsByPrefix(principal, persistence) {
|
|
let request = Services.qms.clearStoragesForOriginPrefix(
|
|
principal,
|
|
persistence
|
|
);
|
|
|
|
return request;
|
|
}
|
|
|
|
function clearOrigin(principal, persistence) {
|
|
let request = Services.qms.clearStoragesForPrincipal(principal, persistence);
|
|
|
|
return request;
|
|
}
|
|
|
|
function reset() {
|
|
let request = Services.qms.reset();
|
|
|
|
return request;
|
|
}
|
|
|
|
function resetClient(principal) {
|
|
let request = Services.qms.resetStoragesForClient(principal, "ls", "default");
|
|
|
|
return request;
|
|
}
|
|
|
|
function installPackage(packageName) {
|
|
let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
|
|
|
|
let packageFile = currentDir.clone();
|
|
packageFile.append(packageName + ".zip");
|
|
|
|
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
|
|
Ci.nsIZipReader
|
|
);
|
|
zipReader.open(packageFile);
|
|
|
|
let entryNames = [];
|
|
let entries = zipReader.findEntries(null);
|
|
while (entries.hasMore()) {
|
|
let entry = entries.getNext();
|
|
entryNames.push(entry);
|
|
}
|
|
entryNames.sort();
|
|
|
|
for (let entryName of entryNames) {
|
|
let zipentry = zipReader.getEntry(entryName);
|
|
|
|
let file = getRelativeFile(entryName);
|
|
|
|
if (zipentry.isDirectory) {
|
|
file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
|
|
} else {
|
|
let istream = zipReader.getInputStream(entryName);
|
|
|
|
var ostream = Cc[
|
|
"@mozilla.org/network/file-output-stream;1"
|
|
].createInstance(Ci.nsIFileOutputStream);
|
|
ostream.init(file, -1, parseInt("0644", 8), 0);
|
|
|
|
let bostream = Cc[
|
|
"@mozilla.org/network/buffered-output-stream;1"
|
|
].createInstance(Ci.nsIBufferedOutputStream);
|
|
bostream.init(ostream, 32768);
|
|
|
|
bostream.writeFrom(istream, istream.available());
|
|
|
|
istream.close();
|
|
bostream.close();
|
|
}
|
|
}
|
|
|
|
zipReader.close();
|
|
}
|
|
|
|
function getProfileDir() {
|
|
return Services.dirsvc.get("ProfD", Ci.nsIFile);
|
|
}
|
|
|
|
// Given a "/"-delimited path relative to the profile directory,
|
|
// return an nsIFile representing the path. This does not test
|
|
// for the existence of the file or parent directories.
|
|
// It is safe even on Windows where the directory separator is not "/",
|
|
// but make sure you're not passing in a "\"-delimited path.
|
|
function getRelativeFile(relativePath) {
|
|
let profileDir = getProfileDir();
|
|
|
|
let file = profileDir.clone();
|
|
relativePath.split("/").forEach(function (component) {
|
|
file.append(component);
|
|
});
|
|
|
|
return file;
|
|
}
|
|
|
|
function repeatChar(count, ch) {
|
|
if (count == 0) {
|
|
return "";
|
|
}
|
|
|
|
let result = ch;
|
|
let count2 = count / 2;
|
|
|
|
// Double the input until it is long enough.
|
|
while (result.length <= count2) {
|
|
result += result;
|
|
}
|
|
|
|
// Use substring to hit the precise length target without using extra memory.
|
|
return result + result.substring(0, count - result.length);
|
|
}
|
|
|
|
function getPrincipal(url, attrs) {
|
|
let uri = Services.io.newURI(url);
|
|
if (!attrs) {
|
|
attrs = {};
|
|
}
|
|
return Services.scriptSecurityManager.createContentPrincipal(uri, attrs);
|
|
}
|
|
|
|
function getCurrentPrincipal() {
|
|
return Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
|
|
}
|
|
|
|
function getDefaultPrincipal() {
|
|
return getPrincipal("http://example.com");
|
|
}
|
|
|
|
function getSimpleDatabase(principal, persistence) {
|
|
let connection = Cc["@mozilla.org/dom/sdb-connection;1"].createInstance(
|
|
Ci.nsISDBConnection
|
|
);
|
|
|
|
if (!principal) {
|
|
principal = getDefaultPrincipal();
|
|
}
|
|
|
|
connection.init(principal, persistence);
|
|
|
|
return connection;
|
|
}
|
|
|
|
function getLocalStorage(principal) {
|
|
if (!principal) {
|
|
principal = getDefaultPrincipal();
|
|
}
|
|
|
|
return Services.domStorageManager.createStorage(
|
|
null,
|
|
principal,
|
|
principal,
|
|
""
|
|
);
|
|
}
|
|
|
|
class RequestError extends Error {
|
|
constructor(resultCode, resultName) {
|
|
super(`Request failed (code: ${resultCode}, name: ${resultName})`);
|
|
this.name = "RequestError";
|
|
this.resultCode = resultCode;
|
|
this.resultName = resultName;
|
|
}
|
|
}
|
|
|
|
async function requestFinished(request) {
|
|
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;
|
|
}
|
|
|
|
function loadSubscript(path) {
|
|
let file = do_get_file(path, false);
|
|
let uri = Services.io.newFileURI(file);
|
|
Services.scriptloader.loadSubScript(uri.spec);
|
|
}
|
|
|
|
async function readUsageFromUsageFile(usageFile) {
|
|
let file = await File.createFromNsIFile(usageFile);
|
|
|
|
let buffer = await new Promise(resolve => {
|
|
let reader = new FileReader();
|
|
reader.onloadend = () => resolve(reader.result);
|
|
reader.readAsArrayBuffer(file);
|
|
});
|
|
|
|
// Manually getting the lower 32-bits because of the lack of support for
|
|
// 64-bit values currently from DataView/JS (other than the BigInt support
|
|
// that's currently behind a flag).
|
|
let view = new DataView(buffer, 8, 4);
|
|
return view.getUint32();
|
|
}
|