Bug 1945643 - Update to mozilla-nimbus-schemas 2025.1.1 r=chumphreys
[gecko.git] / dom / quota / test / xpcshell / common / head.js
blob2ca00eeb4713e5018ecb605e2f29b7cc9cbd2676
1 /**
2 * Any copyright is dedicated to the Public Domain.
3 * http://creativecommons.org/publicdomain/zero/1.0/
4 */
6 const NS_OK = Cr.NS_OK;
7 const NS_ERROR_FAILURE = Cr.NS_ERROR_FAILURE;
8 const NS_ERROR_UNEXPECTED = Cr.NS_ERROR_UNEXPECTED;
9 const NS_ERROR_FILE_NO_DEVICE_SPACE = Cr.NS_ERROR_FILE_NO_DEVICE_SPACE;
11 const loggingEnabled = false;
13 var testGenerator;
15 loadScript("dom/quota/test/common/xpcshell.js");
17 function log(msg) {
18 if (loggingEnabled) {
19 info(msg);
23 function is(a, b, msg) {
24 Assert.equal(a, b, msg);
27 function ok(cond, msg) {
28 Assert.ok(!!cond, msg);
31 function todo(cond, msg) {
32 todo_check_true(cond);
35 function run_test() {
36 runTest();
39 if (!this.runTest) {
40 this.runTest = function () {
41 do_get_profile();
43 enableStorageTesting();
44 enableTesting();
46 // In order to support converting tests to using async functions from using
47 // generator functions, we detect async functions by checking the name of
48 // function's constructor.
49 Assert.ok(
50 typeof testSteps === "function",
51 "There should be a testSteps function"
53 if (testSteps.constructor.name === "AsyncFunction") {
54 // Do run our existing cleanup function that would normally be called by
55 // the generator's call to finishTest().
56 registerCleanupFunction(function () {
57 resetStorageTesting();
58 resetTesting();
59 });
61 add_task(testSteps);
63 // Since we defined run_test, we must invoke run_next_test() to start the
64 // async test.
65 run_next_test();
66 } else {
67 Assert.ok(
68 testSteps.constructor.name === "GeneratorFunction",
69 "Unsupported function type"
72 do_test_pending();
74 testGenerator = testSteps();
75 testGenerator.next();
80 function finishTest() {
81 resetStorageTesting();
82 resetTesting();
84 executeSoon(function () {
85 do_test_finished();
86 });
89 function grabArgAndContinueHandler(arg) {
90 testGenerator.next(arg);
93 function continueToNextStep() {
94 executeSoon(function () {
95 testGenerator.next();
96 });
99 function continueToNextStepSync() {
100 testGenerator.next();
103 function enableTesting() {
104 SpecialPowers.setBoolPref(
105 "dom.storage.enable_unsupported_legacy_implementation",
106 false
110 function resetTesting() {
111 SpecialPowers.clearUserPref(
112 "dom.storage.enable_unsupported_legacy_implementation"
116 function setGlobalLimit(globalLimit) {
117 SpecialPowers.setIntPref(
118 "dom.quotaManager.temporaryStorage.fixedLimit",
119 globalLimit
123 function resetGlobalLimit() {
124 SpecialPowers.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
127 function storageInitialized(callback) {
128 let request = SpecialPowers._getQuotaManager().storageInitialized();
129 request.callback = callback;
131 return request;
134 function persistentStorageInitialized(callback) {
135 let request = SpecialPowers._getQuotaManager().persistentStorageInitialized();
136 request.callback = callback;
138 return request;
141 function temporaryStorageInitialized(callback) {
142 let request = SpecialPowers._getQuotaManager().temporaryStorageInitialized();
143 request.callback = callback;
145 return request;
148 function persistentOriginInitialized(principal, callback) {
149 let request =
150 SpecialPowers._getQuotaManager().persistentOriginInitialized(principal);
151 request.callback = callback;
153 return request;
156 function temporaryOriginInitialized(persistence, principal, callback) {
157 let request = SpecialPowers._getQuotaManager().temporaryOriginInitialized(
158 persistence,
159 principal
161 request.callback = callback;
163 return request;
166 function init(callback) {
167 let request = SpecialPowers._getQuotaManager().init();
168 request.callback = callback;
170 return request;
173 function initializePersistentStorage(callback) {
174 let request = SpecialPowers._getQuotaManager().initializePersistentStorage();
175 request.callback = callback;
177 return request;
180 function initTemporaryStorage(callback) {
181 let request = SpecialPowers._getQuotaManager().initTemporaryStorage();
182 request.callback = callback;
184 return request;
187 function initPersistentOrigin(principal, callback) {
188 let request =
189 SpecialPowers._getQuotaManager().initializePersistentOrigin(principal);
190 request.callback = callback;
192 return request;
195 function initTemporaryOrigin(
196 persistence,
197 principal,
198 createIfNonExistent = true,
199 callback
201 let request = SpecialPowers._getQuotaManager().initializeTemporaryOrigin(
202 persistence,
203 principal,
204 createIfNonExistent
206 request.callback = callback;
208 return request;
211 function initPersistentClient(principal, client, callback) {
212 let request = SpecialPowers._getQuotaManager().initializePersistentClient(
213 principal,
214 client
216 request.callback = callback;
218 return request;
221 function initTemporaryClient(persistence, principal, client, callback) {
222 let request = SpecialPowers._getQuotaManager().initializeTemporaryClient(
223 persistence,
224 principal,
225 client
227 request.callback = callback;
229 return request;
232 function getFullOriginMetadata(persistence, principal, callback) {
233 const request = SpecialPowers._getQuotaManager().getFullOriginMetadata(
234 persistence,
235 principal
237 request.callback = callback;
239 return request;
242 function clearClient(principal, client, persistence, callback) {
243 let request = SpecialPowers._getQuotaManager().clearStoragesForClient(
244 principal,
245 client,
246 persistence
248 request.callback = callback;
250 return request;
253 function clearOrigin(principal, persistence, callback) {
254 let request = SpecialPowers._getQuotaManager().clearStoragesForPrincipal(
255 principal,
256 persistence
258 request.callback = callback;
260 return request;
263 function clearOriginsByPrefix(principal, persistence, callback) {
264 let request = SpecialPowers._getQuotaManager().clearStoragesForOriginPrefix(
265 principal,
266 persistence
268 request.callback = callback;
270 return request;
273 function clearPrivateBrowsing(callback) {
274 let request =
275 SpecialPowers._getQuotaManager().clearStoragesForPrivateBrowsing();
276 request.callback = callback;
278 return request;
281 function resetClient(principal, client) {
282 let request = Services.qms.resetStoragesForClient(
283 principal,
284 client,
285 "default"
288 return request;
291 function persist(principal, callback) {
292 let request = SpecialPowers._getQuotaManager().persist(principal);
293 request.callback = callback;
295 return request;
298 function persisted(principal, callback) {
299 let request = SpecialPowers._getQuotaManager().persisted(principal);
300 request.callback = callback;
302 return request;
305 function estimateOrigin(principal, callback) {
306 let request = SpecialPowers._getQuotaManager().estimate(principal);
307 request.callback = callback;
309 return request;
312 function listOrigins(callback) {
313 let request = SpecialPowers._getQuotaManager().listOrigins(callback);
314 request.callback = callback;
316 return request;
319 function getPersistedFromMetadata(readBuffer) {
320 const persistedPosition = 8; // Persisted state is stored in the 9th byte
321 let view =
322 readBuffer instanceof Uint8Array ? readBuffer : new Uint8Array(readBuffer);
324 return !!view[persistedPosition];
327 function grabResultAndContinueHandler(request) {
328 testGenerator.next(request.result);
331 function grabUsageAndContinueHandler(request) {
332 testGenerator.next(request.result.usage);
335 function getUsage(usageHandler, getAll) {
336 let request = SpecialPowers._getQuotaManager().getUsage(usageHandler, getAll);
338 return request;
341 function getOriginUsage(principal) {
342 let request = Services.qms.getUsageForPrincipal(principal, function () {});
344 return request;
347 function getCachedOriginUsage(principal) {
348 let request = Services.qms.getCachedUsageForPrincipal(
349 principal,
350 function () {}
353 return request;
356 function getCachedOriginUsage(principal) {
357 let request = Services.qms.getCachedUsageForPrincipal(principal);
359 return request;
362 function getCurrentUsage(usageHandler) {
363 let principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
364 Ci.nsIPrincipal
366 let request = SpecialPowers._getQuotaManager().getUsageForPrincipal(
367 principal,
368 usageHandler
371 return request;
374 function getPrincipal(url, attr = {}) {
375 let uri = Cc["@mozilla.org/network/io-service;1"]
376 .getService(Ci.nsIIOService)
377 .newURI(url);
378 let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(
379 Ci.nsIScriptSecurityManager
381 return ssm.createContentPrincipal(uri, attr);
384 var SpecialPowers = {
385 getBoolPref(prefName) {
386 return this._getPrefs().getBoolPref(prefName);
389 setBoolPref(prefName, value) {
390 this._getPrefs().setBoolPref(prefName, value);
393 setIntPref(prefName, value) {
394 this._getPrefs().setIntPref(prefName, value);
397 clearUserPref(prefName) {
398 this._getPrefs().clearUserPref(prefName);
401 _getPrefs() {
402 let prefService = Cc["@mozilla.org/preferences-service;1"].getService(
403 Ci.nsIPrefService
405 return prefService.getBranch(null);
408 _getQuotaManager() {
409 return Cc["@mozilla.org/dom/quota-manager-service;1"].getService(
410 Ci.nsIQuotaManagerService
415 function installPackages(packageRelativePaths) {
416 if (packageRelativePaths.length != 2) {
417 throw new Error("Unsupported number of package relative paths");
420 for (const packageRelativePath of packageRelativePaths) {
421 installPackage(packageRelativePath);
425 // Take current storage structure on disk and compare it with the expected
426 // structure. The expected structure is defined in JSON and consists of a per
427 // test package definition and a shared package definition. The shared package
428 // definition should contain unknown stuff which needs to be properly handled
429 // in all situations.
430 function verifyStorage(packageDefinitionRelativePaths, key, sharedKey) {
431 if (packageDefinitionRelativePaths.length != 2) {
432 throw new Error("Unsupported number of package definition relative paths");
435 function verifyEntries(entries, name, indent = "") {
436 log(`${indent}Verifying ${name} entries`);
438 indent += " ";
440 for (const entry of entries) {
441 const maybeName = entry.name;
443 log(`${indent}Verifying entry ${maybeName}`);
445 let hasName = false;
446 let hasDir = false;
447 let hasEntries = false;
449 for (const property in entry) {
450 switch (property) {
451 case "note":
452 case "todo":
453 break;
455 case "name":
456 hasName = true;
457 break;
459 case "dir":
460 hasDir = true;
461 break;
463 case "entries":
464 hasEntries = true;
465 break;
467 default:
468 throw new Error(`Unknown property ${property}`);
472 if (!hasName) {
473 throw new Error("An entry must have the name property");
476 if (!hasDir) {
477 throw new Error("An entry must have the dir property");
480 if (hasEntries && !entry.dir) {
481 throw new Error("An entry can't have entries if it's not a directory");
484 if (hasEntries) {
485 verifyEntries(entry.entries, entry.name, indent);
490 function getCurrentEntries() {
491 log("Getting current entries");
493 function getEntryForFile(file) {
494 let entry = {
495 name: file.leafName,
496 dir: file.isDirectory(),
499 if (file.isDirectory()) {
500 const enumerator = file.directoryEntries;
501 let nextFile;
502 while ((nextFile = enumerator.nextFile)) {
503 if (!entry.entries) {
504 entry.entries = [];
506 entry.entries.push(getEntryForFile(nextFile));
510 return entry;
513 let entries = [];
515 let file = getRelativeFile("indexedDB");
516 if (file.exists()) {
517 entries.push(getEntryForFile(file));
520 file = getRelativeFile("storage");
521 if (file.exists()) {
522 entries.push(getEntryForFile(file));
525 file = getRelativeFile("storage.sqlite");
526 if (file.exists()) {
527 entries.push(getEntryForFile(file));
530 verifyEntries(entries, "current");
532 return entries;
535 function getEntriesFromPackageDefinition(
536 packageDefinitionRelativePath,
537 lookupKey
539 log(`Getting ${lookupKey} entries from ${packageDefinitionRelativePath}`);
541 const currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
542 const file = getRelativeFile(
543 packageDefinitionRelativePath + ".json",
544 currentDir
547 const fileInputStream = Cc[
548 "@mozilla.org/network/file-input-stream;1"
549 ].createInstance(Ci.nsIFileInputStream);
550 fileInputStream.init(file, -1, -1, 0);
552 const scriptableInputStream = Cc[
553 "@mozilla.org/scriptableinputstream;1"
554 ].createInstance(Ci.nsIScriptableInputStream);
555 scriptableInputStream.init(fileInputStream);
557 const data = scriptableInputStream.readBytes(
558 scriptableInputStream.available()
561 const obj = JSON.parse(data);
563 const result = obj.find(({ key: elementKey }) => elementKey == lookupKey);
565 if (!result) {
566 throw new Error("The file doesn't contain an element for given key");
569 if (!result.entries) {
570 throw new Error("The element doesn't have the entries property");
573 verifyEntries(result.entries, lookupKey);
575 return result.entries;
578 function addSharedEntries(expectedEntries, sharedEntries, name, indent = "") {
579 log(`${indent}Checking common ${name} entries`);
581 indent += " ";
583 for (const sharedEntry of sharedEntries) {
584 const expectedEntry = expectedEntries.find(
585 ({ name: elementName }) => elementName == sharedEntry.name
588 if (expectedEntry) {
589 log(`${indent}Checking common entry ${sharedEntry.name}`);
591 if (!expectedEntry.dir || !sharedEntry.dir) {
592 throw new Error("A common entry must be a directory");
595 if (!expectedEntry.entries && !sharedEntry.entries) {
596 throw new Error("A common entry must not be a leaf");
599 if (sharedEntry.entries) {
600 if (!expectedEntry.entries) {
601 expectedEntry.entries = [];
604 addSharedEntries(
605 expectedEntry.entries,
606 sharedEntry.entries,
607 sharedEntry.name,
608 indent
611 } else {
612 log(`${indent}Adding entry ${sharedEntry.name}`);
613 expectedEntries.push(sharedEntry);
618 function compareEntries(currentEntries, expectedEntries, name, indent = "") {
619 log(`${indent}Comparing ${name} entries`);
621 indent += " ";
623 if (currentEntries.length != expectedEntries.length) {
624 throw new Error("Entries must have the same length");
627 for (const currentEntry of currentEntries) {
628 log(`${indent}Comparing entry ${currentEntry.name}`);
630 const expectedEntry = expectedEntries.find(
631 ({ name: elementName }) => elementName == currentEntry.name
634 if (!expectedEntry) {
635 throw new Error("Cannot find a matching entry");
638 if (expectedEntry.dir != currentEntry.dir) {
639 throw new Error("The dir property doesn't match");
642 if (
643 (expectedEntry.entries && !currentEntry.entries) ||
644 (!expectedEntry.entries && currentEntry.entries)
646 throw new Error("The entries property doesn't match");
649 if (expectedEntry.entries) {
650 compareEntries(
651 currentEntry.entries,
652 expectedEntry.entries,
653 currentEntry.name,
654 indent
660 const currentEntries = getCurrentEntries();
662 log("Stringified current entries: " + JSON.stringify(currentEntries));
664 const expectedEntries = getEntriesFromPackageDefinition(
665 packageDefinitionRelativePaths[0],
668 const sharedEntries = getEntriesFromPackageDefinition(
669 packageDefinitionRelativePaths[1],
670 sharedKey ? sharedKey : key
673 addSharedEntries(expectedEntries, sharedEntries, key);
675 log("Stringified expected entries: " + JSON.stringify(expectedEntries));
677 compareEntries(currentEntries, expectedEntries, key);
680 async function verifyInitializationStatus(
681 expectStorageIsInitialized,
682 expectPersistentStorageIsInitialized,
683 expectTemporaryStorageIsInitialized
685 if (!expectStorageIsInitialized && expectPersistentStorageIsInitialized) {
686 throw new Error("Invalid expectation");
689 if (!expectStorageIsInitialized && expectTemporaryStorageIsInitialized) {
690 throw new Error("Invalid expectation");
693 let request = storageInitialized();
694 await requestFinished(request);
696 const storageIsInitialized = request.result;
698 request = persistentStorageInitialized();
699 await requestFinished(request);
701 const persistentStorageIsInitialized = request.result;
703 request = temporaryStorageInitialized();
704 await requestFinished(request);
706 const temporaryStorageIsInitialized = request.result;
709 !(!storageIsInitialized && persistentStorageIsInitialized),
710 "Initialization status is consistent"
714 !(!storageIsInitialized && temporaryStorageIsInitialized),
715 "Initialization status is consistent"
718 if (expectStorageIsInitialized) {
719 ok(storageIsInitialized, "Storage is initialized");
720 } else {
721 ok(!storageIsInitialized, "Storage is not initialized");
724 if (expectPersistentStorageIsInitialized) {
725 ok(persistentStorageIsInitialized, "Persistent storage is initialized");
726 } else {
728 !persistentStorageIsInitialized,
729 "Persistent storage is not initialized"
733 if (expectTemporaryStorageIsInitialized) {
734 ok(temporaryStorageIsInitialized, "Temporary storage is initialized");
735 } else {
736 ok(!temporaryStorageIsInitialized, "Temporary storage is not initialized");