summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/ajax/offline/offlineTests.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/tests/mochitest/ajax/offline/offlineTests.js
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/tests/mochitest/ajax/offline/offlineTests.js')
-rw-r--r--dom/tests/mochitest/ajax/offline/offlineTests.js390
1 files changed, 390 insertions, 0 deletions
diff --git a/dom/tests/mochitest/ajax/offline/offlineTests.js b/dom/tests/mochitest/ajax/offline/offlineTests.js
new file mode 100644
index 0000000000..eb03f25f0a
--- /dev/null
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -0,0 +1,390 @@
+// Utility functions for offline tests.
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+var Cu = SpecialPowers.Cu;
+var LoadContextInfo = Cc["@mozilla.org/load-context-info-factory;1"].getService(Ci.nsILoadContextInfoFactory);
+var CommonUtils = Cu.import("resource://services-common/utils.js", {}).CommonUtils;
+
+const kNetBase = 2152398848; // 0x804B0000
+var NS_ERROR_CACHE_KEY_NOT_FOUND = kNetBase + 61;
+var NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION = kNetBase + 64;
+
+// Reading the contents of multiple cache entries asynchronously
+function OfflineCacheContents(urls) {
+ this.urls = urls;
+ this.contents = {};
+}
+
+OfflineCacheContents.prototype = {
+QueryInterface: function(iid) {
+ if (!iid.equals(Ci.nsISupports) &&
+ !iid.equals(Ci.nsICacheEntryOpenCallback)) {
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+ return this;
+ },
+onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+onCacheEntryAvailable: function(desc, isnew, applicationCache, status) {
+ if (!desc) {
+ this.fetch(this.callback);
+ return;
+ }
+
+ var stream = desc.openInputStream(0);
+ var sstream = Cc["@mozilla.org/scriptableinputstream;1"]
+ .createInstance(SpecialPowers.Ci.nsIScriptableInputStream);
+ sstream.init(stream);
+ this.contents[desc.key] = sstream.read(sstream.available());
+ sstream.close();
+ desc.close();
+ this.fetch(this.callback);
+ },
+
+fetch: function(callback)
+{
+ this.callback = callback;
+ if (this.urls.length == 0) {
+ callback(this.contents);
+ return;
+ }
+
+ var url = this.urls.shift();
+ var self = this;
+
+ var cacheStorage = OfflineTest.getActiveStorage();
+ cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY,
+ SpecialPowers.wrapCallbackObject(this));
+}
+};
+
+var OfflineTest = {
+
+_hasSlave: false,
+
+// The window where test results should be sent.
+_masterWindow: null,
+
+// Array of all PUT overrides on the server
+_pathOverrides: [],
+
+// SJSs whom state was changed to be reverted on teardown
+_SJSsStated: [],
+
+setupChild: function()
+{
+ this._masterWindow = window;
+ return true;
+},
+
+/**
+ * Setup the tests. This will reload the current page in a new window
+ * if necessary.
+ *
+ * @return boolean Whether this window is the slave window
+ * to actually run the test in.
+ */
+setup: function()
+{
+ this._masterWindow = window;
+ return true;
+},
+
+teardownAndFinish: function()
+{
+ this.teardown(function(self) { self.finish(); });
+},
+
+teardown: function(callback)
+{
+ // First wait for any pending scheduled updates to finish
+ this.waitForUpdates(function(self) {
+ // Remove the offline-app permission we gave ourselves.
+
+ SpecialPowers.removePermission("offline-app", window.document);
+
+ // Clear all overrides on the server
+ for (override in self._pathOverrides)
+ self.deleteData(self._pathOverrides[override]);
+ for (statedSJS in self._SJSsStated)
+ self.setSJSState(self._SJSsStated[statedSJS], "");
+
+ self.clear();
+ callback(self);
+ });
+},
+
+finish: function()
+{
+ SimpleTest.executeSoon(SimpleTest.finish);
+},
+
+//
+// Mochitest wrappers - These forward tests to the proper mochitest window.
+//
+ok: function(condition, name)
+{
+ // Forward all arguments to SimpleTest.ok where we will check that ok() was
+ // called with at most 2 arguments.
+ return this._masterWindow.SimpleTest.ok.apply(this._masterWindow.SimpleTest,
+ arguments);
+},
+
+is: function(a, b, name)
+{
+ return this._masterWindow.SimpleTest.is(a, b, name);
+},
+
+isnot: function(a, b, name)
+{
+ return this._masterWindow.SimpleTest.isnot(a, b, name);
+},
+
+todo: function(a, name)
+{
+ return this._masterWindow.SimpleTest.todo(a, name);
+},
+
+clear: function()
+{
+ // XXX: maybe we should just wipe out the entire disk cache.
+ var applicationCache = this.getActiveCache();
+ if (applicationCache) {
+ applicationCache.discard();
+ }
+},
+
+waitForUpdates: function(callback)
+{
+ var self = this;
+ var observer = {
+ notified: false,
+ observe: function(subject, topic, data) {
+ if (subject) {
+ subject.QueryInterface(SpecialPowers.Ci.nsIOfflineCacheUpdate);
+ dump("Update of " + subject.manifestURI.spec + " finished\n");
+ }
+
+ SimpleTest.executeSoon(function() {
+ if (observer.notified) {
+ return;
+ }
+
+ var updateservice = Cc["@mozilla.org/offlinecacheupdate-service;1"]
+ .getService(SpecialPowers.Ci.nsIOfflineCacheUpdateService);
+ var updatesPending = updateservice.numUpdates;
+ if (updatesPending == 0) {
+ try {
+ SpecialPowers.removeObserver(observer, "offline-cache-update-completed");
+ } catch(ex) {}
+ dump("All pending updates done\n");
+ observer.notified = true;
+ callback(self);
+ return;
+ }
+
+ dump("Waiting for " + updateservice.numUpdates + " update(s) to finish\n");
+ });
+ }
+ }
+
+ SpecialPowers.addObserver(observer, "offline-cache-update-completed", false);
+
+ // Call now to check whether there are some updates scheduled
+ observer.observe();
+},
+
+failEvent: function(e)
+{
+ OfflineTest.ok(false, "Unexpected event: " + e.type);
+},
+
+// The offline API as specified has no way to watch the load of a resource
+// added with applicationCache.mozAdd().
+waitForAdd: function(url, onFinished) {
+ // Check every half second for ten seconds.
+ var numChecks = 20;
+
+ var waitForAddListener = SpecialPowers.wrapCallbackObject({
+ onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+ onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
+ if (entry) {
+ entry.close();
+ onFinished();
+ return;
+ }
+
+ if (--numChecks == 0) {
+ onFinished();
+ return;
+ }
+
+ setTimeout(OfflineTest.priv(waitFunc), 500);
+ }
+ });
+
+ var waitFunc = function() {
+ var cacheStorage = OfflineTest.getActiveStorage();
+ cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, waitForAddListener);
+ }
+
+ setTimeout(this.priv(waitFunc), 500);
+},
+
+manifestURL: function(overload)
+{
+ var manifestURLspec;
+ if (overload) {
+ manifestURLspec = overload;
+ } else {
+ var win = window;
+ while (win && !win.document.documentElement.getAttribute("manifest")) {
+ if (win == win.parent)
+ break;
+ win = win.parent;
+ }
+ if (win)
+ manifestURLspec = win.document.documentElement.getAttribute("manifest");
+ }
+
+ var ios = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService)
+
+ var baseURI = ios.newURI(window.location.href);
+ return ios.newURI(manifestURLspec, null, baseURI);
+},
+
+loadContext: function()
+{
+ return SpecialPowers.wrap(window).docShell
+ .QueryInterface(SpecialPowers.Ci.nsILoadContext);
+},
+
+loadContextInfo: function()
+{
+ return LoadContextInfo.fromLoadContext(this.loadContext(), false);
+},
+
+getActiveCache: function(overload)
+{
+ // Note that this is the current active cache in the cache stack, not the
+ // one associated with this window.
+ var serv = Cc["@mozilla.org/network/application-cache-service;1"]
+ .getService(Ci.nsIApplicationCacheService);
+
+ var groupID = serv.buildGroupIDForInfo(this.manifestURL(overload), this.loadContextInfo());
+ var cache;
+ // Sometimes this throws a NS_ERROR_UNEXPECTED when cache isn't init
+ try {
+ cache = serv.getActiveCache(groupID);
+ } catch (e) {
+ cache = false;
+ }
+ return cache;
+},
+
+getActiveStorage: function()
+{
+ var cache = this.getActiveCache();
+ if (!cache) {
+ return null;
+ }
+
+ var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+ .getService(Ci.nsICacheStorageService);
+ return cacheService.appCacheStorage(LoadContextInfo.default, cache);
+},
+
+priv: function(func)
+{
+ var self = this;
+ return function() {
+ func(arguments);
+ }
+},
+
+checkCacheEntries: function(entries, callback)
+{
+ var checkNextEntry = function() {
+ if (entries.length == 0) {
+ setTimeout(OfflineTest.priv(callback), 0);
+ } else {
+ OfflineTest.checkCache(entries[0][0], entries[0][1], checkNextEntry);
+ entries.shift();
+ }
+ }
+
+ checkNextEntry();
+},
+
+checkCache: function(url, expectEntry, callback)
+{
+ var cacheStorage = this.getActiveStorage();
+ this._checkCache(cacheStorage, url, expectEntry, callback);
+},
+
+_checkCache: function(cacheStorage, url, expectEntry, callback)
+{
+ if (!cacheStorage) {
+ if (expectEntry) {
+ this.ok(false, url + " should exist in the offline cache (no session)");
+ } else {
+ this.ok(true, url + " should not exist in the offline cache (no session)");
+ }
+ if (callback) setTimeout(this.priv(callback), 0);
+ return;
+ }
+
+ var _checkCacheListener = SpecialPowers.wrapCallbackObject({
+ onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+ onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
+ if (entry) {
+ if (expectEntry) {
+ OfflineTest.ok(true, url + " should exist in the offline cache");
+ } else {
+ OfflineTest.ok(false, url + " should not exist in the offline cache");
+ }
+ entry.close();
+ } else {
+ if (status == NS_ERROR_CACHE_KEY_NOT_FOUND) {
+ if (expectEntry) {
+ OfflineTest.ok(false, url + " should exist in the offline cache");
+ } else {
+ OfflineTest.ok(true, url + " should not exist in the offline cache");
+ }
+ } else if (status == NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION) {
+ // There was a cache key that we couldn't access yet, that's good enough.
+ if (expectEntry) {
+ OfflineTest.ok(!mustBeValid, url + " should exist in the offline cache");
+ } else {
+ OfflineTest.ok(mustBeValid, url + " should not exist in the offline cache");
+ }
+ } else {
+ OfflineTest.ok(false, "got invalid error for " + url);
+ }
+ }
+ if (callback) setTimeout(OfflineTest.priv(callback), 0);
+ }
+ });
+
+ cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, _checkCacheListener);
+},
+
+setSJSState: function(sjsPath, stateQuery)
+{
+ var client = new XMLHttpRequest();
+ client.open("GET", sjsPath + "?state=" + stateQuery, false);
+
+ var appcachechannel = SpecialPowers.wrap(client).channel.QueryInterface(Ci.nsIApplicationCacheChannel);
+ appcachechannel.chooseApplicationCache = false;
+ appcachechannel.inheritApplicationCache = false;
+ appcachechannel.applicationCache = null;
+
+ client.send();
+
+ if (stateQuery == "")
+ delete this._SJSsStated[sjsPath];
+ else
+ this._SJSsStated.push(sjsPath);
+}
+
+};