import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,21 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_MODULE = 'update'
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
XPIDL_SOURCES += [
'nsIUpdateTimerManager.idl',
]
EXTRA_COMPONENTS += [
'nsUpdateTimerManager.js',
'nsUpdateTimerManager.manifest',
]
with Files('**'):
BUG_COMPONENT = ('Toolkit', 'Application Update')

View file

@ -0,0 +1,54 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsITimerCallback;
/**
* An interface describing a global application service that allows long
* duration (e.g. 1-7 or more days, weeks or months) timers to be registered
* and then fired.
*/
[scriptable, uuid(0765c92c-6145-4253-9db4-594d8023087e)]
interface nsIUpdateTimerManager : nsISupports
{
/**
* Register an interval with the timer manager. The timer manager
* periodically checks to see if the interval has expired and if it has
* calls the specified callback. This is persistent across application
* restarts and can handle intervals of long durations.
* @param id
* An id that identifies the interval, used for persistence
* @param callback
* A nsITimerCallback object that is notified when the interval
* expires
* @param interval
* The length of time, in seconds, of the interval
*
* Note: to avoid having to instantiate a component to call registerTimer
* the component can intead register an update-timer category with comma
* separated values as a single string representing the timer as follows.
*
* _xpcom_categories: [{ category: "update-timer",
* value: "contractID," +
* "method," +
* "id," +
* "preference," +
* "interval" }],
* the values are as follows
* contractID : the contract ID for the component.
* method : the method used to instantiate the interface. This should be
* either getService or createInstance depending on your
* component.
* id : the id that identifies the interval, used for persistence.
* preference : the preference to for timer interval. This value can be
* optional by specifying an empty string for the value.
* interval : the default interval in seconds for the timer.
*/
void registerTimer(in AString id,
in nsITimerCallback callback,
in unsigned long interval);
};

View file

@ -0,0 +1,339 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm", this);
Components.utils.import("resource://gre/modules/Services.jsm", this);
const Cc = Components.classes;
const Ci = Components.interfaces;
const PREF_APP_UPDATE_LASTUPDATETIME_FMT = "app.update.lastUpdateTime.%ID%";
const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay";
const PREF_APP_UPDATE_TIMERFIRSTINTERVAL = "app.update.timerFirstInterval";
const PREF_APP_UPDATE_LOG = "app.update.log";
const CATEGORY_UPDATE_TIMER = "update-timer";
XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function tm_gLogEnabled() {
return getPref("getBoolPref", PREF_APP_UPDATE_LOG, false);
});
/**
* Gets a preference value, handling the case where there is no default.
* @param func
* The name of the preference function to call, on nsIPrefBranch
* @param preference
* The name of the preference
* @param defaultValue
* The default value to return in the event the preference has
* no setting
* @returns The value of the preference, or undefined if there was no
* user or default value.
*/
function getPref(func, preference, defaultValue) {
try {
return Services.prefs[func](preference);
} catch (e) {
}
return defaultValue;
}
/**
* Logs a string to the error console.
* @param string
* The string to write to the error console.
*/
function LOG(string) {
if (gLogEnabled) {
dump("*** UTM:SVC " + string + "\n");
Services.console.logStringMessage("UTM:SVC " + string);
}
}
/**
* A manager for timers. Manages timers that fire over long periods of time
* (e.g. days, weeks, months).
* @constructor
*/
function TimerManager() {
Services.obs.addObserver(this, "xpcom-shutdown", false);
}
TimerManager.prototype = {
/**
* The Checker Timer
*/
_timer: null,
/**
* The Checker Timer minimum delay interval as specified by the
* app.update.timerMinimumDelay pref. If the app.update.timerMinimumDelay
* pref doesn't exist this will default to 120000.
*/
_timerMinimumDelay: null,
/**
* The set of registered timers.
*/
_timers: { },
/**
* See nsIObserver.idl
*/
observe: function TM_observe(aSubject, aTopic, aData) {
// Prevent setting the timer interval to a value of less than 30 seconds.
var minInterval = 30000;
// Prevent setting the first timer interval to a value of less than 10
// seconds.
var minFirstInterval = 10000;
switch (aTopic) {
case "utm-test-init":
// Enforce a minimum timer interval of 500 ms for tests and fall through
// to profile-after-change to initialize the timer.
minInterval = 500;
minFirstInterval = 500;
case "profile-after-change":
this._timerMinimumDelay = Math.max(1000 * getPref("getIntPref", PREF_APP_UPDATE_TIMERMINIMUMDELAY, 120),
minInterval);
// Prevent the timer delay between notifications to other consumers from
// being greater than 5 minutes which is 300000 milliseconds.
this._timerMinimumDelay = Math.min(this._timerMinimumDelay, 300000);
// Prevent the first interval from being less than the value of minFirstInterval
let firstInterval = Math.max(getPref("getIntPref", PREF_APP_UPDATE_TIMERFIRSTINTERVAL,
30000), minFirstInterval);
// Prevent the first interval from being greater than 2 minutes which is
// 120000 milliseconds.
firstInterval = Math.min(firstInterval, 120000);
// Cancel the timer if it has already been initialized. This is primarily
// for tests.
this._canEnsureTimer = true;
this._ensureTimer(firstInterval);
break;
case "xpcom-shutdown":
Services.obs.removeObserver(this, "xpcom-shutdown");
// Release everything we hold onto.
this._cancelTimer();
for (var timerID in this._timers) {
delete this._timers[timerID];
}
this._timers = null;
break;
}
},
/**
* Called when the checking timer fires.
*
* We only fire one notification each time, so that the operations are
* staggered. We don't want too many to happen at once, which could
* negatively impact responsiveness.
*
* @param timer
* The checking timer that fired.
*/
notify: function TM_notify(timer) {
var nextDelay = null;
function updateNextDelay(delay) {
if (nextDelay === null || delay < nextDelay) {
nextDelay = delay;
}
}
// Each timer calls tryFire(), which figures out which is the one that
// wanted to be called earliest. That one will be fired; the others are
// skipped and will be done later.
var now = Math.round(Date.now() / 1000);
var callbackToFire = null;
var earliestIntendedTime = null;
var skippedFirings = false;
var lastUpdateTime = null;
function tryFire(callback, intendedTime) {
var selected = false;
if (intendedTime <= now) {
if (intendedTime < earliestIntendedTime ||
earliestIntendedTime === null) {
callbackToFire = callback;
earliestIntendedTime = intendedTime;
selected = true;
} else if (earliestIntendedTime !== null) {
skippedFirings = true;
}
}
// We do not need to updateNextDelay for the timer that actually fires;
// we'll update right after it fires, with the proper intended time.
// Note that we might select one, then select another later (with an
// earlier intended time); it is still ok that we did not update for
// the first one, since if we have skipped firings, the next delay
// will be the minimum delay anyhow.
if (!selected) {
updateNextDelay(intendedTime - now);
}
}
var catMan = Cc["@mozilla.org/categorymanager;1"].
getService(Ci.nsICategoryManager);
var entries = catMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
while (entries.hasMoreElements()) {
let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
let value = catMan.getCategoryEntry(CATEGORY_UPDATE_TIMER, entry);
let [cid, method, timerID, prefInterval, defaultInterval, maxInterval] = value.split(",");
defaultInterval = parseInt(defaultInterval);
// cid and method are validated below when calling notify.
if (!timerID || !defaultInterval || isNaN(defaultInterval)) {
LOG("TimerManager:notify - update-timer category registered" +
(cid ? " for " + cid : "") + " without required parameters - " +
"skipping");
continue;
}
let interval = getPref("getIntPref", prefInterval, defaultInterval);
// Allow the update-timer category to specify a maximum value to prevent
// values larger than desired.
maxInterval = parseInt(maxInterval);
if (maxInterval && !isNaN(maxInterval)) {
interval = Math.min(interval, maxInterval);
}
let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/,
timerID);
// Initialize the last update time to 0 when the preference isn't set so
// the timer will be notified soon after a new profile's first use.
lastUpdateTime = getPref("getIntPref", prefLastUpdate, 0);
// If the last update time is greater than the current time then reset
// it to 0 and the timer manager will correct the value when it fires
// next for this consumer.
if (lastUpdateTime > now) {
lastUpdateTime = 0;
}
if (lastUpdateTime == 0) {
Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
}
tryFire(function () {
try {
Components.classes[cid][method](Ci.nsITimerCallback).notify(timer);
LOG("TimerManager:notify - notified " + cid);
} catch (e) {
LOG("TimerManager:notify - error notifying component id: " +
cid + " ,error: " + e);
}
lastUpdateTime = now;
Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
updateNextDelay(lastUpdateTime + interval - now);
}, lastUpdateTime + interval);
}
for (let _timerID in this._timers) {
let timerID = _timerID; // necessary for the closure to work properly
let timerData = this._timers[timerID];
// If the last update time is greater than the current time then reset
// it to 0 and the timer manager will correct the value when it fires
// next for this consumer.
if (timerData.lastUpdateTime > now) {
let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID);
timerData.lastUpdateTime = 0;
Services.prefs.setIntPref(prefLastUpdate, timerData.lastUpdateTime);
}
tryFire(function () {
if (timerData.callback && timerData.callback.notify) {
try {
timerData.callback.notify(timer);
LOG("TimerManager:notify - notified timerID: " + timerID);
} catch (e) {
LOG("TimerManager:notify - error notifying timerID: " + timerID +
", error: " + e);
}
} else {
LOG("TimerManager:notify - timerID: " + timerID + " doesn't " +
"implement nsITimerCallback - skipping");
}
lastUpdateTime = now;
timerData.lastUpdateTime = lastUpdateTime;
let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID);
Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
updateNextDelay(timerData.lastUpdateTime + timerData.interval - now);
}, timerData.lastUpdateTime + timerData.interval);
}
if (callbackToFire) {
callbackToFire();
}
if (nextDelay !== null) {
if (skippedFirings) {
timer.delay = this._timerMinimumDelay;
} else {
timer.delay = Math.max(nextDelay * 1000, this._timerMinimumDelay);
}
this.lastTimerReset = Date.now();
} else {
this._cancelTimer();
}
},
/**
* Starts the timer, if necessary, and ensures that it will fire soon enough
* to happen after time |interval| (in milliseconds).
*/
_ensureTimer: function (interval) {
if (!this._canEnsureTimer) {
return;
}
if (!this._timer) {
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._timer.initWithCallback(this, interval,
Ci.nsITimer.TYPE_REPEATING_SLACK);
this.lastTimerReset = Date.now();
} else if (Date.now() + interval < this.lastTimerReset + this._timer.delay) {
this._timer.delay = Math.max(this.lastTimerReset + interval - Date.now(), 0);
}
},
/**
* Stops the timer, if it is running.
*/
_cancelTimer: function () {
if (this._timer) {
this._timer.cancel();
this._timer = null;
}
},
/**
* See nsIUpdateTimerManager.idl
*/
registerTimer: function TM_registerTimer(id, callback, interval) {
LOG("TimerManager:registerTimer - id: " + id);
if (id in this._timers && callback != this._timers[id].callback) {
LOG("TimerManager:registerTimer - Ignoring second registration for " + id);
return;
}
let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, id);
// Initialize the last update time to 0 when the preference isn't set so
// the timer will be notified soon after a new profile's first use.
let lastUpdateTime = getPref("getIntPref", prefLastUpdate, 0);
let now = Math.round(Date.now() / 1000);
if (lastUpdateTime > now) {
lastUpdateTime = 0;
}
if (lastUpdateTime == 0) {
Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
}
this._timers[id] = {callback: callback,
interval: interval,
lastUpdateTime: lastUpdateTime};
this._ensureTimer(interval * 1000);
},
classID: Components.ID("{B322A5C0-A419-484E-96BA-D7182163899F}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateTimerManager,
Ci.nsITimerCallback,
Ci.nsIObserver])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TimerManager]);

View file

@ -0,0 +1,3 @@
component {B322A5C0-A419-484E-96BA-D7182163899F} nsUpdateTimerManager.js
contract @mozilla.org/updates/timer-manager;1 {B322A5C0-A419-484E-96BA-D7182163899F}
category profile-after-change nsUpdateTimerManager @mozilla.org/updates/timer-manager;1

View file

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View file

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

View file

@ -0,0 +1,9 @@
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
head =
tail =
[consumerNotifications.js]