diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/tests/mochitest/ajax/offline/offlineTests.js | |
parent | Initial commit. (diff) | |
download | firefox-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.js | 390 |
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); +} + +}; |