Bug 1816170 - Disable perftest-on-autoland cron. r=aglavic
[gecko.git] / dom / indexedDB / test / unit / xpcshell-head-parent-process.js
blob1e0b4ed482b604feda65e76e695dd979176a72b7
1 /**
2  * Any copyright is dedicated to the Public Domain.
3  * http://creativecommons.org/publicdomain/zero/1.0/
4  */
6 // Tests using testGenerator are expected to define it themselves.
7 // Testing functions are expected to call testSteps and its type should either
8 // be GeneratorFunction or AsyncFunction
9 /* global testGenerator, testSteps:false */
11 var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
13 if (!("self" in this)) {
14   this.self = this;
17 var bufferCache = [];
19 function is(a, b, msg) {
20   Assert.equal(a, b, msg);
23 function ok(cond, msg) {
24   Assert.ok(!!cond, msg);
27 function isnot(a, b, msg) {
28   Assert.notEqual(a, b, msg);
31 function todo(condition, name, diag) {
32   todo_check_true(condition);
35 function run_test() {
36   runTest();
39 if (!this.runTest) {
40   this.runTest = function() {
41     if (SpecialPowers.isMainProcess()) {
42       // XPCShell does not get a profile by default.
43       do_get_profile();
45       enableTesting();
46       enableExperimental();
47     }
49     Cu.importGlobalProperties(["indexedDB"]);
51     // In order to support converting tests to using async functions from using
52     // generator functions, we detect async functions by checking the name of
53     // function's constructor.
54     Assert.ok(
55       typeof testSteps === "function",
56       "There should be a testSteps function"
57     );
58     if (testSteps.constructor.name === "AsyncFunction") {
59       // Do run our existing cleanup function that would normally be called by
60       // the generator's call to finishTest().
61       registerCleanupFunction(resetTesting);
63       add_task(testSteps);
65       // Since we defined run_test, we must invoke run_next_test() to start the
66       // async test.
67       run_next_test();
68     } else {
69       Assert.ok(
70         testSteps.constructor.name === "GeneratorFunction",
71         "Unsupported function type"
72       );
74       do_test_pending();
75       testGenerator.next();
76     }
77   };
80 function finishTest() {
81   if (SpecialPowers.isMainProcess()) {
82     resetExperimental();
83     resetTesting();
84   }
86   SpecialPowers.removeFiles();
88   executeSoon(function() {
89     do_test_finished();
90   });
93 function grabEventAndContinueHandler(event) {
94   testGenerator.next(event);
97 function continueToNextStep() {
98   executeSoon(function() {
99     testGenerator.next();
100   });
103 function errorHandler(event) {
104   try {
105     dump("indexedDB error: " + event.target.error.name);
106   } catch (e) {
107     dump("indexedDB error: " + e);
108   }
109   Assert.ok(false);
110   finishTest();
113 function unexpectedSuccessHandler() {
114   Assert.ok(false);
115   finishTest();
118 function expectedErrorHandler(name) {
119   return function(event) {
120     Assert.equal(event.type, "error");
121     Assert.equal(event.target.error.name, name);
122     event.preventDefault();
123     grabEventAndContinueHandler(event);
124   };
127 function expectUncaughtException(expecting) {
128   // This is dummy for xpcshell test.
131 function ExpectError(name, preventDefault) {
132   this._name = name;
133   this._preventDefault = preventDefault;
135 ExpectError.prototype = {
136   handleEvent(event) {
137     Assert.equal(event.type, "error");
138     Assert.equal(this._name, event.target.error.name);
139     if (this._preventDefault) {
140       event.preventDefault();
141       event.stopPropagation();
142     }
143     grabEventAndContinueHandler(event);
144   },
147 function continueToNextStepSync() {
148   testGenerator.next();
151 // TODO compareKeys is duplicated in ../helpers.js, can we import that here?
152 // the same applies to many other functions in this file
153 // this duplication should be avoided (bug 1565986)
154 function compareKeys(k1, k2) {
155   let t = typeof k1;
156   if (t != typeof k2) {
157     return false;
158   }
160   if (t !== "object") {
161     return k1 === k2;
162   }
164   if (k1 instanceof Date) {
165     return k2 instanceof Date && k1.getTime() === k2.getTime();
166   }
168   if (k1 instanceof Array) {
169     if (!(k2 instanceof Array) || k1.length != k2.length) {
170       return false;
171     }
173     for (let i = 0; i < k1.length; ++i) {
174       if (!compareKeys(k1[i], k2[i])) {
175         return false;
176       }
177     }
179     return true;
180   }
182   if (k1 instanceof ArrayBuffer) {
183     if (!(k2 instanceof ArrayBuffer)) {
184       return false;
185     }
187     function arrayBuffersAreEqual(a, b) {
188       if (a.byteLength != b.byteLength) {
189         return false;
190       }
191       let ui8b = new Uint8Array(b);
192       return new Uint8Array(a).every((val, i) => val === ui8b[i]);
193     }
195     return arrayBuffersAreEqual(k1, k2);
196   }
198   return false;
201 function addPermission(permission, url) {
202   throw new Error("addPermission");
205 function removePermission(permission, url) {
206   throw new Error("removePermission");
209 function allowIndexedDB(url) {
210   throw new Error("allowIndexedDB");
213 function disallowIndexedDB(url) {
214   throw new Error("disallowIndexedDB");
217 function enableExperimental() {
218   SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
221 function resetExperimental() {
222   SpecialPowers.clearUserPref("dom.indexedDB.experimental");
225 function enableTesting() {
226   SpecialPowers.setBoolPref("dom.indexedDB.testing", true);
229 function resetTesting() {
230   SpecialPowers.clearUserPref("dom.indexedDB.testing");
233 function gc() {
234   Cu.forceGC();
235   Cu.forceCC();
238 function scheduleGC() {
239   SpecialPowers.exactGC(continueToNextStep);
242 function setTimeout(fun, timeout) {
243   let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
244   var event = {
245     notify(timer) {
246       fun();
247     },
248   };
249   timer.initWithCallback(event, timeout, Ci.nsITimer.TYPE_ONE_SHOT);
250   return timer;
253 function initStorage() {
254   return Services.qms.init();
257 function initPersistentOrigin(principal) {
258   return Services.qms.initializePersistentOrigin(principal);
261 function resetOrClearAllDatabases(callback, clear) {
262   if (!SpecialPowers.isMainProcess()) {
263     throw new Error("clearAllDatabases not implemented for child processes!");
264   }
266   const quotaPref = "dom.quotaManager.testing";
268   let oldPrefValue;
269   if (Services.prefs.prefHasUserValue(quotaPref)) {
270     oldPrefValue = SpecialPowers.getBoolPref(quotaPref);
271   }
273   SpecialPowers.setBoolPref(quotaPref, true);
275   let request;
277   try {
278     if (clear) {
279       request = Services.qms.clear();
280     } else {
281       request = Services.qms.reset();
282     }
283   } catch (e) {
284     if (oldPrefValue !== undefined) {
285       SpecialPowers.setBoolPref(quotaPref, oldPrefValue);
286     } else {
287       SpecialPowers.clearUserPref(quotaPref);
288     }
289     throw e;
290   }
292   request.callback = callback;
294   return request;
297 function resetAllDatabases(callback) {
298   return resetOrClearAllDatabases(callback, false);
301 function clearAllDatabases(callback) {
302   return resetOrClearAllDatabases(callback, true);
305 function installPackagedProfile(packageName) {
306   let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
308   let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
310   let packageFile = currentDir.clone();
311   packageFile.append(packageName + ".zip");
313   let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
314     Ci.nsIZipReader
315   );
316   zipReader.open(packageFile);
318   let entryNames = [];
319   for (let entry of zipReader.findEntries(null)) {
320     if (entry != "create_db.html") {
321       entryNames.push(entry);
322     }
323   }
324   entryNames.sort();
326   for (let entryName of entryNames) {
327     let zipentry = zipReader.getEntry(entryName);
329     let file = profileDir.clone();
330     let split = entryName.split("/");
331     for (let i = 0; i < split.length; i++) {
332       file.append(split[i]);
333     }
335     if (zipentry.isDirectory) {
336       file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
337     } else {
338       let istream = zipReader.getInputStream(entryName);
340       var ostream = Cc[
341         "@mozilla.org/network/file-output-stream;1"
342       ].createInstance(Ci.nsIFileOutputStream);
343       ostream.init(file, -1, parseInt("0644", 8), 0);
345       let bostream = Cc[
346         "@mozilla.org/network/buffered-output-stream;1"
347       ].createInstance(Ci.nsIBufferedOutputStream);
348       bostream.init(ostream, 32768);
350       bostream.writeFrom(istream, istream.available());
352       istream.close();
353       bostream.close();
354     }
355   }
357   zipReader.close();
360 function getChromeFilesDir() {
361   let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
363   let idbDir = profileDir.clone();
364   idbDir.append("storage");
365   idbDir.append("permanent");
366   idbDir.append("chrome");
367   idbDir.append("idb");
369   let idbEntries = idbDir.directoryEntries;
370   while (idbEntries.hasMoreElements()) {
371     let file = idbEntries.nextFile;
372     if (file.isDirectory()) {
373       return file;
374     }
375   }
377   throw new Error("files directory doesn't exist!");
380 function getView(size) {
381   let buffer = new ArrayBuffer(size);
382   let view = new Uint8Array(buffer);
383   is(buffer.byteLength, size, "Correct byte length");
384   return view;
387 function getRandomView(size) {
388   let view = getView(size);
389   for (let i = 0; i < size; i++) {
390     view[i] = parseInt(Math.random() * 255);
391   }
392   return view;
395 function getBlob(str) {
396   return new Blob([str], { type: "type/text" });
399 function getFile(name, type, str) {
400   return new File([str], name, { type });
403 function isWasmSupported() {
404   let testingFunctions = Cu.getJSTestingFunctions();
405   return testingFunctions.wasmIsSupported();
408 function getWasmModule(binary) {
409   let module = new WebAssembly.Module(binary);
410   return module;
413 function compareBuffers(buffer1, buffer2) {
414   if (buffer1.byteLength != buffer2.byteLength) {
415     return false;
416   }
418   let view1 = buffer1 instanceof Uint8Array ? buffer1 : new Uint8Array(buffer1);
419   let view2 = buffer2 instanceof Uint8Array ? buffer2 : new Uint8Array(buffer2);
420   for (let i = 0; i < buffer1.byteLength; i++) {
421     if (view1[i] != view2[i]) {
422       return false;
423     }
424   }
425   return true;
428 function verifyBuffers(buffer1, buffer2) {
429   ok(compareBuffers(buffer1, buffer2), "Correct buffer data");
432 function verifyBlob(blob1, blob2) {
433   is(Blob.isInstance(blob1), true, "Instance of nsIDOMBlob");
434   is(File.isInstance(blob1), File.isInstance(blob2), "Instance of DOM File");
435   is(blob1.size, blob2.size, "Correct size");
436   is(blob1.type, blob2.type, "Correct type");
437   if (File.isInstance(blob2)) {
438     is(blob1.name, blob2.name, "Correct name");
439   }
441   let buffer1;
442   let buffer2;
444   for (let i = 0; i < bufferCache.length; i++) {
445     if (bufferCache[i].blob == blob2) {
446       buffer2 = bufferCache[i].buffer;
447       break;
448     }
449   }
451   if (!buffer2) {
452     let reader = new FileReader();
453     reader.readAsArrayBuffer(blob2);
454     reader.onload = function(event) {
455       buffer2 = event.target.result;
456       bufferCache.push({ blob: blob2, buffer: buffer2 });
457       if (buffer1) {
458         verifyBuffers(buffer1, buffer2);
459         testGenerator.next();
460       }
461     };
462   }
464   let reader = new FileReader();
465   reader.readAsArrayBuffer(blob1);
466   reader.onload = function(event) {
467     buffer1 = event.target.result;
468     if (buffer2) {
469       verifyBuffers(buffer1, buffer2);
470       testGenerator.next();
471     }
472   };
475 function verifyView(view1, view2) {
476   is(view1.byteLength, view2.byteLength, "Correct byteLength");
477   verifyBuffers(view1, view2);
478   continueToNextStep();
481 function grabFileUsageAndContinueHandler(request) {
482   testGenerator.next(request.result.fileUsage);
485 function getCurrentUsage(usageHandler) {
486   let principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
487     Ci.nsIPrincipal
488   );
489   Services.qms.getUsageForPrincipal(principal, usageHandler);
492 function setTemporaryStorageLimit(limit) {
493   const pref = "dom.quotaManager.temporaryStorage.fixedLimit";
494   if (limit) {
495     info("Setting temporary storage limit to " + limit);
496     SpecialPowers.setIntPref(pref, limit);
497   } else {
498     info("Removing temporary storage limit");
499     SpecialPowers.clearUserPref(pref);
500   }
503 function setDataThreshold(threshold) {
504   info("Setting data threshold to " + threshold);
505   SpecialPowers.setIntPref("dom.indexedDB.dataThreshold", threshold);
508 function resetDataThreshold() {
509   info("Clearing data threshold pref");
510   SpecialPowers.clearUserPref("dom.indexedDB.dataThreshold");
513 function setMaxSerializedMsgSize(aSize) {
514   info("Setting maximal size of a serialized message to " + aSize);
515   SpecialPowers.setIntPref("dom.indexedDB.maxSerializedMsgSize", aSize);
518 function enablePreprocessing() {
519   info("Setting preprocessing pref");
520   SpecialPowers.setBoolPref("dom.indexedDB.preprocessing", true);
523 function resetPreprocessing() {
524   info("Clearing preprocessing pref");
525   SpecialPowers.clearUserPref("dom.indexedDB.preprocessing");
528 function getSystemPrincipal() {
529   return Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
532 function getPrincipal(url) {
533   let uri = Services.io.newURI(url);
534   return Services.scriptSecurityManager.createContentPrincipal(uri, {});
537 class RequestError extends Error {
538   constructor(resultCode, resultName) {
539     super(`Request failed (code: ${resultCode}, name: ${resultName})`);
540     this.name = "RequestError";
541     this.resultCode = resultCode;
542     this.resultName = resultName;
543   }
546 async function requestFinished(request) {
547   await new Promise(function(resolve) {
548     request.callback = function() {
549       resolve();
550     };
551   });
553   if (request.resultCode !== Cr.NS_OK) {
554     throw new RequestError(request.resultCode, request.resultName);
555   }
557   return request.result;
560 // TODO: Rename to openDBRequestSucceeded ?
561 function expectingSuccess(request) {
562   return new Promise(function(resolve, reject) {
563     request.onerror = function(event) {
564       ok(false, "indexedDB error, '" + event.target.error.name + "'");
565       reject(event);
566     };
567     request.onsuccess = function(event) {
568       resolve(event);
569     };
570     request.onupgradeneeded = function(event) {
571       ok(false, "Got upgrade, but did not expect it!");
572       reject(event);
573     };
574   });
577 // TODO: Rename to openDBRequestUpgradeNeeded ?
578 function expectingUpgrade(request) {
579   return new Promise(function(resolve, reject) {
580     request.onerror = function(event) {
581       ok(false, "indexedDB error, '" + event.target.error.name + "'");
582       reject(event);
583     };
584     request.onupgradeneeded = function(event) {
585       resolve(event);
586     };
587     request.onsuccess = function(event) {
588       ok(false, "Got success, but did not expect it!");
589       reject(event);
590     };
591   });
594 function requestSucceeded(request) {
595   return new Promise(function(resolve, reject) {
596     request.onerror = function(event) {
597       ok(false, "indexedDB error, '" + event.target.error.name + "'");
598       reject(event);
599     };
600     request.onsuccess = function(event) {
601       resolve(event);
602     };
603   });
606 // Given a "/"-delimited path relative to the profile directory,
607 // return an nsIFile representing the path.  This does not test
608 // for the existence of the file or parent directories.
609 // It is safe even on Windows where the directory separator is not "/",
610 // but make sure you're not passing in a "\"-delimited path.
611 function getRelativeFile(relativePath) {
612   let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
614   let file = profileDir.clone();
615   relativePath.split("/").forEach(function(component) {
616     file.append(component);
617   });
619   return file;
622 var SpecialPowers = {
623   isMainProcess() {
624     return (
625       Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
626     );
627   },
628   notifyObservers(subject, topic, data) {
629     Services.obs.notifyObservers(subject, topic, data);
630   },
631   notifyObserversInParentProcess(subject, topic, data) {
632     if (subject) {
633       throw new Error("Can't send subject to another process!");
634     }
635     return this.notifyObservers(subject, topic, data);
636   },
637   getBoolPref(prefName) {
638     return Services.prefs.getBoolPref(prefName);
639   },
640   setBoolPref(prefName, value) {
641     Services.prefs.setBoolPref(prefName, value);
642   },
643   setIntPref(prefName, value) {
644     Services.prefs.setIntPref(prefName, value);
645   },
646   clearUserPref(prefName) {
647     Services.prefs.clearUserPref(prefName);
648   },
649   // Copied (and slightly adjusted) from testing/specialpowers/content/SpecialPowersAPI.jsm
650   exactGC(callback) {
651     let count = 0;
653     function doPreciseGCandCC() {
654       function scheduledGCCallback() {
655         Cu.forceCC();
657         if (++count < 3) {
658           doPreciseGCandCC();
659         } else {
660           callback();
661         }
662       }
664       Cu.schedulePreciseGC(scheduledGCCallback);
665     }
667     doPreciseGCandCC();
668   },
670   get Cc() {
671     return Cc;
672   },
674   get Ci() {
675     return Ci;
676   },
678   get Cu() {
679     return Cu;
680   },
682   // Based on SpecialPowersObserver.prototype.receiveMessage
683   createFiles(requests, callback) {
684     let filePaths = [];
685     if (!this._createdFiles) {
686       this._createdFiles = [];
687     }
688     let createdFiles = this._createdFiles;
689     let promises = [];
690     requests.forEach(function(request) {
691       const filePerms = 0o666;
692       let testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
693       if (request.name) {
694         testFile.append(request.name);
695       } else {
696         testFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, filePerms);
697       }
698       let outStream = Cc[
699         "@mozilla.org/network/file-output-stream;1"
700       ].createInstance(Ci.nsIFileOutputStream);
701       outStream.init(
702         testFile,
703         0x02 | 0x08 | 0x20, // PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE
704         filePerms,
705         0
706       );
707       if (request.data) {
708         outStream.write(request.data, request.data.length);
709         outStream.close();
710       }
711       promises.push(
712         File.createFromFileName(testFile.path, request.options).then(function(
713           file
714         ) {
715           filePaths.push(file);
716         })
717       );
718       createdFiles.push(testFile);
719     });
721     Promise.all(promises).then(function() {
722       setTimeout(function() {
723         callback(filePaths);
724       }, 0);
725     });
726   },
728   removeFiles() {
729     if (this._createdFiles) {
730       this._createdFiles.forEach(function(testFile) {
731         try {
732           testFile.remove(false);
733         } catch (e) {}
734       });
735       this._createdFiles = null;
736     }
737   },