summaryrefslogtreecommitdiffstats
path: root/dom/quota/test/common
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/test/common')
-rw-r--r--dom/quota/test/common/browser.js34
-rw-r--r--dom/quota/test/common/content.js62
-rw-r--r--dom/quota/test/common/file.js45
-rw-r--r--dom/quota/test/common/global.js47
-rw-r--r--dom/quota/test/common/mochitest.js19
-rw-r--r--dom/quota/test/common/nestedtest.js6
-rw-r--r--dom/quota/test/common/system.js74
-rw-r--r--dom/quota/test/common/test_simpledb.js50
-rw-r--r--dom/quota/test/common/test_storage_manager_persist_allow.js30
-rw-r--r--dom/quota/test/common/test_storage_manager_persist_deny.js34
-rw-r--r--dom/quota/test/common/test_storage_manager_persisted.js13
-rw-r--r--dom/quota/test/common/xpcshell.js91
12 files changed, 505 insertions, 0 deletions
diff --git a/dom/quota/test/common/browser.js b/dom/quota/test/common/browser.js
new file mode 100644
index 0000000000..b9903184df
--- /dev/null
+++ b/dom/quota/test/common/browser.js
@@ -0,0 +1,34 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+loadScript("dom/quota/test/common/system.js");
+
+function addTest(testFunction) {
+ const taskFunction = async function () {
+ await enableStorageTesting();
+
+ await testFunction();
+ };
+
+ Object.defineProperty(taskFunction, "name", {
+ value: testFunction.name,
+ writable: false,
+ });
+
+ add_task(taskFunction);
+}
+
+async function enableStorageTesting() {
+ const prefsToSet = [
+ ["dom.quotaManager.testing", true],
+ ["dom.storageManager.enabled", true],
+ ["dom.simpleDB.enabled", true],
+ ];
+ if (Services.appinfo.OS === "WINNT") {
+ prefsToSet.push(["dom.quotaManager.useDOSDevicePathSyntax", true]);
+ }
+
+ await SpecialPowers.pushPrefEnv({ set: prefsToSet });
+}
diff --git a/dom/quota/test/common/content.js b/dom/quota/test/common/content.js
new file mode 100644
index 0000000000..51c9d3d68d
--- /dev/null
+++ b/dom/quota/test/common/content.js
@@ -0,0 +1,62 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const NS_ERROR_STORAGE_BUSY = SpecialPowers.Cr.NS_ERROR_STORAGE_BUSY;
+
+loadScript("dom/quota/test/common/global.js");
+
+function clearAllDatabases(callback) {
+ let qms = SpecialPowers.Services.qms;
+ let principal = SpecialPowers.wrap(document).nodePrincipal;
+ let request = qms.clearStoragesForPrincipal(principal);
+ let cb = SpecialPowers.wrapCallback(callback);
+ request.callback = cb;
+ return request;
+}
+
+// SimpleDB connections and SpecialPowers wrapping:
+//
+// SpecialPowers provides a SpecialPowersHandler Proxy mechanism that lets our
+// content-privileged code borrow its chrome-privileged principal to access
+// things we shouldn't be able to access. The proxies wrap their returned
+// values, so once we have something wrapped we can rely on returned objects
+// being wrapped as well. The proxy will also automatically unwrap wrapped
+// arguments we pass in. However, we need to invoke wrapCallback on callback
+// functions so that the arguments they receive will be wrapped because the
+// proxy does not automatically wrap content-privileged functions.
+//
+// Our use of (wrapped) SpecialPowers.Cc results in getSimpleDatabase()
+// producing a wrapped nsISDBConnection instance. The nsISDBResult instances
+// exposed on the (wrapped) nsISDBRequest are also wrapped.
+// In particular, the wrapper takes responsibility for automatically cloning
+// the ArrayBuffer returned by nsISDBResult.getAsArrayBuffer into the content
+// compartment (rather than wrapping it) so that constructing a Uint8Array
+// from it will succeed.
+
+function getSimpleDatabase() {
+ let connection = SpecialPowers.Cc[
+ "@mozilla.org/dom/sdb-connection;1"
+ ].createInstance(SpecialPowers.Ci.nsISDBConnection);
+
+ let principal = SpecialPowers.wrap(document).nodePrincipal;
+
+ connection.init(principal);
+
+ return connection;
+}
+
+async function requestFinished(request) {
+ 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/common/file.js b/dom/quota/test/common/file.js
new file mode 100644
index 0000000000..55e2e189fb
--- /dev/null
+++ b/dom/quota/test/common/file.js
@@ -0,0 +1,45 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function getBuffer(size) {
+ let buffer = new ArrayBuffer(size);
+ is(buffer.byteLength, size, "Correct byte length");
+ return buffer;
+}
+
+// May be called for any size, but you should call getBuffer() if you know
+// that size is big and that randomness is not necessary because it is
+// noticeably faster.
+function getRandomBuffer(size) {
+ let buffer = getBuffer(size);
+ let view = new Uint8Array(buffer);
+ for (let i = 0; i < size; i++) {
+ view[i] = parseInt(Math.random() * 255);
+ }
+ return buffer;
+}
+
+function compareBuffers(buffer1, buffer2) {
+ if (buffer1.byteLength != buffer2.byteLength) {
+ return false;
+ }
+
+ let view1 = buffer1 instanceof Uint8Array ? buffer1 : new Uint8Array(buffer1);
+ let view2 = buffer2 instanceof Uint8Array ? buffer2 : new Uint8Array(buffer2);
+ for (let i = 0; i < buffer1.byteLength; i++) {
+ if (view1[i] != view2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function getBlob(type, object) {
+ return new Blob([object], { type });
+}
+
+function getNullBlob(size) {
+ return getBlob("binary/null", getBuffer(size));
+}
diff --git a/dom/quota/test/common/global.js b/dom/quota/test/common/global.js
new file mode 100644
index 0000000000..cc7d9d97a2
--- /dev/null
+++ b/dom/quota/test/common/global.js
@@ -0,0 +1,47 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const INT64_MIN = -0x8000000000000000n;
+
+class RequestError extends Error {
+ constructor(resultCode, resultName) {
+ super(`Request failed (code: ${resultCode}, name: ${resultName})`);
+ this.name = "RequestError";
+ this.resultCode = resultCode;
+ this.resultName = resultName;
+ }
+}
+
+function openDBRequestUpgradeNeeded(request) {
+ return new Promise(function (resolve, reject) {
+ request.onerror = function (event) {
+ ok(false, "indexedDB error, '" + event.target.error.name + "'");
+ reject(event);
+ };
+ request.onupgradeneeded = function (event) {
+ resolve(event);
+ };
+ request.onsuccess = function (event) {
+ ok(false, "Got success, but did not expect it!");
+ reject(event);
+ };
+ });
+}
+
+function openDBRequestSucceeded(request) {
+ return new Promise(function (resolve, reject) {
+ request.onerror = function (event) {
+ ok(false, "indexedDB error, '" + event.target.error.name + "'");
+ reject(event);
+ };
+ request.onupgradeneeded = function (event) {
+ ok(false, "Got upgrade, but did not expect it!");
+ reject(event);
+ };
+ request.onsuccess = function (event) {
+ resolve(event);
+ };
+ });
+}
diff --git a/dom/quota/test/common/mochitest.js b/dom/quota/test/common/mochitest.js
new file mode 100644
index 0000000000..1b867f6e92
--- /dev/null
+++ b/dom/quota/test/common/mochitest.js
@@ -0,0 +1,19 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+loadScript("dom/quota/test/common/content.js");
+
+async function enableStorageTesting() {
+ let prefsToSet = [
+ ["dom.quotaManager.testing", true],
+ ["dom.storageManager.enabled", true],
+ ["dom.simpleDB.enabled", true],
+ ];
+ if (SpecialPowers.Services.appinfo.OS === "WINNT") {
+ prefsToSet.push(["dom.quotaManager.useDOSDevicePathSyntax", true]);
+ }
+
+ await SpecialPowers.pushPrefEnv({ set: prefsToSet });
+}
diff --git a/dom/quota/test/common/nestedtest.js b/dom/quota/test/common/nestedtest.js
new file mode 100644
index 0000000000..5c2011bfe9
--- /dev/null
+++ b/dom/quota/test/common/nestedtest.js
@@ -0,0 +1,6 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+loadScript("dom/quota/test/common/content.js");
diff --git a/dom/quota/test/common/system.js b/dom/quota/test/common/system.js
new file mode 100644
index 0000000000..b01bb8d1fa
--- /dev/null
+++ b/dom/quota/test/common/system.js
@@ -0,0 +1,74 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const PR_USEC_PER_SEC = 1000000;
+
+const NS_ERROR_STORAGE_BUSY = Cr.NS_ERROR_STORAGE_BUSY;
+
+loadScript("dom/quota/test/common/global.js");
+
+function getProfileDir() {
+ return Services.dirsvc.get("ProfD", Ci.nsIFile);
+}
+
+// Given a "/"-delimited path relative to a base file (or the profile
+// directory if a base file is not provided) 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, baseFile) {
+ if (!baseFile) {
+ baseFile = getProfileDir();
+ }
+
+ let file = baseFile.clone();
+
+ if (Services.appinfo.OS === "WINNT") {
+ let winFile = file.QueryInterface(Ci.nsILocalFileWin);
+ winFile.useDOSDevicePathSyntax = true;
+ }
+
+ relativePath.split("/").forEach(function (component) {
+ if (component == "..") {
+ file = file.parent;
+ } else {
+ file.append(component);
+ }
+ });
+
+ return file;
+}
+
+function getCurrentPrincipal() {
+ return Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
+}
+
+function getSimpleDatabase(principal, persistence) {
+ let connection = Cc["@mozilla.org/dom/sdb-connection;1"].createInstance(
+ Ci.nsISDBConnection
+ );
+
+ if (!principal) {
+ principal = getCurrentPrincipal();
+ }
+
+ connection.init(principal, persistence);
+
+ return connection;
+}
+
+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;
+}
diff --git a/dom/quota/test/common/test_simpledb.js b/dom/quota/test/common/test_simpledb.js
new file mode 100644
index 0000000000..dee7019097
--- /dev/null
+++ b/dom/quota/test/common/test_simpledb.js
@@ -0,0 +1,50 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+loadScript("dom/quota/test/common/file.js");
+
+async function testSteps() {
+ const name = "data";
+ const bufferSize = 100;
+
+ let database = getSimpleDatabase();
+
+ let request = database.open(name);
+ await requestFinished(request);
+
+ let buffer1 = getRandomBuffer(bufferSize);
+
+ request = database.write(buffer1);
+ await requestFinished(request);
+
+ request = database.seek(0);
+ await requestFinished(request);
+
+ request = database.read(bufferSize);
+ let result = await requestFinished(request);
+
+ let buffer2 = result.getAsArrayBuffer();
+
+ ok(compareBuffers(buffer1, buffer2), "Buffers equal.");
+
+ let database2 = getSimpleDatabase();
+
+ try {
+ request = database2.open(name);
+ await requestFinished(request);
+ ok(false, "Should have thrown!");
+ } catch (ex) {
+ ok(request.resultCode == NS_ERROR_STORAGE_BUSY, "Good result code.");
+ }
+
+ request = database.close();
+ await requestFinished(request);
+
+ request = database2.open(name);
+ await requestFinished(request);
+
+ request = database2.close();
+ await requestFinished(request);
+}
diff --git a/dom/quota/test/common/test_storage_manager_persist_allow.js b/dom/quota/test/common/test_storage_manager_persist_allow.js
new file mode 100644
index 0000000000..0a6e59843d
--- /dev/null
+++ b/dom/quota/test/common/test_storage_manager_persist_allow.js
@@ -0,0 +1,30 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function* testSteps() {
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [["dom.storageManager.prompt.testing.allow", true]],
+ },
+ continueToNextStep
+ );
+ yield undefined;
+
+ navigator.storage.persist().then(grabArgAndContinueHandler);
+ let persistResult = yield undefined;
+
+ is(persistResult, true, "Persist succeeded");
+
+ navigator.storage.persisted().then(grabArgAndContinueHandler);
+ let persistedResult = yield undefined;
+
+ is(
+ persistResult,
+ persistedResult,
+ "Persist/persisted results are consistent"
+ );
+
+ finishTest();
+}
diff --git a/dom/quota/test/common/test_storage_manager_persist_deny.js b/dom/quota/test/common/test_storage_manager_persist_deny.js
new file mode 100644
index 0000000000..855d739ca3
--- /dev/null
+++ b/dom/quota/test/common/test_storage_manager_persist_deny.js
@@ -0,0 +1,34 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function* testSteps() {
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [["dom.storageManager.prompt.testing.allow", false]],
+ },
+ continueToNextStep
+ );
+ yield undefined;
+
+ navigator.storage.persist().then(grabArgAndContinueHandler);
+ let persistResult = yield undefined;
+
+ is(
+ persistResult,
+ false,
+ "Cancel the persist prompt and resolve a promise with false"
+ );
+
+ navigator.storage.persisted().then(grabArgAndContinueHandler);
+ let persistedResult = yield undefined;
+
+ is(
+ persistResult,
+ persistedResult,
+ "Persist/persisted results are consistent"
+ );
+
+ finishTest();
+}
diff --git a/dom/quota/test/common/test_storage_manager_persisted.js b/dom/quota/test/common/test_storage_manager_persisted.js
new file mode 100644
index 0000000000..ebda93649a
--- /dev/null
+++ b/dom/quota/test/common/test_storage_manager_persisted.js
@@ -0,0 +1,13 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function* testSteps() {
+ navigator.storage.persisted().then(grabArgAndContinueHandler);
+ let persistedResult = yield undefined;
+
+ is(persistedResult, false, "Persisted returns false");
+
+ finishTest();
+}
diff --git a/dom/quota/test/common/xpcshell.js b/dom/quota/test/common/xpcshell.js
new file mode 100644
index 0000000000..ed3afaa467
--- /dev/null
+++ b/dom/quota/test/common/xpcshell.js
@@ -0,0 +1,91 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+loadScript("dom/quota/test/common/system.js");
+
+function enableStorageTesting() {
+ Services.prefs.setBoolPref("dom.quotaManager.testing", true);
+ Services.prefs.setBoolPref("dom.storageManager.enabled", true);
+ Services.prefs.setBoolPref("dom.simpleDB.enabled", true);
+ if (Services.appinfo.OS === "WINNT") {
+ Services.prefs.setBoolPref("dom.quotaManager.useDOSDevicePathSyntax", true);
+ }
+}
+
+function resetStorageTesting() {
+ Services.prefs.clearUserPref("dom.quotaManager.testing");
+ Services.prefs.clearUserPref("dom.storageManager.enabled");
+ Services.prefs.clearUserPref("dom.simpleDB.enabled");
+ if (Services.appinfo.OS === "WINNT") {
+ Services.prefs.clearUserPref("dom.quotaManager.useDOSDevicePathSyntax");
+ }
+}
+
+function clear(callback) {
+ let request = Services.qms.clear();
+ request.callback = callback;
+
+ return request;
+}
+
+function reset(callback) {
+ let request = Services.qms.reset();
+ request.callback = callback;
+
+ return request;
+}
+
+function installPackage(packageRelativePath, allowFileOverwrites) {
+ let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+
+ let packageFile = getRelativeFile(packageRelativePath + ".zip", currentDir);
+
+ let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
+ Ci.nsIZipReader
+ );
+ zipReader.open(packageFile);
+
+ let entryNames = Array.from(zipReader.findEntries(null));
+ entryNames.sort();
+
+ for (let entryName of entryNames) {
+ if (entryName.match(/^create_db\.(html|js)/)) {
+ continue;
+ }
+
+ let zipentry = zipReader.getEntry(entryName);
+
+ let file = getRelativeFile(entryName);
+
+ if (zipentry.isDirectory) {
+ if (!file.exists()) {
+ file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
+ }
+ } else {
+ if (!allowFileOverwrites && file.exists()) {
+ throw new Error("File already exists!");
+ }
+
+ 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();
+}