michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: */ michael@0: michael@0: /* General Update Timer Manager Tests */ michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cm = Components.manager; michael@0: const Cr = Components.results; michael@0: michael@0: Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: const CATEGORY_UPDATE_TIMER = "update-timer"; michael@0: michael@0: const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay"; michael@0: const PREF_APP_UPDATE_TIMERFIRSTINTERVAL = "app.update.timerFirstInterval"; michael@0: const PREF_APP_UPDATE_LOG_ALL = "app.update.log.all"; michael@0: const PREF_BRANCH_LAST_UPDATE_TIME = "app.update.lastUpdateTime."; michael@0: michael@0: const MAIN_TIMER_INTERVAL = 1000; // milliseconds michael@0: const CONSUMER_TIMER_INTERVAL = 1; // seconds michael@0: michael@0: const TESTS = [ { michael@0: desc : "Test Timer Callback 1", michael@0: timerID : "test1-update-timer", michael@0: defaultInterval : "bogus", michael@0: prefInterval : "test1.timer.interval", michael@0: contractID : "@mozilla.org/test1/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("9c7ce81f-98bb-4729-adb4-4d0deb0f59e5"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 2", michael@0: timerID : "test2-update-timer", michael@0: defaultInterval : 86400, michael@0: prefInterval : "test2.timer.interval", michael@0: contractID : "@mozilla.org/test2/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("512834f3-05bb-46be-84e0-81d881a140b7"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 3", michael@0: timerID : "test3-update-timer", michael@0: defaultInterval : CONSUMER_TIMER_INTERVAL, michael@0: prefInterval : "test3.timer.interval", michael@0: contractID : "@mozilla.org/test3/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("c8ac5027-8d11-4471-9d7c-fd692501b437"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 4", michael@0: timerID : "test4-update-timer", michael@0: defaultInterval : CONSUMER_TIMER_INTERVAL, michael@0: prefInterval : "test4.timer.interval", michael@0: contractID : "@mozilla.org/test4/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("6b0e79f3-4ab8-414c-8f14-dde10e185727"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 5", michael@0: timerID : "test5-update-timer", michael@0: defaultInterval : CONSUMER_TIMER_INTERVAL, michael@0: prefInterval : "test5.timer.interval", michael@0: contractID : "@mozilla.org/test5/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("2f6b7b92-e40f-4874-bfbb-eeb2412c959d"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 6", michael@0: timerID : "test6-update-timer", michael@0: defaultInterval : 86400, michael@0: prefInterval : "test6.timer.interval", michael@0: contractID : "@mozilla.org/test6/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("8a95f611-b2ac-4c7e-8b73-9748c4839731"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 7", michael@0: timerID : "test7-update-timer", michael@0: defaultInterval : CONSUMER_TIMER_INTERVAL, michael@0: prefInterval : "test7.timer.interval", michael@0: contractID : "@mozilla.org/test7/timercallback;1", michael@0: method : "createInstance", michael@0: classID : Components.ID("2d091020-e23c-11e2-a28f-0800200c9a66"), michael@0: notified : false michael@0: }, { michael@0: desc : "Test Timer Callback 8", michael@0: timerID : "test8-update-timer", michael@0: defaultInterval : CONSUMER_TIMER_INTERVAL, michael@0: contractID : "@mozilla.org/test8/timercallback;1", michael@0: classID : Components.ID("af878d4b-1d12-41f6-9a90-4e687367ecc1"), michael@0: notified : false, michael@0: lastUpdateTime : 0 michael@0: }, { michael@0: desc : "Test Timer Callback 9", michael@0: timerID : "test9-update-timer", michael@0: defaultInterval : CONSUMER_TIMER_INTERVAL, michael@0: contractID : "@mozilla.org/test9/timercallback;1", michael@0: classID : Components.ID("5136b201-d64c-4328-8cf1-1a63491cc117"), michael@0: notified : false, michael@0: lastUpdateTime : 0 michael@0: } ]; michael@0: michael@0: var gUTM; michael@0: var gNextFunc; michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "gPref", michael@0: "@mozilla.org/preferences-service;1", michael@0: "nsIPrefBranch"); michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "gCatMan", michael@0: "@mozilla.org/categorymanager;1", michael@0: "nsICategoryManager"); michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "gCompReg", function() { michael@0: return Cm.QueryInterface(Ci.nsIComponentRegistrar); michael@0: }); michael@0: michael@0: function run_test() { michael@0: do_test_pending(); michael@0: michael@0: // Set the timer to fire every second michael@0: gPref.setIntPref(PREF_APP_UPDATE_TIMERMINIMUMDELAY, MAIN_TIMER_INTERVAL/1000); michael@0: gPref.setIntPref(PREF_APP_UPDATE_TIMERFIRSTINTERVAL, MAIN_TIMER_INTERVAL); michael@0: gPref.setBoolPref(PREF_APP_UPDATE_LOG_ALL, true); michael@0: michael@0: // Remove existing update timers to prevent them from being notified michael@0: var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER); michael@0: while (entries.hasMoreElements()) { michael@0: let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false); michael@0: } michael@0: michael@0: gUTM = Cc["@mozilla.org/updates/timer-manager;1"]. michael@0: getService(Ci.nsIUpdateTimerManager). michael@0: QueryInterface(Ci.nsIObserver); michael@0: gUTM.observe(null, "utm-test-init", ""); michael@0: michael@0: do_execute_soon(run_test1thru7); michael@0: } michael@0: michael@0: function end_test() { michael@0: gUTM.observe(null, "xpcom-shutdown", ""); michael@0: do_test_finished(); michael@0: } michael@0: michael@0: function run_test1thru7() { michael@0: gNextFunc = check_test1thru7; michael@0: // bogus default interval michael@0: gCompReg.registerFactory(TESTS[0].classID, TESTS[0].desc, michael@0: TESTS[0].contractID, gTest1Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[0].desc, michael@0: [TESTS[0].contractID, TESTS[0].method, michael@0: TESTS[0].timerID, TESTS[0].prefInterval, michael@0: TESTS[0].defaultInterval].join(","), false, true); michael@0: michael@0: // doesn't implement nsITimerCallback michael@0: gCompReg.registerFactory(TESTS[1].classID, TESTS[1].desc, michael@0: TESTS[1].contractID, gTest2Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[1].desc, michael@0: [TESTS[1].contractID, TESTS[1].method, michael@0: TESTS[1].timerID, TESTS[1].prefInterval, michael@0: TESTS[1].defaultInterval].join(","), false, true); michael@0: michael@0: // has a last update time of now - 43200 which is half of its interval michael@0: var lastUpdateTime = Math.round(Date.now() / 1000) - 43200; michael@0: gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[2].timerID, lastUpdateTime); michael@0: gCompReg.registerFactory(TESTS[2].classID, TESTS[2].desc, michael@0: TESTS[2].contractID, gTest3Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[2].desc, michael@0: [TESTS[2].contractID, TESTS[2].method, michael@0: TESTS[2].timerID, TESTS[2].prefInterval, michael@0: TESTS[2].defaultInterval].join(","), false, true); michael@0: michael@0: // doesn't have a notify method michael@0: gCompReg.registerFactory(TESTS[3].classID, TESTS[3].desc, michael@0: TESTS[3].contractID, gTest4Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[3].desc, michael@0: [TESTS[3].contractID, TESTS[3].method, michael@0: TESTS[3].timerID, TESTS[3].prefInterval, michael@0: TESTS[3].defaultInterval].join(","), false, true); michael@0: michael@0: // already has a last update time michael@0: gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[4].timerID, 1); michael@0: gCompReg.registerFactory(TESTS[4].classID, TESTS[4].desc, michael@0: TESTS[4].contractID, gTest5Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, michael@0: [TESTS[4].contractID, TESTS[4].method, michael@0: TESTS[4].timerID, TESTS[4].prefInterval, michael@0: TESTS[4].defaultInterval].join(","), false, true); michael@0: michael@0: // has an interval preference that overrides the default michael@0: gPref.setIntPref(TESTS[5].prefInterval, CONSUMER_TIMER_INTERVAL); michael@0: gCompReg.registerFactory(TESTS[5].classID, TESTS[5].desc, michael@0: TESTS[5].contractID, gTest6Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, michael@0: [TESTS[5].contractID, TESTS[5].method, michael@0: TESTS[5].timerID, TESTS[5].prefInterval, michael@0: TESTS[5].defaultInterval].join(","), false, true); michael@0: michael@0: // has a next update time 24 hours from now michael@0: var nextUpdateTime = Math.round(Date.now() / 1000) + 86400; michael@0: gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[6].timerID, nextUpdateTime); michael@0: gCompReg.registerFactory(TESTS[6].classID, TESTS[6].desc, michael@0: TESTS[6].contractID, gTest7Factory); michael@0: gCatMan.addCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, michael@0: [TESTS[6].contractID, TESTS[6].method, michael@0: TESTS[6].timerID, TESTS[6].prefInterval, michael@0: TESTS[6].defaultInterval].join(","), false, true); michael@0: } michael@0: michael@0: function finished_test1thru7() { michael@0: if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified) michael@0: do_timeout(0, gNextFunc); michael@0: } michael@0: michael@0: function check_test1thru7() { michael@0: dump("Testing: a category registered timer didn't fire due to an invalid " + michael@0: "default interval\n"); michael@0: do_check_false(TESTS[0].notified); michael@0: michael@0: dump("Testing: a category registered timer didn't fire due to not " + michael@0: "implementing nsITimerCallback\n"); michael@0: do_check_false(TESTS[1].notified); michael@0: michael@0: dump("Testing: a category registered timer didn't fire due to the next " + michael@0: "update time being in the future\n"); michael@0: do_check_false(TESTS[2].notified); michael@0: michael@0: dump("Testing: a category registered timer didn't fire due to not " + michael@0: "having a notify method\n"); michael@0: do_check_false(TESTS[3].notified); michael@0: michael@0: dump("Testing: a category registered timer has fired\n"); michael@0: do_check_true(TESTS[4].notified); michael@0: michael@0: dump("Testing: a category registered timer fired that has an interval " + michael@0: "preference that overrides a default that wouldn't have fired yet\n"); michael@0: do_check_true(TESTS[5].notified); michael@0: michael@0: dump("Testing: a category registered timer has fired due to the next " + michael@0: "update time being reset due to a future last update time\n"); michael@0: do_check_true(TESTS[6].notified); michael@0: michael@0: dump("Testing: two category registered timers last update time has " + michael@0: "user values\n"); michael@0: do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME + michael@0: TESTS[4].timerID)); michael@0: do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME + michael@0: TESTS[5].timerID)); michael@0: michael@0: // Remove the category timers that should have failed michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[0].desc, true); michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[1].desc, true); michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[2].desc, true); michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[3].desc, true); michael@0: var count = 0; michael@0: var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER); michael@0: while (entries.hasMoreElements()) { michael@0: let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false); michael@0: count++; michael@0: } michael@0: dump("Testing: no " + CATEGORY_UPDATE_TIMER + " categories are still " + michael@0: "registered\n"); michael@0: do_check_eq(count, 0); michael@0: michael@0: do_timeout(0, run_test8); michael@0: } michael@0: michael@0: function run_test8() { michael@0: gNextFunc = check_test8; michael@0: for (var i = 0; i < 2; i++) { michael@0: gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID, 1); michael@0: gCompReg.registerFactory(TESTS[7 + i].classID, TESTS[7 + i].desc, michael@0: TESTS[7 + i].contractID, eval("gTest" + (8 + i) + "Factory")); michael@0: gUTM.registerTimer(TESTS[7 + i].timerID, eval("gTest" + (8 + i) + "TimerCallback"), michael@0: TESTS[7 + i].defaultInterval); michael@0: } michael@0: } michael@0: michael@0: function check_test8() { michael@0: var self = arguments.callee; michael@0: self.timesCalled = (self.timesCalled || 0) + 1; michael@0: if (self.timesCalled < 2) michael@0: return; michael@0: michael@0: dump("Testing: two registerTimer registered timers have fired\n"); michael@0: for (var i = 0; i < 2; i++) michael@0: do_check_true(TESTS[7 + i].notified); michael@0: michael@0: // Check that 'staggering' has happened: even though the two events wanted to fire at michael@0: // the same time, we waited a full MAIN_TIMER_INTERVAL between them. michael@0: // (to avoid sensitivity to random timing issues, we fudge by a factor of 0.5 here) michael@0: do_check_true(Math.abs(TESTS[7].notifyTime - TESTS[8].notifyTime) >= michael@0: MAIN_TIMER_INTERVAL * 0.5); michael@0: michael@0: dump("Testing: two registerTimer registered timers last update time have " + michael@0: "been updated\n"); michael@0: for (var i = 0; i < 2; i++) michael@0: do_check_neq(gPref.getIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID), 1); michael@0: end_test(); michael@0: } michael@0: michael@0: var gTest1TimerCallback = { michael@0: notify: function T1CB_notify(aTimer) { michael@0: do_throw("gTest1TimerCallback notify method should not have been called"); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest1Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest1TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest2TimerCallback = { michael@0: notify: function T2CB_notify(aTimer) { michael@0: do_throw("gTest2TimerCallback notify method should not have been called"); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimer]) michael@0: }; michael@0: michael@0: var gTest2Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest2TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest3TimerCallback = { michael@0: notify: function T3CB_notify(aTimer) { michael@0: do_throw("gTest3TimerCallback notify method should not have been called"); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest3Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest3TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest4TimerCallback = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest4Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest4TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest5TimerCallback = { michael@0: notify: function T5CB_notify(aTimer) { michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, true); michael@0: TESTS[4].notified = true; michael@0: finished_test1thru7(); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest5Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest5TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest6TimerCallback = { michael@0: notify: function T6CB_notify(aTimer) { michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, true); michael@0: TESTS[5].notified = true; michael@0: finished_test1thru7(); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest6Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest6TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest7TimerCallback = { michael@0: notify: function T7CB_notify(aTimer) { michael@0: gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, true); michael@0: TESTS[6].notified = true; michael@0: finished_test1thru7(); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest7Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest7TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest8TimerCallback = { michael@0: notify: function T8CB_notify(aTimer) { michael@0: TESTS[7].notified = true; michael@0: TESTS[7].notifyTime = Date.now(); michael@0: do_timeout(0, check_test8); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest8Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest8TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: }; michael@0: michael@0: var gTest9TimerCallback = { michael@0: notify: function T9CB_notify(aTimer) { michael@0: TESTS[8].notified = true; michael@0: TESTS[8].notifyTime = Date.now(); michael@0: do_timeout(0, check_test8); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) michael@0: }; michael@0: michael@0: var gTest9Factory = { michael@0: createInstance: function (outer, iid) { michael@0: if (outer == null) michael@0: return gTest9TimerCallback.QueryInterface(iid); michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: };