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