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 = []; |