|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 */ |
|
5 |
|
6 /* General Update Timer Manager Tests */ |
|
7 |
|
8 const Cc = Components.classes; |
|
9 const Ci = Components.interfaces; |
|
10 const Cm = Components.manager; |
|
11 const Cr = Components.results; |
|
12 |
|
13 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
14 |
|
15 const CATEGORY_UPDATE_TIMER = "update-timer"; |
|
16 |
|
17 const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay"; |
|
18 const PREF_APP_UPDATE_TIMERFIRSTINTERVAL = "app.update.timerFirstInterval"; |
|
19 const PREF_APP_UPDATE_LOG_ALL = "app.update.log.all"; |
|
20 const PREF_BRANCH_LAST_UPDATE_TIME = "app.update.lastUpdateTime."; |
|
21 |
|
22 const MAIN_TIMER_INTERVAL = 1000; // milliseconds |
|
23 const CONSUMER_TIMER_INTERVAL = 1; // seconds |
|
24 |
|
25 const TESTS = [ { |
|
26 desc : "Test Timer Callback 1", |
|
27 timerID : "test1-update-timer", |
|
28 defaultInterval : "bogus", |
|
29 prefInterval : "test1.timer.interval", |
|
30 contractID : "@mozilla.org/test1/timercallback;1", |
|
31 method : "createInstance", |
|
32 classID : Components.ID("9c7ce81f-98bb-4729-adb4-4d0deb0f59e5"), |
|
33 notified : false |
|
34 }, { |
|
35 desc : "Test Timer Callback 2", |
|
36 timerID : "test2-update-timer", |
|
37 defaultInterval : 86400, |
|
38 prefInterval : "test2.timer.interval", |
|
39 contractID : "@mozilla.org/test2/timercallback;1", |
|
40 method : "createInstance", |
|
41 classID : Components.ID("512834f3-05bb-46be-84e0-81d881a140b7"), |
|
42 notified : false |
|
43 }, { |
|
44 desc : "Test Timer Callback 3", |
|
45 timerID : "test3-update-timer", |
|
46 defaultInterval : CONSUMER_TIMER_INTERVAL, |
|
47 prefInterval : "test3.timer.interval", |
|
48 contractID : "@mozilla.org/test3/timercallback;1", |
|
49 method : "createInstance", |
|
50 classID : Components.ID("c8ac5027-8d11-4471-9d7c-fd692501b437"), |
|
51 notified : false |
|
52 }, { |
|
53 desc : "Test Timer Callback 4", |
|
54 timerID : "test4-update-timer", |
|
55 defaultInterval : CONSUMER_TIMER_INTERVAL, |
|
56 prefInterval : "test4.timer.interval", |
|
57 contractID : "@mozilla.org/test4/timercallback;1", |
|
58 method : "createInstance", |
|
59 classID : Components.ID("6b0e79f3-4ab8-414c-8f14-dde10e185727"), |
|
60 notified : false |
|
61 }, { |
|
62 desc : "Test Timer Callback 5", |
|
63 timerID : "test5-update-timer", |
|
64 defaultInterval : CONSUMER_TIMER_INTERVAL, |
|
65 prefInterval : "test5.timer.interval", |
|
66 contractID : "@mozilla.org/test5/timercallback;1", |
|
67 method : "createInstance", |
|
68 classID : Components.ID("2f6b7b92-e40f-4874-bfbb-eeb2412c959d"), |
|
69 notified : false |
|
70 }, { |
|
71 desc : "Test Timer Callback 6", |
|
72 timerID : "test6-update-timer", |
|
73 defaultInterval : 86400, |
|
74 prefInterval : "test6.timer.interval", |
|
75 contractID : "@mozilla.org/test6/timercallback;1", |
|
76 method : "createInstance", |
|
77 classID : Components.ID("8a95f611-b2ac-4c7e-8b73-9748c4839731"), |
|
78 notified : false |
|
79 }, { |
|
80 desc : "Test Timer Callback 7", |
|
81 timerID : "test7-update-timer", |
|
82 defaultInterval : CONSUMER_TIMER_INTERVAL, |
|
83 prefInterval : "test7.timer.interval", |
|
84 contractID : "@mozilla.org/test7/timercallback;1", |
|
85 method : "createInstance", |
|
86 classID : Components.ID("2d091020-e23c-11e2-a28f-0800200c9a66"), |
|
87 notified : false |
|
88 }, { |
|
89 desc : "Test Timer Callback 8", |
|
90 timerID : "test8-update-timer", |
|
91 defaultInterval : CONSUMER_TIMER_INTERVAL, |
|
92 contractID : "@mozilla.org/test8/timercallback;1", |
|
93 classID : Components.ID("af878d4b-1d12-41f6-9a90-4e687367ecc1"), |
|
94 notified : false, |
|
95 lastUpdateTime : 0 |
|
96 }, { |
|
97 desc : "Test Timer Callback 9", |
|
98 timerID : "test9-update-timer", |
|
99 defaultInterval : CONSUMER_TIMER_INTERVAL, |
|
100 contractID : "@mozilla.org/test9/timercallback;1", |
|
101 classID : Components.ID("5136b201-d64c-4328-8cf1-1a63491cc117"), |
|
102 notified : false, |
|
103 lastUpdateTime : 0 |
|
104 } ]; |
|
105 |
|
106 var gUTM; |
|
107 var gNextFunc; |
|
108 |
|
109 XPCOMUtils.defineLazyServiceGetter(this, "gPref", |
|
110 "@mozilla.org/preferences-service;1", |
|
111 "nsIPrefBranch"); |
|
112 |
|
113 XPCOMUtils.defineLazyServiceGetter(this, "gCatMan", |
|
114 "@mozilla.org/categorymanager;1", |
|
115 "nsICategoryManager"); |
|
116 |
|
117 XPCOMUtils.defineLazyGetter(this, "gCompReg", function() { |
|
118 return Cm.QueryInterface(Ci.nsIComponentRegistrar); |
|
119 }); |
|
120 |
|
121 function run_test() { |
|
122 do_test_pending(); |
|
123 |
|
124 // Set the timer to fire every second |
|
125 gPref.setIntPref(PREF_APP_UPDATE_TIMERMINIMUMDELAY, MAIN_TIMER_INTERVAL/1000); |
|
126 gPref.setIntPref(PREF_APP_UPDATE_TIMERFIRSTINTERVAL, MAIN_TIMER_INTERVAL); |
|
127 gPref.setBoolPref(PREF_APP_UPDATE_LOG_ALL, true); |
|
128 |
|
129 // Remove existing update timers to prevent them from being notified |
|
130 var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER); |
|
131 while (entries.hasMoreElements()) { |
|
132 let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; |
|
133 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false); |
|
134 } |
|
135 |
|
136 gUTM = Cc["@mozilla.org/updates/timer-manager;1"]. |
|
137 getService(Ci.nsIUpdateTimerManager). |
|
138 QueryInterface(Ci.nsIObserver); |
|
139 gUTM.observe(null, "utm-test-init", ""); |
|
140 |
|
141 do_execute_soon(run_test1thru7); |
|
142 } |
|
143 |
|
144 function end_test() { |
|
145 gUTM.observe(null, "xpcom-shutdown", ""); |
|
146 do_test_finished(); |
|
147 } |
|
148 |
|
149 function run_test1thru7() { |
|
150 gNextFunc = check_test1thru7; |
|
151 // bogus default interval |
|
152 gCompReg.registerFactory(TESTS[0].classID, TESTS[0].desc, |
|
153 TESTS[0].contractID, gTest1Factory); |
|
154 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[0].desc, |
|
155 [TESTS[0].contractID, TESTS[0].method, |
|
156 TESTS[0].timerID, TESTS[0].prefInterval, |
|
157 TESTS[0].defaultInterval].join(","), false, true); |
|
158 |
|
159 // doesn't implement nsITimerCallback |
|
160 gCompReg.registerFactory(TESTS[1].classID, TESTS[1].desc, |
|
161 TESTS[1].contractID, gTest2Factory); |
|
162 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[1].desc, |
|
163 [TESTS[1].contractID, TESTS[1].method, |
|
164 TESTS[1].timerID, TESTS[1].prefInterval, |
|
165 TESTS[1].defaultInterval].join(","), false, true); |
|
166 |
|
167 // has a last update time of now - 43200 which is half of its interval |
|
168 var lastUpdateTime = Math.round(Date.now() / 1000) - 43200; |
|
169 gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[2].timerID, lastUpdateTime); |
|
170 gCompReg.registerFactory(TESTS[2].classID, TESTS[2].desc, |
|
171 TESTS[2].contractID, gTest3Factory); |
|
172 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[2].desc, |
|
173 [TESTS[2].contractID, TESTS[2].method, |
|
174 TESTS[2].timerID, TESTS[2].prefInterval, |
|
175 TESTS[2].defaultInterval].join(","), false, true); |
|
176 |
|
177 // doesn't have a notify method |
|
178 gCompReg.registerFactory(TESTS[3].classID, TESTS[3].desc, |
|
179 TESTS[3].contractID, gTest4Factory); |
|
180 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[3].desc, |
|
181 [TESTS[3].contractID, TESTS[3].method, |
|
182 TESTS[3].timerID, TESTS[3].prefInterval, |
|
183 TESTS[3].defaultInterval].join(","), false, true); |
|
184 |
|
185 // already has a last update time |
|
186 gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[4].timerID, 1); |
|
187 gCompReg.registerFactory(TESTS[4].classID, TESTS[4].desc, |
|
188 TESTS[4].contractID, gTest5Factory); |
|
189 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, |
|
190 [TESTS[4].contractID, TESTS[4].method, |
|
191 TESTS[4].timerID, TESTS[4].prefInterval, |
|
192 TESTS[4].defaultInterval].join(","), false, true); |
|
193 |
|
194 // has an interval preference that overrides the default |
|
195 gPref.setIntPref(TESTS[5].prefInterval, CONSUMER_TIMER_INTERVAL); |
|
196 gCompReg.registerFactory(TESTS[5].classID, TESTS[5].desc, |
|
197 TESTS[5].contractID, gTest6Factory); |
|
198 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, |
|
199 [TESTS[5].contractID, TESTS[5].method, |
|
200 TESTS[5].timerID, TESTS[5].prefInterval, |
|
201 TESTS[5].defaultInterval].join(","), false, true); |
|
202 |
|
203 // has a next update time 24 hours from now |
|
204 var nextUpdateTime = Math.round(Date.now() / 1000) + 86400; |
|
205 gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[6].timerID, nextUpdateTime); |
|
206 gCompReg.registerFactory(TESTS[6].classID, TESTS[6].desc, |
|
207 TESTS[6].contractID, gTest7Factory); |
|
208 gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, |
|
209 [TESTS[6].contractID, TESTS[6].method, |
|
210 TESTS[6].timerID, TESTS[6].prefInterval, |
|
211 TESTS[6].defaultInterval].join(","), false, true); |
|
212 } |
|
213 |
|
214 function finished_test1thru7() { |
|
215 if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified) |
|
216 do_timeout(0, gNextFunc); |
|
217 } |
|
218 |
|
219 function check_test1thru7() { |
|
220 dump("Testing: a category registered timer didn't fire due to an invalid " + |
|
221 "default interval\n"); |
|
222 do_check_false(TESTS[0].notified); |
|
223 |
|
224 dump("Testing: a category registered timer didn't fire due to not " + |
|
225 "implementing nsITimerCallback\n"); |
|
226 do_check_false(TESTS[1].notified); |
|
227 |
|
228 dump("Testing: a category registered timer didn't fire due to the next " + |
|
229 "update time being in the future\n"); |
|
230 do_check_false(TESTS[2].notified); |
|
231 |
|
232 dump("Testing: a category registered timer didn't fire due to not " + |
|
233 "having a notify method\n"); |
|
234 do_check_false(TESTS[3].notified); |
|
235 |
|
236 dump("Testing: a category registered timer has fired\n"); |
|
237 do_check_true(TESTS[4].notified); |
|
238 |
|
239 dump("Testing: a category registered timer fired that has an interval " + |
|
240 "preference that overrides a default that wouldn't have fired yet\n"); |
|
241 do_check_true(TESTS[5].notified); |
|
242 |
|
243 dump("Testing: a category registered timer has fired due to the next " + |
|
244 "update time being reset due to a future last update time\n"); |
|
245 do_check_true(TESTS[6].notified); |
|
246 |
|
247 dump("Testing: two category registered timers last update time has " + |
|
248 "user values\n"); |
|
249 do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME + |
|
250 TESTS[4].timerID)); |
|
251 do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME + |
|
252 TESTS[5].timerID)); |
|
253 |
|
254 // Remove the category timers that should have failed |
|
255 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[0].desc, true); |
|
256 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[1].desc, true); |
|
257 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[2].desc, true); |
|
258 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[3].desc, true); |
|
259 var count = 0; |
|
260 var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER); |
|
261 while (entries.hasMoreElements()) { |
|
262 let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; |
|
263 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false); |
|
264 count++; |
|
265 } |
|
266 dump("Testing: no " + CATEGORY_UPDATE_TIMER + " categories are still " + |
|
267 "registered\n"); |
|
268 do_check_eq(count, 0); |
|
269 |
|
270 do_timeout(0, run_test8); |
|
271 } |
|
272 |
|
273 function run_test8() { |
|
274 gNextFunc = check_test8; |
|
275 for (var i = 0; i < 2; i++) { |
|
276 gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID, 1); |
|
277 gCompReg.registerFactory(TESTS[7 + i].classID, TESTS[7 + i].desc, |
|
278 TESTS[7 + i].contractID, eval("gTest" + (8 + i) + "Factory")); |
|
279 gUTM.registerTimer(TESTS[7 + i].timerID, eval("gTest" + (8 + i) + "TimerCallback"), |
|
280 TESTS[7 + i].defaultInterval); |
|
281 } |
|
282 } |
|
283 |
|
284 function check_test8() { |
|
285 var self = arguments.callee; |
|
286 self.timesCalled = (self.timesCalled || 0) + 1; |
|
287 if (self.timesCalled < 2) |
|
288 return; |
|
289 |
|
290 dump("Testing: two registerTimer registered timers have fired\n"); |
|
291 for (var i = 0; i < 2; i++) |
|
292 do_check_true(TESTS[7 + i].notified); |
|
293 |
|
294 // Check that 'staggering' has happened: even though the two events wanted to fire at |
|
295 // the same time, we waited a full MAIN_TIMER_INTERVAL between them. |
|
296 // (to avoid sensitivity to random timing issues, we fudge by a factor of 0.5 here) |
|
297 do_check_true(Math.abs(TESTS[7].notifyTime - TESTS[8].notifyTime) >= |
|
298 MAIN_TIMER_INTERVAL * 0.5); |
|
299 |
|
300 dump("Testing: two registerTimer registered timers last update time have " + |
|
301 "been updated\n"); |
|
302 for (var i = 0; i < 2; i++) |
|
303 do_check_neq(gPref.getIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID), 1); |
|
304 end_test(); |
|
305 } |
|
306 |
|
307 var gTest1TimerCallback = { |
|
308 notify: function T1CB_notify(aTimer) { |
|
309 do_throw("gTest1TimerCallback notify method should not have been called"); |
|
310 }, |
|
311 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
312 }; |
|
313 |
|
314 var gTest1Factory = { |
|
315 createInstance: function (outer, iid) { |
|
316 if (outer == null) |
|
317 return gTest1TimerCallback.QueryInterface(iid); |
|
318 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
319 } |
|
320 }; |
|
321 |
|
322 var gTest2TimerCallback = { |
|
323 notify: function T2CB_notify(aTimer) { |
|
324 do_throw("gTest2TimerCallback notify method should not have been called"); |
|
325 }, |
|
326 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimer]) |
|
327 }; |
|
328 |
|
329 var gTest2Factory = { |
|
330 createInstance: function (outer, iid) { |
|
331 if (outer == null) |
|
332 return gTest2TimerCallback.QueryInterface(iid); |
|
333 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
334 } |
|
335 }; |
|
336 |
|
337 var gTest3TimerCallback = { |
|
338 notify: function T3CB_notify(aTimer) { |
|
339 do_throw("gTest3TimerCallback notify method should not have been called"); |
|
340 }, |
|
341 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
342 }; |
|
343 |
|
344 var gTest3Factory = { |
|
345 createInstance: function (outer, iid) { |
|
346 if (outer == null) |
|
347 return gTest3TimerCallback.QueryInterface(iid); |
|
348 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
349 } |
|
350 }; |
|
351 |
|
352 var gTest4TimerCallback = { |
|
353 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
354 }; |
|
355 |
|
356 var gTest4Factory = { |
|
357 createInstance: function (outer, iid) { |
|
358 if (outer == null) |
|
359 return gTest4TimerCallback.QueryInterface(iid); |
|
360 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
361 } |
|
362 }; |
|
363 |
|
364 var gTest5TimerCallback = { |
|
365 notify: function T5CB_notify(aTimer) { |
|
366 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, true); |
|
367 TESTS[4].notified = true; |
|
368 finished_test1thru7(); |
|
369 }, |
|
370 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
371 }; |
|
372 |
|
373 var gTest5Factory = { |
|
374 createInstance: function (outer, iid) { |
|
375 if (outer == null) |
|
376 return gTest5TimerCallback.QueryInterface(iid); |
|
377 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
378 } |
|
379 }; |
|
380 |
|
381 var gTest6TimerCallback = { |
|
382 notify: function T6CB_notify(aTimer) { |
|
383 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, true); |
|
384 TESTS[5].notified = true; |
|
385 finished_test1thru7(); |
|
386 }, |
|
387 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
388 }; |
|
389 |
|
390 var gTest6Factory = { |
|
391 createInstance: function (outer, iid) { |
|
392 if (outer == null) |
|
393 return gTest6TimerCallback.QueryInterface(iid); |
|
394 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
395 } |
|
396 }; |
|
397 |
|
398 var gTest7TimerCallback = { |
|
399 notify: function T7CB_notify(aTimer) { |
|
400 gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, true); |
|
401 TESTS[6].notified = true; |
|
402 finished_test1thru7(); |
|
403 }, |
|
404 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
405 }; |
|
406 |
|
407 var gTest7Factory = { |
|
408 createInstance: function (outer, iid) { |
|
409 if (outer == null) |
|
410 return gTest7TimerCallback.QueryInterface(iid); |
|
411 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
412 } |
|
413 }; |
|
414 |
|
415 var gTest8TimerCallback = { |
|
416 notify: function T8CB_notify(aTimer) { |
|
417 TESTS[7].notified = true; |
|
418 TESTS[7].notifyTime = Date.now(); |
|
419 do_timeout(0, check_test8); |
|
420 }, |
|
421 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
422 }; |
|
423 |
|
424 var gTest8Factory = { |
|
425 createInstance: function (outer, iid) { |
|
426 if (outer == null) |
|
427 return gTest8TimerCallback.QueryInterface(iid); |
|
428 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
429 } |
|
430 }; |
|
431 |
|
432 var gTest9TimerCallback = { |
|
433 notify: function T9CB_notify(aTimer) { |
|
434 TESTS[8].notified = true; |
|
435 TESTS[8].notifyTime = Date.now(); |
|
436 do_timeout(0, check_test8); |
|
437 }, |
|
438 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) |
|
439 }; |
|
440 |
|
441 var gTest9Factory = { |
|
442 createInstance: function (outer, iid) { |
|
443 if (outer == null) |
|
444 return gTest9TimerCallback.QueryInterface(iid); |
|
445 throw Cr.NS_ERROR_NO_AGGREGATION; |
|
446 } |
|
447 }; |