/** * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /* eslint-disable mozilla/no-arbitrary-setTimeout */ var testGenerator = testSteps(); function* testSteps() { let uri = Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService). newURI("https://www.example.com"); let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] .getService(Ci.nsIScriptSecurityManager); let principal = ssm.createCodebasePrincipal(uri, {}); info("Setting permissions"); let permMgr = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); permMgr.add(uri, "indexedDB", Ci.nsIPermissionManager.ALLOW_ACTION); info("Setting idle preferences to prevent real 'idle-daily' notification"); let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); prefs.setIntPref("idle.lastDailyNotification", (Date.now() / 1000) - 10); info("Activating real idle service"); do_get_idle(); info("Creating databases"); let quotaManagerService = Cc["@mozilla.org/dom/quota-manager-service;1"]. getService(Ci.nsIQuotaManagerService); // Keep at least one database open. let req = indexedDB.open("foo-a", 1); req.onerror = errorHandler; req.onsuccess = grabEventAndContinueHandler; let event = yield undefined; // Keep at least one factory operation alive by deleting a database that is // stil open. req = indexedDB.open("foo-b", 1); req.onerror = errorHandler; req.onsuccess = grabEventAndContinueHandler; event = yield undefined; indexedDB.deleteDatabase("foo-b"); // Create a database which we will later try to open while maintenance is // performed. req = indexedDB.open("foo-c", 1); req.onerror = errorHandler; req.onsuccess = grabEventAndContinueHandler; event = yield undefined; let dbC = event.target.result; dbC.close(); let dbCount = 0; for (let persistence of ["persistent", "temporary", "default"]) { for (let i = 1; i <= 5; i++) { let dbName = "foo-" + i; let dbPersistence = persistence; let req = indexedDB.openForPrincipal(principal, dbName, { version: 1, storage: dbPersistence }); req.onerror = event => { if (dbPersistence != "persistent") { errorHandler(event); return; } // Explicit persistence is currently blocked on mobile. info("Failed to create persistent database '" + dbPersistence + "/" + dbName + "', hopefully this is on mobile!"); event.preventDefault(); if (!(--dbCount)) { continueToNextStep(); } }; req.onupgradeneeded = event => { let db = event.target.result; let objectStore = db.createObjectStore("foo"); // Add lots of data... for (let j = 0; j < 100; j++) { objectStore.add("abcdefghijklmnopqrstuvwxyz0123456789", j); } // And then clear it so that maintenance has some space to reclaim. objectStore.clear(); }; req.onsuccess = event => { let db = event.target.result; ok(db, "Created database '" + dbPersistence + "/" + dbName + "'"); db.close(); if (!(--dbCount)) { continueToNextStep(); } }; dbCount++; } } yield undefined; info("Getting usage before maintenance"); let usageBeforeMaintenance; quotaManagerService.getUsageForPrincipal(principal, (request) => { let usage = request.result.usage; ok(usage > 0, "Usage is non-zero"); usageBeforeMaintenance = usage; continueToNextStep(); }); yield undefined; info("Sending fake 'idle-daily' notification to QuotaManager"); let observer = quotaManagerService.QueryInterface(Ci.nsIObserver); observer.observe(null, "idle-daily", ""); info("Opening database while maintenance is performed"); req = indexedDB.open("foo-c", 1); req.onerror = errorHandler; req.onsuccess = grabEventAndContinueHandler; yield undefined; info("Waiting for maintenance to start"); // This time is totally arbitrary. Most likely directory scanning will have // completed, QuotaManager locks will be acquired, and maintenance tasks will // be scheduled before this time has elapsed, so we will be testing the // maintenance code. However, if something is slow then this will test // shutting down in the middle of maintenance. setTimeout(continueToNextStep, 10000); yield undefined; info("Getting usage after maintenance"); let usageAfterMaintenance; quotaManagerService.getUsageForPrincipal(principal, (request) => { let usage = request.result.usage; ok(usage > 0, "Usage is non-zero"); usageAfterMaintenance = usage; continueToNextStep(); }); yield undefined; info("Usage before: " + usageBeforeMaintenance + ". " + "Usage after: " + usageAfterMaintenance); ok(usageAfterMaintenance <= usageBeforeMaintenance, "Maintenance decreased file sizes or left them the same"); finishTest(); yield undefined; }