200 lines
6.6 KiB
JavaScript
200 lines
6.6 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
const { classes: Cc, utils: Cu, interfaces: Ci, results: Cr } = Components;
|
|
|
|
Cu.import("resource://gre/modules/TelemetryController.jsm", this);
|
|
Cu.import("resource://gre/modules/Services.jsm", this);
|
|
|
|
const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
|
|
const gIsMac = ("@mozilla.org/xpcom/mac-utils;1" in Cc);
|
|
const gIsAndroid = ("@mozilla.org/android/bridge;1" in Cc);
|
|
const gIsGonk = ("@mozilla.org/cellbroadcast/gonkservice;1" in Cc);
|
|
|
|
const MILLISECONDS_PER_MINUTE = 60 * 1000;
|
|
const MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE;
|
|
const MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR;
|
|
|
|
const HAS_DATAREPORTINGSERVICE = "@mozilla.org/datareporting/service;1" in Cc;
|
|
|
|
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
|
|
let gOldAppInfo = null;
|
|
let gGlobalScope = this;
|
|
|
|
/**
|
|
* Decode the payload of an HTTP request into a ping.
|
|
* @param {Object} request The data representing an HTTP request (nsIHttpRequest).
|
|
* @return {Object} The decoded ping payload.
|
|
*/
|
|
function decodeRequestPayload(request) {
|
|
let s = request.bodyInputStream;
|
|
let payload = null;
|
|
let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON)
|
|
|
|
if (request.getHeader("content-encoding") == "gzip") {
|
|
let observer = {
|
|
buffer: "",
|
|
onStreamComplete: function(loader, context, status, length, result) {
|
|
this.buffer = String.fromCharCode.apply(this, result);
|
|
}
|
|
};
|
|
|
|
let scs = Cc["@mozilla.org/streamConverters;1"]
|
|
.getService(Ci.nsIStreamConverterService);
|
|
let listener = Cc["@mozilla.org/network/stream-loader;1"]
|
|
.createInstance(Ci.nsIStreamLoader);
|
|
listener.init(observer);
|
|
let converter = scs.asyncConvertData("gzip", "uncompressed",
|
|
listener, null);
|
|
converter.onStartRequest(null, null);
|
|
converter.onDataAvailable(null, null, s, 0, s.available());
|
|
converter.onStopRequest(null, null, null);
|
|
let unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
|
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
|
unicodeConverter.charset = "UTF-8";
|
|
let utf8string = unicodeConverter.ConvertToUnicode(observer.buffer);
|
|
utf8string += unicodeConverter.Finish();
|
|
payload = decoder.decode(utf8string);
|
|
} else {
|
|
payload = decoder.decodeFromStream(s, s.available());
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
|
|
function loadAddonManager(id, name, version, platformVersion) {
|
|
let ns = {};
|
|
Cu.import("resource://gre/modules/Services.jsm", ns);
|
|
let head = "../../../../mozapps/extensions/test/xpcshell/head_addons.js";
|
|
let file = do_get_file(head);
|
|
let uri = ns.Services.io.newFileURI(file);
|
|
ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
|
|
createAppInfo(id, name, version, platformVersion);
|
|
startupManager();
|
|
}
|
|
|
|
function createAppInfo(id, name, version, platformVersion) {
|
|
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
|
|
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
|
|
let gAppInfo;
|
|
if (!gOldAppInfo) {
|
|
gOldAppInfo = Cc[XULAPPINFO_CONTRACTID].getService(Ci.nsIXULRuntime);
|
|
}
|
|
|
|
gAppInfo = {
|
|
// nsIXULAppInfo
|
|
vendor: "Mozilla",
|
|
name: name,
|
|
ID: id,
|
|
version: version,
|
|
appBuildID: "2007010101",
|
|
platformVersion: platformVersion,
|
|
platformBuildID: "2007010101",
|
|
|
|
// nsIXULRuntime
|
|
inSafeMode: false,
|
|
logConsoleErrors: true,
|
|
OS: "XPCShell",
|
|
XPCOMABI: "noarch-spidermonkey",
|
|
invalidateCachesOnRestart: function invalidateCachesOnRestart() {
|
|
// Do nothing
|
|
},
|
|
|
|
// nsICrashReporter
|
|
annotations: {},
|
|
|
|
annotateCrashReport: function(key, data) {
|
|
this.annotations[key] = data;
|
|
},
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
|
|
Ci.nsIXULRuntime,
|
|
Ci.nsICrashReporter,
|
|
Ci.nsISupports])
|
|
};
|
|
|
|
Object.setPrototypeOf(gAppInfo, gOldAppInfo);
|
|
|
|
var XULAppInfoFactory = {
|
|
createInstance: function (outer, iid) {
|
|
if (outer != null)
|
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
|
return gAppInfo.QueryInterface(iid);
|
|
}
|
|
};
|
|
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
|
registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
|
|
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
|
|
}
|
|
|
|
// Fake the timeout functions for the TelemetryScheduler.
|
|
function fakeSchedulerTimer(set, clear) {
|
|
let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
|
|
session.Policy.setSchedulerTickTimeout = set;
|
|
session.Policy.clearSchedulerTickTimeout = clear;
|
|
}
|
|
|
|
/**
|
|
* Fake the current date.
|
|
* This passes all received arguments to a new Date constructor and
|
|
* uses the resulting date to fake the time in Telemetry modules.
|
|
*
|
|
* @return Date The new faked date.
|
|
*/
|
|
function fakeNow(...args) {
|
|
const date = new Date(...args);
|
|
const modules = [
|
|
Cu.import("resource://gre/modules/TelemetrySession.jsm"),
|
|
Cu.import("resource://gre/modules/TelemetryEnvironment.jsm"),
|
|
Cu.import("resource://gre/modules/TelemetryController.jsm"),
|
|
Cu.import("resource://gre/modules/TelemetryStorage.jsm"),
|
|
];
|
|
|
|
for (let m of modules) {
|
|
m.Policy.now = () => date;
|
|
}
|
|
|
|
return new Date(date);
|
|
}
|
|
|
|
// Fake the timeout functions for TelemetryController sending.
|
|
function fakePingSendTimer(set, clear) {
|
|
let ping = Cu.import("resource://gre/modules/TelemetryController.jsm");
|
|
ping.Policy.setPingSendTimeout = set;
|
|
ping.Policy.clearPingSendTimeout = clear;
|
|
}
|
|
|
|
function fakeMidnightPingFuzzingDelay(delayMs) {
|
|
let ping = Cu.import("resource://gre/modules/TelemetryController.jsm");
|
|
ping.Policy.midnightPingFuzzingDelay = () => delayMs;
|
|
}
|
|
|
|
// Return a date that is |offset| ms in the future from |date|.
|
|
function futureDate(date, offset) {
|
|
return new Date(date.getTime() + offset);
|
|
}
|
|
|
|
function truncateToDays(aMsec) {
|
|
return Math.floor(aMsec / MILLISECONDS_PER_DAY);
|
|
}
|
|
|
|
// Returns a promise that resolves to true when the passed promise rejects,
|
|
// false otherwise.
|
|
function promiseRejects(promise) {
|
|
return promise.then(() => false, () => true);
|
|
}
|
|
|
|
// Set logging preferences for all the tests.
|
|
Services.prefs.setCharPref("toolkit.telemetry.log.level", "Trace");
|
|
TelemetryController.initLogging();
|
|
|
|
// Telemetry archiving should be on.
|
|
Services.prefs.setBoolPref("toolkit.telemetry.archive.enabled", true);
|
|
|
|
// Avoid timers interrupting test behavior.
|
|
fakeSchedulerTimer(() => {}, () => {});
|
|
fakePingSendTimer(() => {}, () => {});
|
|
// Make pind sending predictable.
|
|
fakeMidnightPingFuzzingDelay(0);
|