michael@0: /* -*- Mode: Javasript; indent-tab-mode: nil; js-indent-level: 2 -*- */ michael@0: michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: michael@0: /** michael@0: * This is testcase do following steps to make sure bug767025 removing michael@0: * files as expection. michael@0: * michael@0: * STEPS: michael@0: * - Schedule a offline cache update for app.manifest. michael@0: * - pages/foo1, pages/foo2, pages/foo3, and pages/foo4 are cached. michael@0: * - Activate pages/foo1 michael@0: * - Doom pages/foo1, and pages/foo2. michael@0: * - pages/foo1 should keep alive while pages/foo2 was gone. michael@0: * - Activate pages/foo3 michael@0: * - Evict all documents. michael@0: * - all documents except pages/foo1 are gone since pages/foo1 & pages/foo3 michael@0: * are activated. michael@0: */ michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: const kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID = michael@0: "@mozilla.org/offlinecacheupdate-service;1"; michael@0: const kNS_CACHESERVICE_CONTRACTID = michael@0: "@mozilla.org/network/cache-service;1"; michael@0: const kNS_APPLICATIONCACHESERVICE_CONTRACTID = michael@0: "@mozilla.org/network/application-cache-service;1"; michael@0: michael@0: const kManifest = "CACHE MANIFEST\n" + michael@0: "/pages/foo1\n" + michael@0: "/pages/foo2\n" + michael@0: "/pages/foo3\n" + michael@0: "/pages/foo4\n"; michael@0: michael@0: const kDataFileSize = 1024; // file size for each content page michael@0: const kHttpLocation = "http://localhost:4444/"; michael@0: michael@0: function manifest_handler(metadata, response) { michael@0: do_print("manifest\n"); michael@0: response.setHeader("content-type", "text/cache-manifest"); michael@0: michael@0: response.write(kManifest); michael@0: } michael@0: michael@0: function datafile_handler(metadata, response) { michael@0: do_print("datafile_handler\n"); michael@0: let data = ""; michael@0: michael@0: while(data.length < kDataFileSize) { michael@0: data = data + Math.random().toString(36).substring(2, 15); michael@0: } michael@0: michael@0: response.setHeader("content-type", "text/plain"); michael@0: response.write(data.substring(0, kDataFileSize)); michael@0: } michael@0: michael@0: function app_handler(metadata, response) { michael@0: do_print("app_handler\n"); michael@0: response.setHeader("content-type", "text/html"); michael@0: michael@0: response.write(""); michael@0: } michael@0: michael@0: var httpServer; michael@0: michael@0: function init_profile() { michael@0: var ps = Cc["@mozilla.org/preferences-service;1"] michael@0: .getService(Ci.nsIPrefBranch); michael@0: dump(ps.getBoolPref("browser.cache.offline.enable")); michael@0: ps.setBoolPref("browser.cache.offline.enable", true); michael@0: ps.setComplexValue("browser.cache.offline.parent_directory", michael@0: Ci.nsILocalFile, do_get_profile()); michael@0: do_print("profile " + do_get_profile()); michael@0: } michael@0: michael@0: function init_http_server() { michael@0: httpServer = new HttpServer(); michael@0: httpServer.registerPathHandler("/app.appcache", manifest_handler); michael@0: httpServer.registerPathHandler("/app", app_handler); michael@0: for (i = 1; i <= 4; i++) { michael@0: httpServer.registerPathHandler("/pages/foo" + i, datafile_handler); michael@0: } michael@0: httpServer.start(4444); michael@0: } michael@0: michael@0: function clean_app_cache() { michael@0: let cache_service = Cc[kNS_CACHESERVICE_CONTRACTID]. michael@0: getService(Ci.nsICacheService); michael@0: cache_service.evictEntries(Ci.nsICache.STORE_OFFLINE); michael@0: } michael@0: michael@0: function do_app_cache(manifestURL, pageURL) { michael@0: let update_service = Cc[kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID]. michael@0: getService(Ci.nsIOfflineCacheUpdateService); michael@0: michael@0: Services.perms.add(manifestURL, michael@0: "offline-app", michael@0: Ci.nsIPermissionManager.ALLOW_ACTION); michael@0: michael@0: let update = michael@0: update_service.scheduleUpdate(manifestURL, michael@0: pageURL, michael@0: null); /* no window */ michael@0: michael@0: return update; michael@0: } michael@0: michael@0: function watch_update(update, stateChangeHandler, cacheAvailHandler) { michael@0: let observer = { michael@0: QueryInterface: function QueryInterface(iftype) { michael@0: return this; michael@0: }, michael@0: michael@0: updateStateChanged: stateChangeHandler, michael@0: applicationCacheAvailable: cacheAvailHandler michael@0: };~ michael@0: update.addObserver(observer, false); michael@0: michael@0: return update; michael@0: } michael@0: michael@0: function start_and_watch_app_cache(manifestURL, michael@0: pageURL, michael@0: stateChangeHandler, michael@0: cacheAvailHandler) { michael@0: let ioService = Cc["@mozilla.org/network/io-service;1"]. michael@0: getService(Ci.nsIIOService); michael@0: let update = do_app_cache(ioService.newURI(manifestURL, null, null), michael@0: ioService.newURI(pageURL, null, null)); michael@0: watch_update(update, stateChangeHandler, cacheAvailHandler); michael@0: return update; michael@0: } michael@0: michael@0: const {STATE_FINISHED: STATE_FINISHED, michael@0: STATE_CHECKING: STATE_CHECKING, michael@0: STATE_ERROR: STATE_ERROR } = Ci.nsIOfflineCacheUpdateObserver; michael@0: michael@0: /* michael@0: * Start caching app1 as a non-pinned app. michael@0: */ michael@0: function start_cache_nonpinned_app() { michael@0: do_print("Start non-pinned App1"); michael@0: start_and_watch_app_cache(kHttpLocation + "app.appcache", michael@0: kHttpLocation + "app", michael@0: function (update, state) { michael@0: switch(state) { michael@0: case STATE_FINISHED: michael@0: check_bug(); michael@0: break; michael@0: michael@0: case STATE_ERROR: michael@0: do_throw("App cache state = " + state); michael@0: break; michael@0: } michael@0: }, michael@0: function (appcahe) { michael@0: do_print("app avail " + appcache + "\n"); michael@0: }); michael@0: } michael@0: michael@0: var hold_entry_foo1 = null; michael@0: michael@0: function check_bug() { michael@0: // activate foo1 michael@0: asyncOpenCacheEntry( michael@0: kHttpLocation + "pages/foo1", michael@0: "appcache", Ci.nsICacheStorage.OPEN_READONLY, null, michael@0: function(status, entry, appcache) { michael@0: let storage = get_cache_service().appCacheStorage(LoadContextInfo.default, appcache); michael@0: michael@0: // Doom foo1 & foo2 michael@0: storage.asyncDoomURI(createURI(kHttpLocation + "pages/foo1"), "", { onCacheEntryDoomed: function() { michael@0: storage.asyncDoomURI(createURI(kHttpLocation + "pages/foo2"), "", { onCacheEntryDoomed: function() { michael@0: check_evict_cache(appcache); michael@0: }}); michael@0: }}); michael@0: michael@0: hold_entry_foo1 = entry; michael@0: }); michael@0: } michael@0: michael@0: function check_evict_cache(appcache) { michael@0: // Only foo2 should be removed. michael@0: let file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("5"); michael@0: file.append("9"); michael@0: file.append("8379C6596B8CA4-0"); michael@0: do_check_eq(file.exists(), true); michael@0: michael@0: file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("C"); michael@0: file.append("2"); michael@0: file.append("5F356A168B5E3B-0"); michael@0: do_check_eq(file.exists(), false); michael@0: michael@0: // activate foo3 michael@0: asyncOpenCacheEntry( michael@0: kHttpLocation + "pages/foo3", michael@0: "appcache", Ci.nsICacheStorage.OPEN_READONLY, null, michael@0: function(status, entry, appcache) { michael@0: hold_entry_foo3 = entry; michael@0: michael@0: // evict all documents. michael@0: let storage = get_cache_service().appCacheStorage(LoadContextInfo.default, appcache); michael@0: storage.asyncEvictStorage(null); michael@0: michael@0: // All documents are removed except foo1 & foo3. michael@0: syncWithCacheIOThread(function () { michael@0: // foo1 michael@0: let file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("5"); michael@0: file.append("9"); michael@0: file.append("8379C6596B8CA4-0"); michael@0: do_check_eq(file.exists(), true); michael@0: michael@0: file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("0"); michael@0: file.append("0"); michael@0: file.append("61FEE819921D39-0"); michael@0: do_check_eq(file.exists(), false); michael@0: michael@0: file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("3"); michael@0: file.append("9"); michael@0: file.append("0D8759F1DE5452-0"); michael@0: do_check_eq(file.exists(), false); michael@0: michael@0: file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("C"); michael@0: file.append("2"); michael@0: file.append("5F356A168B5E3B-0"); michael@0: do_check_eq(file.exists(), false); michael@0: michael@0: // foo3 michael@0: file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("D"); michael@0: file.append("C"); michael@0: file.append("1ADCCC843B5C00-0"); michael@0: do_check_eq(file.exists(), true); michael@0: michael@0: file = do_get_profile().clone(); michael@0: file.append("OfflineCache"); michael@0: file.append("F"); michael@0: file.append("0"); michael@0: file.append("FC3E6D6C1164E9-0"); michael@0: do_check_eq(file.exists(), false); michael@0: michael@0: httpServer.stop(do_test_finished); michael@0: }); michael@0: }, michael@0: appcache michael@0: ); michael@0: } michael@0: michael@0: function run_test() { michael@0: if (newCacheBackEndUsed()) { michael@0: // times out on storage.asyncDoomURI @ check_bug because that method is not implemented for appcache michael@0: // either revert the test changes or implement the method (former seems more reasonable) michael@0: do_check_true(true, "This test doesn't run with the new cache backend, the test or the cache needs to be fixed"); michael@0: return; michael@0: } michael@0: michael@0: if (typeof _XPCSHELL_PROCESS == "undefined" || michael@0: _XPCSHELL_PROCESS != "child") { michael@0: init_profile(); michael@0: clean_app_cache(); michael@0: } michael@0: michael@0: init_http_server(); michael@0: start_cache_nonpinned_app(); michael@0: do_test_pending(); michael@0: }