| Index: chrome/content/common.js |
| =================================================================== |
| --- a/chrome/content/common.js |
| +++ b/chrome/content/common.js |
| @@ -3,6 +3,11 @@ |
| const Cr = Components.results; |
| const Cu = Components.utils; |
| +const MILLIS_IN_SECOND = 1000; |
| +const MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; |
| +const MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; |
| +const MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; |
| + |
| Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
| Cu.import("resource://gre/modules/Services.jsm"); |
| @@ -40,6 +45,7 @@ |
| let {FilterNotifier} = require("filterNotifier"); |
| let {FilterStorage} = require("filterStorage"); |
| let {ElemHide} = require("elemHide"); |
| +let {Notification} = require("notification"); |
| let {Prefs} = require("prefs"); |
| let {RequestNotifier} = require("requestNotifier"); |
| let {Synchronizer} = require("synchronizer"); |
| @@ -153,6 +159,154 @@ |
| Prefs[pref] = this._pbackup[pref]; |
| } |
| +function setupVirtualTime(processTimers) |
| +{ |
| + let currentTime = 100000 * MILLIS_IN_HOUR; |
| + let startTime = currentTime; |
| + let scheduledTasks = []; |
| + |
| + let modules = Array.prototype.slice.call(arguments, 1); |
| + this._virtualTimeModules = modules; |
| + |
| + for each (let module in this._virtualTimeModules) |
| + { |
| + let global = Cu.getGlobalForObject(getModuleGlobal(module)); |
| + |
| + // Replace Date.now() function |
| + this["_origNow" + module] = global.Date.now; |
| + global.Date.now = function() currentTime; |
| + } |
| + |
| + // Wrap timers |
| + if (processTimers) |
| + { |
| + processTimers(function wrapTimer(timer) |
| + { |
| + let wrapper = {__proto__: timer}; |
| + let callback = timer.callback; |
| + wrapper.handler = function() callback.notify(wrapper); |
| + wrapper.nextExecution = currentTime + timer.delay; |
| + scheduledTasks.push(wrapper); |
| + timer.cancel(); |
| + return wrapper; |
| + }); |
| + } |
| + |
| + // Register observer to track outstanding requests |
| + this._outstandingRequests = 0; |
| + this.observe = function(subject, topic, data) |
| + { |
| + let orig = this._outstandingRequests; |
| + if (topic == "http-on-modify-request") |
| + this._outstandingRequests++; |
| + else if (topic == "http-on-examine-response") |
| + this._outstandingRequests--; |
| + }; |
| + this.QueryInterface = XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]); |
| + Services.obs.addObserver(this, "http-on-modify-request", true); |
| + Services.obs.addObserver(this, "http-on-examine-response", true); |
| + |
| + this.runScheduledTasks = function(maxHours, initial, skip) |
| + { |
| + if (typeof maxHours != "number") |
| + throw new Error("Numerical parameter expected"); |
| + if (typeof initial != "number") |
| + initial = 0; |
| + if (typeof skip != "number") |
| + skip = 0; |
| + |
| + startTime = currentTime; |
| + if (initial >= 0) |
| + { |
| + this._runScheduledTasks(initial); |
| + maxHours -= initial; |
| + } |
| + if (skip) |
| + { |
| + this._skipTasks(skip); |
| + maxHours -= skip; |
| + } |
| + this._runScheduledTasks(maxHours); |
| + } |
| + |
| + this._runScheduledTasks = function(maxHours) |
| + { |
| + let endTime = currentTime + maxHours * MILLIS_IN_HOUR; |
| + while (true) |
| + { |
| + let nextTask = null; |
| + for each (let task in scheduledTasks) |
| + { |
| + if (!nextTask || nextTask.nextExecution > task.nextExecution) |
| + nextTask = task; |
| + } |
| + if (!nextTask || nextTask.nextExecution > endTime) |
| + break; |
| + |
| + currentTime = nextTask.nextExecution; |
| + nextTask.handler(); |
| + |
| + // Let all asynchronous actions finish |
| + let thread = Services.tm.currentThread; |
| + let loopStartTime = Date.now(); |
| + |
| + while (this._outstandingRequests > 0 || thread.hasPendingEvents()) |
| + { |
| + thread.processNextEvent(true); |
| + |
| + if (Date.now() - loopStartTime > 5000) |
| + throw new Error("Test stuck in a download loop"); |
| + } |
| + |
| + if (nextTask.type == Components.interfaces.nsITimer.TYPE_ONE_SHOT) |
| + scheduledTasks = scheduledTasks.filter(function(task) task != nextTask); |
| + else |
| + nextTask.nextExecution = currentTime + nextTask.delay; |
| + } |
| + |
| + currentTime = endTime; |
| + } |
| + |
| + this._skipTasks = function(hours) |
| + { |
| + let newTasks = []; |
| + currentTime += hours * MILLIS_IN_HOUR; |
| + for each (let task in scheduledTasks) |
| + { |
| + if (task.nextExecution >= currentTime) |
| + newTasks.push(task); |
| + else if (task.type != Components.interfaces.nsITimer.TYPE_ONE_SHOT) |
| + { |
| + task.nextExecution = currentTime; |
| + newTasks.push(task); |
| + } |
| + } |
| + scheduledTasks = newTasks; |
| + } |
| + |
| + this.getTimeOffset = function() (currentTime - startTime) / MILLIS_IN_HOUR; |
| + |
| + this.__defineGetter__("currentTime", function() currentTime); |
| +} |
| + |
| +function restoreVirtualTime() |
| +{ |
| + for each (let module in this._virtualTimeModules) |
| + { |
| + let global = Cu.getGlobalForObject(getModuleGlobal(module)); |
| + |
| + // Restore Date.now() function |
| + if ("_origNow" + module in this) |
| + { |
| + global.Date.now = this["_origNow" + module]; |
| + delete this["_origNow" + module]; |
| + } |
| + } |
| + |
| + Services.obs.removeObserver(this, "http-on-modify-request", true); |
| + Services.obs.removeObserver(this, "http-on-examine-response", true); |
| +} |
| + |
| function showProfilingData(debuggerService) |
| { |
| let scripts = []; |