Bug 1150115 - Update the SelfSupport API for the unification changes. r=bsmedberg,smaug

This commit is contained in:
Georg Fritzsche 2015-06-02 13:35:06 +07:00
parent dfe6365f6a
commit 68261bc92e
7 changed files with 324 additions and 14 deletions

View File

@ -49,6 +49,51 @@ let healthReportWrapper = {
}
},
sendTelemetryPingList: function () {
console.log("AboutHealthReport: Collecting Telemetry ping list.");
MozSelfSupport.getTelemetryPingList().then((list) => {
console.log("AboutHealthReport: Sending Telemetry ping list.");
this.injectData("telemetry-ping-list", list);
}).catch((ex) => {
console.log("AboutHealthReport: Collecting ping list failed: " + ex);
});
},
sendTelemetryPingData: function (pingId) {
console.log("AboutHealthReport: Collecting Telemetry ping data.");
MozSelfSupport.getTelemetryPing(pingId).then((ping) => {
console.log("AboutHealthReport: Sending Telemetry ping data.");
this.injectData("telemetry-ping-data", {
id: pingId,
pingData: ping,
});
}).catch((ex) => {
console.log("AboutHealthReport: Loading ping data failed: " + ex);
this.injectData("telemetry-ping-data", {
id: pingId,
error: "error-generic",
});
});
},
sendCurrentEnvironment: function () {
console.log("AboutHealthReport: Sending Telemetry environment data.");
MozSelfSupport.getCurrentTelemetryEnvironment().then((environment) => {
this.injectData("telemetry-current-environment-data", environment);
}).catch((ex) => {
console.log("AboutHealthReport: Collecting current environment data failed: " + ex);
});
},
sendCurrentPingData: function () {
console.log("AboutHealthReport: Sending current Telemetry ping data.");
MozSelfSupport.getCurrentTelemetrySubsessionPing().then((ping) => {
this.injectData("telemetry-current-ping-data", ping);
}).catch((ex) => {
console.log("AboutHealthReport: Collecting current ping data failed: " + ex);
});
},
refreshPayload: function () {
MozSelfSupport.getHealthReportPayload().then(this.updatePayload,
this.handlePayloadFailure);
@ -88,6 +133,18 @@ let healthReportWrapper = {
case "RequestCurrentPayload":
this.refreshPayload();
break;
case "RequestTelemetryPingList":
this.sendTelemetryPingList();
break;
case "RequestTelemetryPingData":
this.sendTelemetryPingData(evt.detail.id);
break;
case "RequestCurrentEnvironment":
this.sendCurrentEnvironment();
break;
case "RequestCurrentPingData":
this.sendCurrentPingData();
break;
default:
Cu.reportError("Unexpected remote command received: " + evt.detail.command + ". Ignoring command.");
break;

View File

@ -64,6 +64,7 @@ support-files =
file_fullscreen-window-open.html
get_user_media.html
head.js
healthreport_pingData.js
healthreport_testRemoteCommands.html
moz.png
navigating_window_with_download.html

View File

@ -7,8 +7,20 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
const CHROME_BASE = "chrome://mochitests/content/browser/browser/base/content/test/general/";
const HTTPS_BASE = "https://example.com/browser/browser/base/content/test/general/";
const TELEMETRY_LOG_PREF = "toolkit.telemetry.log.level";
const telemetryOriginalLogPref = Preferences.get(TELEMETRY_LOG_PREF, null);
registerCleanupFunction(function() {
// Ensure we don't pollute prefs for next tests.
if (telemetryOriginalLogPref) {
Preferences.set(TELEMETRY_LOG_PREF, telemetryOriginalLogPref);
} else {
Preferences.reset(TELEMETRY_LOG_PREF);
}
try {
Services.prefs.clearUserPref("datareporting.healthreport.about.reportUrl");
let policy = Cc["@mozilla.org/datareporting/service;1"]
@ -20,15 +32,45 @@ registerCleanupFunction(function() {
} catch (ex) {}
});
function fakeTelemetryNow(...args) {
let date = new Date(...args);
let scope = {};
const modules = [
Cu.import("resource://gre/modules/TelemetrySession.jsm", scope),
Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", scope),
Cu.import("resource://gre/modules/TelemetryController.jsm", scope),
];
for (let m of modules) {
m.Policy.now = () => new Date(date);
}
return date;
}
function setupPingArchive() {
let scope = {};
Cu.import("resource://gre/modules/TelemetryController.jsm", scope);
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
.loadSubScript(CHROME_BASE + "healthreport_pingData.js", scope);
for (let p of scope.TEST_PINGS) {
fakeTelemetryNow(p.date);
p.id = yield scope.TelemetryController.submitExternalPing(p.type, p.payload);
}
}
let gTests = [
{
desc: "Test the remote commands",
setup: function ()
setup: Task.async(function*()
{
Services.prefs.setCharPref("datareporting.healthreport.about.reportUrl",
"https://example.com/browser/browser/base/content/test/general/healthreport_testRemoteCommands.html");
},
Preferences.set(TELEMETRY_LOG_PREF, "Trace");
yield setupPingArchive();
Preferences.set("datareporting.healthreport.about.reportUrl",
HTTPS_BASE + "healthreport_testRemoteCommands.html");
}),
run: function (iframe)
{
let deferred = Promise.defer();
@ -61,7 +103,6 @@ let gTests = [
}
},
]; // gTests
function test()
@ -74,7 +115,7 @@ function test()
Task.spawn(function () {
for (let test of gTests) {
info(test.desc);
test.setup();
yield test.setup();
let iframe = yield promiseNewTabLoadEvent("about:healthreport");
@ -105,4 +146,3 @@ function promiseNewTabLoadEvent(aUrl, aEventType="load")
}, true);
return deferred.promise;
}

View File

@ -0,0 +1,17 @@
const TEST_PINGS = [
{
type: "test-telemetryArchive-1",
payload: { foo: "bar" },
date: new Date(2010, 1, 1, 10, 0, 0),
},
{
type: "test-telemetryArchive-2",
payload: { x: { y: "z"} },
date: new Date(2010, 1, 1, 11, 0, 0),
},
{
type: "test-telemetryArchive-3",
payload: { moo: "meh" },
date: new Date(2010, 1, 1, 12, 0, 0),
},
];

View File

@ -1,8 +1,10 @@
<html>
<head>
<meta charset="utf-8">
<script>
<script type="application/javascript;version=1.7"
src="healthreport_pingData.js">
</script>
<script type="application/javascript;version=1.7">
function init() {
window.addEventListener("message", function process(e) {
@ -34,6 +36,80 @@ function validatePayload(payload) {
return true;
}
function isArray(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
}
function writeDiagnostic(text) {
let node = document.createTextNode(text);
let br = document.createElement("br");
document.body.appendChild(node);
document.body.appendChild(br);
}
function validateCurrentTelemetryEnvironment(data) {
// Simple check for now: check that the received object has the expected
// top-level properties.
const expectedKeys = ["profile", "settings", "system", "build", "partner", "addons"];
return expectedKeys.every(key => (key in data));
}
function validateCurrentTelemetryPingData(ping) {
// Simple check for now: check that the received object has the expected
// top-level properties and that the type and reason match.
const expectedKeys = ["environment", "clientId", "payload", "application",
"version", "type", "id"];
return expectedKeys.every(key => (key in ping)) &&
(ping.type == "main") &&
("info" in ping.payload) &&
("reason" in ping.payload.info) &&
(ping.payload.info.reason == "gather-subsession-payload");
}
function validateTelemetryPingList(list) {
if (!isArray(list)) {
console.log("Telemetry ping list is not an array.");
return false;
}
if (list.length != TEST_PINGS.length) {
console.log("Telemetry ping length is not correct.");
return false;
}
let valid = true;
for (let i=0; i<list.length; ++i) {
let received = list[i];
let expected = TEST_PINGS[i];
if (received.type != expected.type ||
received.timestampCreated != expected.date.getTime()) {
writeDiagnostic("Telemetry ping " + i + " does not match.");
writeDiagnostic("Expected: " + JSON.stringify(expected));
writeDiagnostic("Received: " + JSON.stringify(received));
valid = false;
} else {
writeDiagnostic("Telemetry ping " + i + " matches.");
}
}
return true;
}
function validateTelemetryPingData(expected, received) {
const receivedDate = new Date(received.creationDate);
if (received.id != expected.id ||
received.type != expected.type ||
receivedDate.getTime() != expected.date.getTime()) {
writeDiagnostic("Telemetry ping data for " + expected.id + " doesn't match.");
writeDiagnostic("Expected: " + JSON.stringify(expected));
writeDiagnostic("Received: " + JSON.stringify(received));
return false;
}
writeDiagnostic("Telemetry ping data for " + expected.id + " matched.");
return true;
}
var tests = [
{
info: "Checking initial value is enabled",
@ -91,6 +167,50 @@ var tests = [
return validatePayload(payload);
},
},
{
info: "Verifying that we can get the current Telemetry environment data",
event: "RequestCurrentEnvironment",
payloadType: "telemetry-current-environment-data",
validateResponse: function(payload) {
return validateCurrentTelemetryEnvironment(payload);
},
},
{
info: "Verifying that we can get the current Telemetry ping data",
event: "RequestCurrentPingData",
payloadType: "telemetry-current-ping-data",
validateResponse: function(payload) {
return validateCurrentTelemetryPingData(payload);
},
},
{
info: "Verifying that we get the proper Telemetry ping list",
event: "RequestTelemetryPingList",
payloadType: "telemetry-ping-list",
validateResponse: function(payload) {
// Validate the ping list
if (!validateTelemetryPingList(payload)) {
return false;
}
// Now that we received the ping ids, set up additional test tasks
// that check loading the individual pings.
for (let i=0; i<TEST_PINGS.length; ++i) {
TEST_PINGS[i].id = payload[i].id;
tests.push({
info: "Verifying that we can get the proper Telemetry ping data #" + (i + 1),
event: "RequestTelemetryPingData",
eventData: { id: TEST_PINGS[i].id },
payloadType: "telemetry-ping-data",
validateResponse: function(payload) {
return validateTelemetryPingData(TEST_PINGS[i], payload.pingData);
},
});
}
return true;
},
},
];
var currentTest = -1;
@ -112,7 +232,7 @@ function doTest(evt) {
}
// start the next test if there are any left
if (tests[++currentTest])
sendToBrowser(tests[currentTest].event);
sendToBrowser(tests[currentTest].event, tests[currentTest].eventData);
else
reportFinished();
}
@ -129,8 +249,14 @@ function reportFinished(cmd) {
document.dispatchEvent(event);
}
function sendToBrowser(type) {
var event = new CustomEvent("RemoteHealthReportCommand", {detail: {command: type}, bubbles: true});
function sendToBrowser(type, eventData) {
eventData = eventData || {};
let detail = {command: type};
for (let key of Object.keys(eventData)) {
detail[key] = eventData[key];
}
var event = new CustomEvent("RemoteHealthReportCommand", {detail: detail, bubbles: true});
document.dispatchEvent(event);
}

View File

@ -21,6 +21,13 @@ XPCOMUtils.defineLazyGetter(this, "reporter", () => {
.healthReporter;
});
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryArchive",
"resource://gre/modules/TelemetryArchive.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
"resource://gre/modules/TelemetryEnvironment.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryController",
"resource://gre/modules/TelemetryController.jsm");
function MozSelfSupportInterface() {
}
@ -73,6 +80,29 @@ MozSelfSupportInterface.prototype = {
Services.search.restoreDefaultEngines();
Services.search.resetToOriginalDefaultEngine();
},
getTelemetryPingList: function() {
return this._wrapPromise(TelemetryArchive.promiseArchivedPingList());
},
getTelemetryPing: function(pingId) {
return this._wrapPromise(TelemetryArchive.promiseArchivedPingById(pingId));
},
getCurrentTelemetryEnvironment: function() {
const current = TelemetryEnvironment.currentEnvironment;
return new this._window.Promise(resolve => resolve(current));
},
getCurrentTelemetrySubsessionPing: function() {
const current = TelemetryController.getCurrentPingData(true);
return new this._window.Promise(resolve => resolve(current));
},
_wrapPromise: function(promise) {
return new this._window.Promise(
(resolve, reject) => promise.then(resolve, reject));
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozSelfSupportInterface]);

View File

@ -40,6 +40,45 @@ interface MozSelfSupport
*/
Promise<object> getHealthReportPayload();
/**
* Retrieve a list of the archived Telemetry pings.
* This contains objects with ping info, which are of the form:
* {
* type: <string>, // The pings type, e.g. "main", "environment-change", ...
* timestampCreated: <number>, // The time the ping was created (ms since unix epoch).
* id: <string>, // The pings UUID.
* }
*
* @return Promise<sequence<Object>>
* Resolved with the ping infos when the archived ping list has been built.
*/
Promise<sequence<object>> getTelemetryPingList();
/**
* Retrieve an archived Telemetry ping by it's id.
* This will load the ping data async from the archive, possibly hitting the disk.
*
* @return Promise<Object>
* Resolved with the ping data, see the Telemetry "main" ping documentation for the format.
*/
Promise<object> getTelemetryPing(DOMString pingID);
/**
* Get the current Telemetry environment - see the Telemetry documentation for details on the format.
*
* @return Promise<Object>
* Resolved with an object containing the Telemetry environment data.
*/
Promise<object> getCurrentTelemetryEnvironment();
/**
* Get a Telemetry "main" ping containing the current session measurements.
*
* @return Promise<Object>
* Resolved with the ping data, see the Telemetry "main" ping documentation for the format.
*/
Promise<object> getCurrentTelemetrySubsessionPing();
/**
* Resets a named pref:
* - if there is a default value, then change the value back to default,