|
1 /* -*- Mode: Javasript; indent-tab-mode: nil; js-indent-level: 2 -*- */ |
|
2 |
|
3 Cu.import("resource://testing-common/httpd.js"); |
|
4 |
|
5 /** |
|
6 * This is testcase do following steps to make sure bug767025 removing |
|
7 * files as expection. |
|
8 * |
|
9 * STEPS: |
|
10 * - Schedule a offline cache update for app.manifest. |
|
11 * - pages/foo1, pages/foo2, pages/foo3, and pages/foo4 are cached. |
|
12 * - Activate pages/foo1 |
|
13 * - Doom pages/foo1, and pages/foo2. |
|
14 * - pages/foo1 should keep alive while pages/foo2 was gone. |
|
15 * - Activate pages/foo3 |
|
16 * - Evict all documents. |
|
17 * - all documents except pages/foo1 are gone since pages/foo1 & pages/foo3 |
|
18 * are activated. |
|
19 */ |
|
20 |
|
21 Cu.import("resource://gre/modules/Services.jsm"); |
|
22 |
|
23 const kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID = |
|
24 "@mozilla.org/offlinecacheupdate-service;1"; |
|
25 const kNS_CACHESERVICE_CONTRACTID = |
|
26 "@mozilla.org/network/cache-service;1"; |
|
27 const kNS_APPLICATIONCACHESERVICE_CONTRACTID = |
|
28 "@mozilla.org/network/application-cache-service;1"; |
|
29 |
|
30 const kManifest = "CACHE MANIFEST\n" + |
|
31 "/pages/foo1\n" + |
|
32 "/pages/foo2\n" + |
|
33 "/pages/foo3\n" + |
|
34 "/pages/foo4\n"; |
|
35 |
|
36 const kDataFileSize = 1024; // file size for each content page |
|
37 const kHttpLocation = "http://localhost:4444/"; |
|
38 |
|
39 function manifest_handler(metadata, response) { |
|
40 do_print("manifest\n"); |
|
41 response.setHeader("content-type", "text/cache-manifest"); |
|
42 |
|
43 response.write(kManifest); |
|
44 } |
|
45 |
|
46 function datafile_handler(metadata, response) { |
|
47 do_print("datafile_handler\n"); |
|
48 let data = ""; |
|
49 |
|
50 while(data.length < kDataFileSize) { |
|
51 data = data + Math.random().toString(36).substring(2, 15); |
|
52 } |
|
53 |
|
54 response.setHeader("content-type", "text/plain"); |
|
55 response.write(data.substring(0, kDataFileSize)); |
|
56 } |
|
57 |
|
58 function app_handler(metadata, response) { |
|
59 do_print("app_handler\n"); |
|
60 response.setHeader("content-type", "text/html"); |
|
61 |
|
62 response.write("<html></html>"); |
|
63 } |
|
64 |
|
65 var httpServer; |
|
66 |
|
67 function init_profile() { |
|
68 var ps = Cc["@mozilla.org/preferences-service;1"] |
|
69 .getService(Ci.nsIPrefBranch); |
|
70 dump(ps.getBoolPref("browser.cache.offline.enable")); |
|
71 ps.setBoolPref("browser.cache.offline.enable", true); |
|
72 ps.setComplexValue("browser.cache.offline.parent_directory", |
|
73 Ci.nsILocalFile, do_get_profile()); |
|
74 do_print("profile " + do_get_profile()); |
|
75 } |
|
76 |
|
77 function init_http_server() { |
|
78 httpServer = new HttpServer(); |
|
79 httpServer.registerPathHandler("/app.appcache", manifest_handler); |
|
80 httpServer.registerPathHandler("/app", app_handler); |
|
81 for (i = 1; i <= 4; i++) { |
|
82 httpServer.registerPathHandler("/pages/foo" + i, datafile_handler); |
|
83 } |
|
84 httpServer.start(4444); |
|
85 } |
|
86 |
|
87 function clean_app_cache() { |
|
88 let cache_service = Cc[kNS_CACHESERVICE_CONTRACTID]. |
|
89 getService(Ci.nsICacheService); |
|
90 cache_service.evictEntries(Ci.nsICache.STORE_OFFLINE); |
|
91 } |
|
92 |
|
93 function do_app_cache(manifestURL, pageURL) { |
|
94 let update_service = Cc[kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID]. |
|
95 getService(Ci.nsIOfflineCacheUpdateService); |
|
96 |
|
97 Services.perms.add(manifestURL, |
|
98 "offline-app", |
|
99 Ci.nsIPermissionManager.ALLOW_ACTION); |
|
100 |
|
101 let update = |
|
102 update_service.scheduleUpdate(manifestURL, |
|
103 pageURL, |
|
104 null); /* no window */ |
|
105 |
|
106 return update; |
|
107 } |
|
108 |
|
109 function watch_update(update, stateChangeHandler, cacheAvailHandler) { |
|
110 let observer = { |
|
111 QueryInterface: function QueryInterface(iftype) { |
|
112 return this; |
|
113 }, |
|
114 |
|
115 updateStateChanged: stateChangeHandler, |
|
116 applicationCacheAvailable: cacheAvailHandler |
|
117 };~ |
|
118 update.addObserver(observer, false); |
|
119 |
|
120 return update; |
|
121 } |
|
122 |
|
123 function start_and_watch_app_cache(manifestURL, |
|
124 pageURL, |
|
125 stateChangeHandler, |
|
126 cacheAvailHandler) { |
|
127 let ioService = Cc["@mozilla.org/network/io-service;1"]. |
|
128 getService(Ci.nsIIOService); |
|
129 let update = do_app_cache(ioService.newURI(manifestURL, null, null), |
|
130 ioService.newURI(pageURL, null, null)); |
|
131 watch_update(update, stateChangeHandler, cacheAvailHandler); |
|
132 return update; |
|
133 } |
|
134 |
|
135 const {STATE_FINISHED: STATE_FINISHED, |
|
136 STATE_CHECKING: STATE_CHECKING, |
|
137 STATE_ERROR: STATE_ERROR } = Ci.nsIOfflineCacheUpdateObserver; |
|
138 |
|
139 /* |
|
140 * Start caching app1 as a non-pinned app. |
|
141 */ |
|
142 function start_cache_nonpinned_app() { |
|
143 do_print("Start non-pinned App1"); |
|
144 start_and_watch_app_cache(kHttpLocation + "app.appcache", |
|
145 kHttpLocation + "app", |
|
146 function (update, state) { |
|
147 switch(state) { |
|
148 case STATE_FINISHED: |
|
149 check_bug(); |
|
150 break; |
|
151 |
|
152 case STATE_ERROR: |
|
153 do_throw("App cache state = " + state); |
|
154 break; |
|
155 } |
|
156 }, |
|
157 function (appcahe) { |
|
158 do_print("app avail " + appcache + "\n"); |
|
159 }); |
|
160 } |
|
161 |
|
162 var hold_entry_foo1 = null; |
|
163 |
|
164 function check_bug() { |
|
165 // activate foo1 |
|
166 asyncOpenCacheEntry( |
|
167 kHttpLocation + "pages/foo1", |
|
168 "appcache", Ci.nsICacheStorage.OPEN_READONLY, null, |
|
169 function(status, entry, appcache) { |
|
170 let storage = get_cache_service().appCacheStorage(LoadContextInfo.default, appcache); |
|
171 |
|
172 // Doom foo1 & foo2 |
|
173 storage.asyncDoomURI(createURI(kHttpLocation + "pages/foo1"), "", { onCacheEntryDoomed: function() { |
|
174 storage.asyncDoomURI(createURI(kHttpLocation + "pages/foo2"), "", { onCacheEntryDoomed: function() { |
|
175 check_evict_cache(appcache); |
|
176 }}); |
|
177 }}); |
|
178 |
|
179 hold_entry_foo1 = entry; |
|
180 }); |
|
181 } |
|
182 |
|
183 function check_evict_cache(appcache) { |
|
184 // Only foo2 should be removed. |
|
185 let file = do_get_profile().clone(); |
|
186 file.append("OfflineCache"); |
|
187 file.append("5"); |
|
188 file.append("9"); |
|
189 file.append("8379C6596B8CA4-0"); |
|
190 do_check_eq(file.exists(), true); |
|
191 |
|
192 file = do_get_profile().clone(); |
|
193 file.append("OfflineCache"); |
|
194 file.append("C"); |
|
195 file.append("2"); |
|
196 file.append("5F356A168B5E3B-0"); |
|
197 do_check_eq(file.exists(), false); |
|
198 |
|
199 // activate foo3 |
|
200 asyncOpenCacheEntry( |
|
201 kHttpLocation + "pages/foo3", |
|
202 "appcache", Ci.nsICacheStorage.OPEN_READONLY, null, |
|
203 function(status, entry, appcache) { |
|
204 hold_entry_foo3 = entry; |
|
205 |
|
206 // evict all documents. |
|
207 let storage = get_cache_service().appCacheStorage(LoadContextInfo.default, appcache); |
|
208 storage.asyncEvictStorage(null); |
|
209 |
|
210 // All documents are removed except foo1 & foo3. |
|
211 syncWithCacheIOThread(function () { |
|
212 // foo1 |
|
213 let file = do_get_profile().clone(); |
|
214 file.append("OfflineCache"); |
|
215 file.append("5"); |
|
216 file.append("9"); |
|
217 file.append("8379C6596B8CA4-0"); |
|
218 do_check_eq(file.exists(), true); |
|
219 |
|
220 file = do_get_profile().clone(); |
|
221 file.append("OfflineCache"); |
|
222 file.append("0"); |
|
223 file.append("0"); |
|
224 file.append("61FEE819921D39-0"); |
|
225 do_check_eq(file.exists(), false); |
|
226 |
|
227 file = do_get_profile().clone(); |
|
228 file.append("OfflineCache"); |
|
229 file.append("3"); |
|
230 file.append("9"); |
|
231 file.append("0D8759F1DE5452-0"); |
|
232 do_check_eq(file.exists(), false); |
|
233 |
|
234 file = do_get_profile().clone(); |
|
235 file.append("OfflineCache"); |
|
236 file.append("C"); |
|
237 file.append("2"); |
|
238 file.append("5F356A168B5E3B-0"); |
|
239 do_check_eq(file.exists(), false); |
|
240 |
|
241 // foo3 |
|
242 file = do_get_profile().clone(); |
|
243 file.append("OfflineCache"); |
|
244 file.append("D"); |
|
245 file.append("C"); |
|
246 file.append("1ADCCC843B5C00-0"); |
|
247 do_check_eq(file.exists(), true); |
|
248 |
|
249 file = do_get_profile().clone(); |
|
250 file.append("OfflineCache"); |
|
251 file.append("F"); |
|
252 file.append("0"); |
|
253 file.append("FC3E6D6C1164E9-0"); |
|
254 do_check_eq(file.exists(), false); |
|
255 |
|
256 httpServer.stop(do_test_finished); |
|
257 }); |
|
258 }, |
|
259 appcache |
|
260 ); |
|
261 } |
|
262 |
|
263 function run_test() { |
|
264 if (newCacheBackEndUsed()) { |
|
265 // times out on storage.asyncDoomURI @ check_bug because that method is not implemented for appcache |
|
266 // either revert the test changes or implement the method (former seems more reasonable) |
|
267 do_check_true(true, "This test doesn't run with the new cache backend, the test or the cache needs to be fixed"); |
|
268 return; |
|
269 } |
|
270 |
|
271 if (typeof _XPCSHELL_PROCESS == "undefined" || |
|
272 _XPCSHELL_PROCESS != "child") { |
|
273 init_profile(); |
|
274 clean_app_cache(); |
|
275 } |
|
276 |
|
277 init_http_server(); |
|
278 start_cache_nonpinned_app(); |
|
279 do_test_pending(); |
|
280 } |