1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/test/unit/test_pinned_app_cache.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,276 @@ 1.4 +/* -*- Mode: Javasript; indent-tab-mode: nil; js-indent-level: 2 -*- */ 1.5 +/* 1.6 + * This testcase performs 3 requests against the offline cache. They 1.7 + * are 1.8 + * 1.9 + * - start_cache_nonpinned_app1() 1.10 + * 1.11 + * - Request nsOfflineCacheService to skip pages (4) of app1 on 1.12 + * the cache storage. 1.13 + * 1.14 + * - The offline cache storage is empty at this monent. 1.15 + * 1.16 + * - start_cache_nonpinned_app2_for_partial() 1.17 + * 1.18 + * - Request nsOfflineCacheService to skip pages of app2 on the 1.19 + * cache storage. 1.20 + * 1.21 + * - The offline cache storage has only enough space for one more 1.22 + * additional page. Only first of pages is really in the cache. 1.23 + * 1.24 + * - start_cache_pinned_app2_for_success() 1.25 + * 1.26 + * - Request nsOfflineCacheService to skip pages of app2 on the 1.27 + * cache storage. 1.28 + * 1.29 + * - The offline cache storage has only enough space for one 1.30 + * additional page. But, this is a pinned request, 1.31 + * nsOfflineCacheService will make more space for this request 1.32 + * by discarding app1 (non-pinned) 1.33 + * 1.34 + */ 1.35 + 1.36 +Cu.import("resource://testing-common/httpd.js"); 1.37 + 1.38 +// const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; 1.39 + 1.40 +Cu.import("resource://gre/modules/Services.jsm"); 1.41 + 1.42 +const kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID = 1.43 + "@mozilla.org/offlinecacheupdate-service;1"; 1.44 + 1.45 +const kManifest1 = "CACHE MANIFEST\n" + 1.46 + "/pages/foo1\n" + 1.47 + "/pages/foo2\n" + 1.48 + "/pages/foo3\n" + 1.49 + "/pages/foo4\n"; 1.50 +const kManifest2 = "CACHE MANIFEST\n" + 1.51 + "/pages/foo5\n" + 1.52 + "/pages/foo6\n" + 1.53 + "/pages/foo7\n" + 1.54 + "/pages/foo8\n"; 1.55 + 1.56 +const kDataFileSize = 1024; // file size for each content page 1.57 +const kCacheSize = kDataFileSize * 5; // total space for offline cache storage 1.58 + 1.59 +XPCOMUtils.defineLazyGetter(this, "kHttpLocation", function() { 1.60 + return "http://localhost:" + httpServer.identity.primaryPort + "/"; 1.61 +}); 1.62 + 1.63 +XPCOMUtils.defineLazyGetter(this, "kHttpLocation_ip", function() { 1.64 + return "http://127.0.0.1:" + httpServer.identity.primaryPort + "/"; 1.65 +}); 1.66 + 1.67 +function manifest1_handler(metadata, response) { 1.68 + do_print("manifest1\n"); 1.69 + response.setHeader("content-type", "text/cache-manifest"); 1.70 + 1.71 + response.write(kManifest1); 1.72 +} 1.73 + 1.74 +function manifest2_handler(metadata, response) { 1.75 + do_print("manifest2\n"); 1.76 + response.setHeader("content-type", "text/cache-manifest"); 1.77 + 1.78 + response.write(kManifest2); 1.79 +} 1.80 + 1.81 +function app_handler(metadata, response) { 1.82 + do_print("app_handler\n"); 1.83 + response.setHeader("content-type", "text/html"); 1.84 + 1.85 + response.write("<html></html>"); 1.86 +} 1.87 + 1.88 +function datafile_handler(metadata, response) { 1.89 + do_print("datafile_handler\n"); 1.90 + let data = ""; 1.91 + 1.92 + while(data.length < kDataFileSize) { 1.93 + data = data + Math.random().toString(36).substring(2, 15); 1.94 + } 1.95 + 1.96 + response.setHeader("content-type", "text/plain"); 1.97 + response.write(data.substring(0, kDataFileSize)); 1.98 +} 1.99 + 1.100 +var httpServer; 1.101 + 1.102 +function init_profile() { 1.103 + var ps = Cc["@mozilla.org/preferences-service;1"] 1.104 + .getService(Ci.nsIPrefBranch); 1.105 + dump(ps.getBoolPref("browser.cache.offline.enable")); 1.106 + ps.setBoolPref("browser.cache.offline.enable", true); 1.107 + ps.setComplexValue("browser.cache.offline.parent_directory", 1.108 + Ci.nsILocalFile, do_get_profile()); 1.109 +} 1.110 + 1.111 +function init_http_server() { 1.112 + httpServer = new HttpServer(); 1.113 + httpServer.registerPathHandler("/app1", app_handler); 1.114 + httpServer.registerPathHandler("/app2", app_handler); 1.115 + httpServer.registerPathHandler("/app1.appcache", manifest1_handler); 1.116 + httpServer.registerPathHandler("/app2.appcache", manifest2_handler); 1.117 + for (i = 1; i <= 8; i++) { 1.118 + httpServer.registerPathHandler("/pages/foo" + i, datafile_handler); 1.119 + } 1.120 + httpServer.start(-1); 1.121 +} 1.122 + 1.123 +function init_cache_capacity() { 1.124 + let prefs = Cc["@mozilla.org/preferences-service;1"] 1.125 + .getService(Components.interfaces.nsIPrefBranch); 1.126 + prefs.setIntPref("browser.cache.offline.capacity", kCacheSize / 1024); 1.127 +} 1.128 + 1.129 +function clean_app_cache() { 1.130 + evict_cache_entries("appcache"); 1.131 +} 1.132 + 1.133 +function do_app_cache(manifestURL, pageURL, pinned) { 1.134 + let update_service = Cc[kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID]. 1.135 + getService(Ci.nsIOfflineCacheUpdateService); 1.136 + 1.137 + Services.perms.add(manifestURL, 1.138 + "pin-app", 1.139 + pinned ? 1.140 + Ci.nsIPermissionManager.ALLOW_ACTION : 1.141 + Ci.nsIPermissionManager.DENY_ACTION); 1.142 + 1.143 + let update = 1.144 + update_service.scheduleUpdate(manifestURL, 1.145 + pageURL, 1.146 + null); /* no window */ 1.147 + 1.148 + return update; 1.149 +} 1.150 + 1.151 +function watch_update(update, stateChangeHandler, cacheAvailHandler) { 1.152 + let observer = { 1.153 + QueryInterface: function QueryInterface(iftype) { 1.154 + return this; 1.155 + }, 1.156 + 1.157 + updateStateChanged: stateChangeHandler, 1.158 + applicationCacheAvailable: cacheAvailHandler 1.159 + }; 1.160 + update.addObserver(observer, false); 1.161 + 1.162 + return update; 1.163 +} 1.164 + 1.165 +function start_and_watch_app_cache(manifestURL, 1.166 + pageURL, 1.167 + pinned, 1.168 + stateChangeHandler, 1.169 + cacheAvailHandler) { 1.170 + let ioService = Cc["@mozilla.org/network/io-service;1"]. 1.171 + getService(Ci.nsIIOService); 1.172 + let update = do_app_cache(ioService.newURI(manifestURL, null, null), 1.173 + ioService.newURI(pageURL, null, null), 1.174 + pinned); 1.175 + watch_update(update, stateChangeHandler, cacheAvailHandler); 1.176 + return update; 1.177 +} 1.178 + 1.179 +const {STATE_FINISHED: STATE_FINISHED, 1.180 + STATE_CHECKING: STATE_CHECKING, 1.181 + STATE_ERROR: STATE_ERROR } = Ci.nsIOfflineCacheUpdateObserver; 1.182 + 1.183 +/* 1.184 + * Start caching app1 as a non-pinned app. 1.185 + */ 1.186 +function start_cache_nonpinned_app() { 1.187 + do_print("Start non-pinned App1"); 1.188 + start_and_watch_app_cache(kHttpLocation + "app1.appcache", 1.189 + kHttpLocation + "app1", 1.190 + false, 1.191 + function (update, state) { 1.192 + switch(state) { 1.193 + case STATE_FINISHED: 1.194 + start_cache_nonpinned_app2_for_partial(); 1.195 + break; 1.196 + 1.197 + case STATE_ERROR: 1.198 + do_throw("App1 cache state = " + state); 1.199 + break; 1.200 + } 1.201 + }, 1.202 + function (appcahe) { 1.203 + do_print("app1 avail " + appcache + "\n"); 1.204 + }); 1.205 +} 1.206 + 1.207 +/* 1.208 + * Start caching app2 as a non-pinned app. 1.209 + * 1.210 + * This cache request is supposed to be saved partially in the cache 1.211 + * storage for running out of the cache storage. The offline cache 1.212 + * storage can hold 5 files at most. (kDataFileSize bytes for each 1.213 + * file) 1.214 + */ 1.215 +function start_cache_nonpinned_app2_for_partial() { 1.216 + let error_count = [0]; 1.217 + do_print("Start non-pinned App2 for partial\n"); 1.218 + start_and_watch_app_cache(kHttpLocation_ip + "app2.appcache", 1.219 + kHttpLocation_ip + "app2", 1.220 + false, 1.221 + function (update, state) { 1.222 + switch(state) { 1.223 + case STATE_FINISHED: 1.224 + start_cache_pinned_app2_for_success(); 1.225 + break; 1.226 + 1.227 + case STATE_ERROR: 1.228 + do_throw("App2 cache state = " + state); 1.229 + break; 1.230 + } 1.231 + }, 1.232 + function (appcahe) { 1.233 + }); 1.234 +} 1.235 + 1.236 +/* 1.237 + * Start caching app2 as a pinned app. 1.238 + * 1.239 + * This request use IP address (127.0.0.1) as the host name instead of 1.240 + * the one used by app1. Because, app1 is also pinned when app2 is 1.241 + * pinned if they have the same host name (localhost). 1.242 + */ 1.243 +function start_cache_pinned_app2_for_success() { 1.244 + let error_count = [0]; 1.245 + do_print("Start pinned App2 for success\n"); 1.246 + start_and_watch_app_cache(kHttpLocation_ip + "app2.appcache", 1.247 + kHttpLocation_ip + "app2", 1.248 + true, 1.249 + function (update, state) { 1.250 + switch(state) { 1.251 + case STATE_FINISHED: 1.252 + do_check_true(error_count[0] == 0, 1.253 + "Do not discard app1?"); 1.254 + httpServer.stop(do_test_finished); 1.255 + break; 1.256 + 1.257 + case STATE_ERROR: 1.258 + do_print("STATE_ERROR\n"); 1.259 + error_count[0]++; 1.260 + break; 1.261 + } 1.262 + }, 1.263 + function (appcahe) { 1.264 + do_print("app2 avail " + appcache + "\n"); 1.265 + }); 1.266 +} 1.267 + 1.268 +function run_test() { 1.269 + if (typeof _XPCSHELL_PROCESS == "undefined" || 1.270 + _XPCSHELL_PROCESS != "child") { 1.271 + init_profile(); 1.272 + init_cache_capacity(); 1.273 + clean_app_cache(); 1.274 + } 1.275 + 1.276 + init_http_server(); 1.277 + start_cache_nonpinned_app(); 1.278 + do_test_pending(); 1.279 +}