diff options
Diffstat (limited to 'netwerk/test/unit/test_pinned_app_cache.js')
-rw-r--r-- | netwerk/test/unit/test_pinned_app_cache.js | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/netwerk/test/unit/test_pinned_app_cache.js b/netwerk/test/unit/test_pinned_app_cache.js new file mode 100644 index 000000000..39b1c764a --- /dev/null +++ b/netwerk/test/unit/test_pinned_app_cache.js @@ -0,0 +1,277 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* + * This testcase performs 3 requests against the offline cache. They + * are + * + * - start_cache_nonpinned_app1() + * + * - Request nsOfflineCacheService to skip pages (4) of app1 on + * the cache storage. + * + * - The offline cache storage is empty at this monent. + * + * - start_cache_nonpinned_app2_for_partial() + * + * - Request nsOfflineCacheService to skip pages of app2 on the + * cache storage. + * + * - The offline cache storage has only enough space for one more + * additional page. Only first of pages is really in the cache. + * + * - start_cache_pinned_app2_for_success() + * + * - Request nsOfflineCacheService to skip pages of app2 on the + * cache storage. + * + * - The offline cache storage has only enough space for one + * additional page. But, this is a pinned request, + * nsOfflineCacheService will make more space for this request + * by discarding app1 (non-pinned) + * + */ + +Cu.import("resource://testing-common/httpd.js"); + +// const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); + +const kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID = + "@mozilla.org/offlinecacheupdate-service;1"; + +const kManifest1 = "CACHE MANIFEST\n" + + "/pages/foo1\n" + + "/pages/foo2\n" + + "/pages/foo3\n" + + "/pages/foo4\n"; +const kManifest2 = "CACHE MANIFEST\n" + + "/pages/foo5\n" + + "/pages/foo6\n" + + "/pages/foo7\n" + + "/pages/foo8\n"; + +const kDataFileSize = 1024; // file size for each content page +const kCacheSize = kDataFileSize * 5; // total space for offline cache storage + +XPCOMUtils.defineLazyGetter(this, "kHttpLocation", function() { + return "http://localhost:" + httpServer.identity.primaryPort + "/"; +}); + +XPCOMUtils.defineLazyGetter(this, "kHttpLocation_ip", function() { + return "http://127.0.0.1:" + httpServer.identity.primaryPort + "/"; +}); + +function manifest1_handler(metadata, response) { + do_print("manifest1\n"); + response.setHeader("content-type", "text/cache-manifest"); + + response.write(kManifest1); +} + +function manifest2_handler(metadata, response) { + do_print("manifest2\n"); + response.setHeader("content-type", "text/cache-manifest"); + + response.write(kManifest2); +} + +function app_handler(metadata, response) { + do_print("app_handler\n"); + response.setHeader("content-type", "text/html"); + + response.write("<html></html>"); +} + +function datafile_handler(metadata, response) { + do_print("datafile_handler\n"); + let data = ""; + + while(data.length < kDataFileSize) { + data = data + Math.random().toString(36).substring(2, 15); + } + + response.setHeader("content-type", "text/plain"); + response.write(data.substring(0, kDataFileSize)); +} + +var httpServer; + +function init_profile() { + var ps = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch); + dump(ps.getBoolPref("browser.cache.offline.enable")); + ps.setBoolPref("browser.cache.offline.enable", true); + ps.setComplexValue("browser.cache.offline.parent_directory", + Ci.nsILocalFile, do_get_profile()); +} + +function init_http_server() { + httpServer = new HttpServer(); + httpServer.registerPathHandler("/app1", app_handler); + httpServer.registerPathHandler("/app2", app_handler); + httpServer.registerPathHandler("/app1.appcache", manifest1_handler); + httpServer.registerPathHandler("/app2.appcache", manifest2_handler); + for (i = 1; i <= 8; i++) { + httpServer.registerPathHandler("/pages/foo" + i, datafile_handler); + } + httpServer.start(-1); +} + +function init_cache_capacity() { + let prefs = Cc["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + prefs.setIntPref("browser.cache.offline.capacity", kCacheSize / 1024); +} + +function clean_app_cache() { + evict_cache_entries("appcache"); +} + +function do_app_cache(manifestURL, pageURL, pinned) { + let update_service = Cc[kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID]. + getService(Ci.nsIOfflineCacheUpdateService); + + Services.perms.add(manifestURL, + "pin-app", + pinned ? + Ci.nsIPermissionManager.ALLOW_ACTION : + Ci.nsIPermissionManager.DENY_ACTION); + + let update = + update_service.scheduleUpdate(manifestURL, + pageURL, + Services.scriptSecurityManager.getSystemPrincipal(), + null); /* no window */ + + return update; +} + +function watch_update(update, stateChangeHandler, cacheAvailHandler) { + let observer = { + QueryInterface: function QueryInterface(iftype) { + return this; + }, + + updateStateChanged: stateChangeHandler, + applicationCacheAvailable: cacheAvailHandler + }; + update.addObserver(observer, false); + + return update; +} + +function start_and_watch_app_cache(manifestURL, + pageURL, + pinned, + stateChangeHandler, + cacheAvailHandler) { + let ioService = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + let update = do_app_cache(ioService.newURI(manifestURL, null, null), + ioService.newURI(pageURL, null, null), + pinned); + watch_update(update, stateChangeHandler, cacheAvailHandler); + return update; +} + +const {STATE_FINISHED: STATE_FINISHED, + STATE_CHECKING: STATE_CHECKING, + STATE_ERROR: STATE_ERROR } = Ci.nsIOfflineCacheUpdateObserver; + +/* + * Start caching app1 as a non-pinned app. + */ +function start_cache_nonpinned_app() { + do_print("Start non-pinned App1"); + start_and_watch_app_cache(kHttpLocation + "app1.appcache", + kHttpLocation + "app1", + false, + function (update, state) { + switch(state) { + case STATE_FINISHED: + start_cache_nonpinned_app2_for_partial(); + break; + + case STATE_ERROR: + do_throw("App1 cache state = " + state); + break; + } + }, + function (appcahe) { + do_print("app1 avail " + appcache + "\n"); + }); +} + +/* + * Start caching app2 as a non-pinned app. + * + * This cache request is supposed to be saved partially in the cache + * storage for running out of the cache storage. The offline cache + * storage can hold 5 files at most. (kDataFileSize bytes for each + * file) + */ +function start_cache_nonpinned_app2_for_partial() { + let error_count = [0]; + do_print("Start non-pinned App2 for partial\n"); + start_and_watch_app_cache(kHttpLocation_ip + "app2.appcache", + kHttpLocation_ip + "app2", + false, + function (update, state) { + switch(state) { + case STATE_FINISHED: + start_cache_pinned_app2_for_success(); + break; + + case STATE_ERROR: + do_throw("App2 cache state = " + state); + break; + } + }, + function (appcahe) { + }); +} + +/* + * Start caching app2 as a pinned app. + * + * This request use IP address (127.0.0.1) as the host name instead of + * the one used by app1. Because, app1 is also pinned when app2 is + * pinned if they have the same host name (localhost). + */ +function start_cache_pinned_app2_for_success() { + let error_count = [0]; + do_print("Start pinned App2 for success\n"); + start_and_watch_app_cache(kHttpLocation_ip + "app2.appcache", + kHttpLocation_ip + "app2", + true, + function (update, state) { + switch(state) { + case STATE_FINISHED: + do_check_true(error_count[0] == 0, + "Do not discard app1?"); + httpServer.stop(do_test_finished); + break; + + case STATE_ERROR: + do_print("STATE_ERROR\n"); + error_count[0]++; + break; + } + }, + function (appcahe) { + do_print("app2 avail " + appcache + "\n"); + }); +} + +function run_test() { + if (typeof _XPCSHELL_PROCESS == "undefined" || + _XPCSHELL_PROCESS != "child") { + init_profile(); + init_cache_capacity(); + clean_app_cache(); + } + + init_http_server(); + start_cache_nonpinned_app(); + do_test_pending(); +} |