michael@0: /** michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ michael@0: */ michael@0: michael@0: var testGenerator = testSteps(); michael@0: michael@0: function testSteps() michael@0: { michael@0: const name = this.window ? window.location.pathname : "Splendid Test"; michael@0: michael@0: const urls = [ michael@0: { url: "http://www.alpha.com", flags: [true, true, false, false] }, michael@0: { url: "http://www.beta.com", flags: [true, false, false, false] }, michael@0: { url: "http://www.gamma.com", flags: [true, true, false, false] }, michael@0: { url: "http://www.delta.com", flags: [true, true, false, false] }, michael@0: { url: "http://www.epsilon.com", flags: [true, true, false, false] }, michael@0: { url: "http://www2.alpha.com", flags: [true, true, false, false] }, michael@0: { url: "http://www2.beta.com", flags: [true, true, false, false] }, michael@0: { url: "http://www2.gamma.com", flags: [true, true, true, false] }, michael@0: { url: "http://www2.delta.com", flags: [true, true, true, true] }, michael@0: { url: "http://www2.epsilon.com", flags: [true, true, true, true] }, michael@0: { url: "http://joe.blog.alpha.com", flags: [true, true, true, true] }, michael@0: { url: "http://joe.blog.beta.com", flags: [true, true, true, true] }, michael@0: { url: "http://joe.blog.gamma.com", flags: [true, true, true, true] }, michael@0: { url: "http://joe.blog.delta.com", flags: [true, true, true, true] }, michael@0: { url: "http://joe.blog.epsilon.com", flags: [true, true, true, true] }, michael@0: { url: "http://www.rudolf.org", flags: [true, true, true, true] }, michael@0: { url: "http://www.pauline.org", flags: [true, true, true, true] }, michael@0: { url: "http://www.marie.org", flags: [true, true, true, true] }, michael@0: { url: "http://www.john.org", flags: [true, true, true, true] }, michael@0: { url: "http://www.ema.org", flags: [true, true, true, true] }, michael@0: { url: "http://www.trigger.com", flags: [false, true, true, true] } michael@0: ]; michael@0: const lastIndex = urls.length - 1; michael@0: const lastUrl = urls[lastIndex].url; michael@0: michael@0: let quotaManager = michael@0: Components.classes["@mozilla.org/dom/quota/manager;1"] michael@0: .getService(Components.interfaces.nsIQuotaManager); michael@0: michael@0: let ioService = Components.classes["@mozilla.org/network/io-service;1"] michael@0: .getService(Components.interfaces.nsIIOService); michael@0: michael@0: let dbSize = 0; michael@0: michael@0: let databases = []; michael@0: michael@0: function setLimit(limit) { michael@0: if (limit) { michael@0: SpecialPowers.setIntPref("dom.quotaManager.temporaryStorage.fixedLimit", michael@0: limit); michael@0: return; michael@0: } michael@0: SpecialPowers.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit"); michael@0: } michael@0: michael@0: function getPrincipal(url) { michael@0: let uri = ioService.newURI(url, null, null); michael@0: return Components.classes["@mozilla.org/scriptsecuritymanager;1"] michael@0: .getService(Components.interfaces.nsIScriptSecurityManager) michael@0: .getNoAppCodebasePrincipal(uri); michael@0: } michael@0: michael@0: function getUsageForUrl(url, usageHandler) { michael@0: let uri = ioService.newURI(url, null, null); michael@0: function callback(uri, usage, fileUsage) { michael@0: usageHandler(usage, fileUsage); michael@0: } michael@0: quotaManager.getUsageForURI(uri, callback); michael@0: } michael@0: michael@0: function grabUsageAndContinueHandler(usage, fileUsage) { michael@0: testGenerator.send(usage); michael@0: } michael@0: michael@0: function checkUsage(stageIndex) { michael@0: let handledIndex = 0; michael@0: michael@0: function usageHandler(usage, fileUsage) { michael@0: if (urls[handledIndex].flags[stageIndex - 1]) { michael@0: ok(usage > 0, "Correct usage"); michael@0: } michael@0: else { michael@0: ok(usage == 0, "Correct usage"); michael@0: } michael@0: if (++handledIndex == urls.length) { michael@0: continueToNextStep(); michael@0: } michael@0: } michael@0: michael@0: for (let i = 0; i < urls.length; i++) { michael@0: getUsageForUrl(urls[i].url, usageHandler); michael@0: } michael@0: } michael@0: michael@0: // Enable clear() and test() michael@0: let testingEnabled = michael@0: SpecialPowers.getBoolPref("dom.quotaManager.testing"); michael@0: SpecialPowers.setBoolPref("dom.quotaManager.testing", true) michael@0: michael@0: // Calibration michael@0: let request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, michael@0: { storage: "temporary" }); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: let event = yield undefined; michael@0: michael@0: getUsageForUrl(lastUrl, grabUsageAndContinueHandler); michael@0: dbSize = yield undefined; michael@0: michael@0: setLimit(lastIndex * dbSize / 1024); michael@0: quotaManager.clear(); michael@0: michael@0: // Stage 1 michael@0: for (let i = 0; i < lastIndex; i++) { michael@0: let data = urls[i]; michael@0: michael@0: request = indexedDB.openForPrincipal(getPrincipal(data.url), name, michael@0: { storage: "temporary" }); michael@0: request.onerror = errorHandler; michael@0: request.onupgradeneeded = grabEventAndContinueHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "upgradeneeded", "Got correct event type"); michael@0: michael@0: let db = event.target.result; michael@0: db.createObjectStore("foo", { }); michael@0: michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "success", "Got correct event type"); michael@0: michael@0: databases.push(event.target.result); michael@0: } michael@0: michael@0: request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, michael@0: { storage: "temporary" }); michael@0: request.addEventListener("error", new ExpectError("QuotaExceededError")); michael@0: request.onsuccess = unexpectedSuccessHandler; michael@0: event = yield undefined; michael@0: michael@0: checkUsage(1); michael@0: yield undefined; michael@0: michael@0: // Stage 2 michael@0: for (let i = 1; i < urls.length; i++) { michael@0: databases[i] = null; michael@0: michael@0: scheduleGC(); michael@0: yield undefined; michael@0: michael@0: // The origin access time is set to the current system time when the first michael@0: // database for an origin is registered or the last one is unregistered. michael@0: // The registration happens when the database object is being created and michael@0: // the unregistration when it is unlinked/garbage collected. michael@0: // Some older windows systems have the system time limited to a maximum michael@0: // resolution of 10 or 15 milliseconds, so without a pause here we would michael@0: // end up with origins with the same access time which would cause random michael@0: // failures. michael@0: setTimeout(function() { testGenerator.next(); }, 20); michael@0: yield undefined; michael@0: } michael@0: michael@0: request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, michael@0: { storage: "temporary" }); michael@0: request.onerror = errorHandler; michael@0: request.onupgradeneeded = grabEventAndContinueHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "upgradeneeded", "Got correct event type"); michael@0: michael@0: let db = event.target.result; michael@0: db.createObjectStore("foo", { }); michael@0: michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "success", "Got correct event type"); michael@0: michael@0: checkUsage(2); michael@0: yield undefined; michael@0: michael@0: // Stage 3 michael@0: setLimit(14 * dbSize / 1024); michael@0: quotaManager.reset(); michael@0: michael@0: request = indexedDB.openForPrincipal(getPrincipal(lastUrl), name, michael@0: { storage: "temporary" }); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "success", "Got correct event type"); michael@0: michael@0: let db = event.target.result; michael@0: michael@0: checkUsage(3); michael@0: yield undefined; michael@0: michael@0: // Stage 4 michael@0: let trans = db.transaction(["foo"], "readwrite"); michael@0: michael@0: let blob = Blob(["bar"]); michael@0: request = trans.objectStore("foo").add(blob, 42); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: trans.oncomplete = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: checkUsage(4); michael@0: yield undefined; michael@0: michael@0: // Cleanup michael@0: setLimit(); michael@0: quotaManager.reset(); michael@0: michael@0: SpecialPowers.setBoolPref("dom.quotaManager.testing", testingEnabled); michael@0: michael@0: finishTest(); michael@0: yield undefined; michael@0: }