diff options
Diffstat (limited to 'dom/quota/test/common')
-rw-r--r-- | dom/quota/test/common/browser.js | 33 | ||||
-rw-r--r-- | dom/quota/test/common/content.js | 62 | ||||
-rw-r--r-- | dom/quota/test/common/file.js | 45 | ||||
-rw-r--r-- | dom/quota/test/common/global.js | 47 | ||||
-rw-r--r-- | dom/quota/test/common/mochitest.js | 18 | ||||
-rw-r--r-- | dom/quota/test/common/nestedtest.js | 6 | ||||
-rw-r--r-- | dom/quota/test/common/system.js | 74 | ||||
-rw-r--r-- | dom/quota/test/common/test_simpledb.js | 50 | ||||
-rw-r--r-- | dom/quota/test/common/test_storage_manager_persist_allow.js | 30 | ||||
-rw-r--r-- | dom/quota/test/common/test_storage_manager_persist_deny.js | 34 | ||||
-rw-r--r-- | dom/quota/test/common/test_storage_manager_persisted.js | 13 | ||||
-rw-r--r-- | dom/quota/test/common/xpcshell.js | 89 |
12 files changed, 501 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..5d9abd79e3 --- /dev/null +++ b/dom/quota/test/common/browser.js @@ -0,0 +1,33 @@ +/** + * 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.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..4bcfcf1138 --- /dev/null +++ b/dom/quota/test/common/mochitest.js @@ -0,0 +1,18 @@ +/** + * 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.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..d0c5d78491 --- /dev/null +++ b/dom/quota/test/common/xpcshell.js @@ -0,0 +1,89 @@ +/** + * 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.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.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(); +} |