Bug 1120379 - Add tests for the deletion ping. r=gfritzsche

This commit is contained in:
Alessio Placitelli 2015-05-28 08:48:00 +02:00
parent 8b8d56a308
commit d05706c0a0
2 changed files with 300 additions and 267 deletions

View File

@ -1,267 +1,272 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<script type="application/javascript;version=1.7" <script type="application/javascript;version=1.7"
src="healthreport_pingData.js"> src="healthreport_pingData.js">
</script> </script>
<script type="application/javascript;version=1.7"> <script type="application/javascript;version=1.7">
function init() { function init() {
window.addEventListener("message", function process(e) { window.addEventListener("message", function process(e) {
// The init function of abouthealth.js schedules an initial payload event, // The init function of abouthealth.js schedules an initial payload event,
// which will be sent after the payload data has been collected. This extra // which will be sent after the payload data has been collected. This extra
// event can cause unexpected successes/failures in this test, so we wait // event can cause unexpected successes/failures in this test, so we wait
// for the extra event to arrive here before progressing with the actual // for the extra event to arrive here before progressing with the actual
// test. // test.
if (e.data.type == "payload") { if (e.data.type == "payload") {
window.removeEventListener("message", process, false); window.removeEventListener("message", process, false);
window.addEventListener("message", doTest, false); window.addEventListener("message", doTest, false);
doTest(); doTest();
} }
}, false); }, false);
} }
function checkSubmissionValue(payload, expectedValue) { function checkSubmissionValue(payload, expectedValue) {
return payload.enabled == expectedValue; return payload.enabled == expectedValue;
} }
function validatePayload(payload) { function validatePayload(payload) {
payload = JSON.parse(payload); payload = JSON.parse(payload);
// xxxmpc - this is some pretty low-bar validation, but we have plenty of tests of that API elsewhere // xxxmpc - this is some pretty low-bar validation, but we have plenty of tests of that API elsewhere
if (!payload.thisPingDate) if (!payload.thisPingDate)
return false; return false;
return true; return true;
} }
function isArray(arg) { function isArray(arg) {
return Object.prototype.toString.call(arg) === '[object Array]'; return Object.prototype.toString.call(arg) === '[object Array]';
} }
function writeDiagnostic(text) { function writeDiagnostic(text) {
let node = document.createTextNode(text); let node = document.createTextNode(text);
let br = document.createElement("br"); let br = document.createElement("br");
document.body.appendChild(node); document.body.appendChild(node);
document.body.appendChild(br); document.body.appendChild(br);
} }
function validateCurrentTelemetryEnvironment(data) { function validateCurrentTelemetryEnvironment(data) {
// Simple check for now: check that the received object has the expected // Simple check for now: check that the received object has the expected
// top-level properties. // top-level properties.
const expectedKeys = ["profile", "settings", "system", "build", "partner", "addons"]; const expectedKeys = ["profile", "settings", "system", "build", "partner", "addons"];
return expectedKeys.every(key => (key in data)); return expectedKeys.every(key => (key in data));
} }
function validateCurrentTelemetryPingData(ping) { function validateCurrentTelemetryPingData(ping) {
// Simple check for now: check that the received object has the expected // Simple check for now: check that the received object has the expected
// top-level properties and that the type and reason match. // top-level properties and that the type and reason match.
const expectedKeys = ["environment", "clientId", "payload", "application", const expectedKeys = ["environment", "clientId", "payload", "application",
"version", "type", "id"]; "version", "type", "id"];
return expectedKeys.every(key => (key in ping)) && return expectedKeys.every(key => (key in ping)) &&
(ping.type == "main") && (ping.type == "main") &&
("info" in ping.payload) && ("info" in ping.payload) &&
("reason" in ping.payload.info) && ("reason" in ping.payload.info) &&
(ping.payload.info.reason == "gather-subsession-payload"); (ping.payload.info.reason == "gather-subsession-payload");
} }
function validateTelemetryPingList(list) { function validateTelemetryPingList(list) {
if (!isArray(list)) { if (!isArray(list)) {
console.log("Telemetry ping list is not an array."); console.log("Telemetry ping list is not an array.");
return false; return false;
} }
if (list.length != TEST_PINGS.length) { // Telemetry may generate other pings (e.g. "deletion" pings), so filter those
console.log("Telemetry ping length is not correct."); // out.
return false; const TEST_TYPES_REGEX = /^test-telemetryArchive/;
} list = list.filter(p => TEST_TYPES_REGEX.test(p.type));
let valid = true; if (list.length != TEST_PINGS.length) {
for (let i=0; i<list.length; ++i) { console.log("Telemetry ping length is not correct.");
let received = list[i]; return false;
let expected = TEST_PINGS[i]; }
if (received.type != expected.type ||
received.timestampCreated != expected.date.getTime()) { let valid = true;
writeDiagnostic("Telemetry ping " + i + " does not match."); for (let i=0; i<list.length; ++i) {
writeDiagnostic("Expected: " + JSON.stringify(expected)); let received = list[i];
writeDiagnostic("Received: " + JSON.stringify(received)); let expected = TEST_PINGS[i];
valid = false; if (received.type != expected.type ||
} else { received.timestampCreated != expected.date.getTime()) {
writeDiagnostic("Telemetry ping " + i + " matches."); writeDiagnostic("Telemetry ping " + i + " does not match.");
} writeDiagnostic("Expected: " + JSON.stringify(expected));
} writeDiagnostic("Received: " + JSON.stringify(received));
valid = false;
return true; } else {
} writeDiagnostic("Telemetry ping " + i + " matches.");
}
function validateTelemetryPingData(expected, received) { }
const receivedDate = new Date(received.creationDate);
if (received.id != expected.id || return true;
received.type != expected.type || }
receivedDate.getTime() != expected.date.getTime()) {
writeDiagnostic("Telemetry ping data for " + expected.id + " doesn't match."); function validateTelemetryPingData(expected, received) {
writeDiagnostic("Expected: " + JSON.stringify(expected)); const receivedDate = new Date(received.creationDate);
writeDiagnostic("Received: " + JSON.stringify(received)); if (received.id != expected.id ||
return false; received.type != expected.type ||
} receivedDate.getTime() != expected.date.getTime()) {
writeDiagnostic("Telemetry ping data for " + expected.id + " doesn't match.");
writeDiagnostic("Telemetry ping data for " + expected.id + " matched."); writeDiagnostic("Expected: " + JSON.stringify(expected));
return true; writeDiagnostic("Received: " + JSON.stringify(received));
} return false;
}
var tests = [
{ writeDiagnostic("Telemetry ping data for " + expected.id + " matched.");
info: "Checking initial value is enabled", return true;
event: "RequestCurrentPrefs", }
payloadType: "prefs",
validateResponse: function(payload) { var tests = [
return checkSubmissionValue(payload, true); {
}, info: "Checking initial value is enabled",
}, event: "RequestCurrentPrefs",
{ payloadType: "prefs",
info: "Verifying disabling works", validateResponse: function(payload) {
event: "DisableDataSubmission", return checkSubmissionValue(payload, true);
payloadType: "prefs", },
validateResponse: function(payload) { },
return checkSubmissionValue(payload, false); {
}, info: "Verifying disabling works",
}, event: "DisableDataSubmission",
{ payloadType: "prefs",
info: "Verifying we're still disabled", validateResponse: function(payload) {
event: "RequestCurrentPrefs", return checkSubmissionValue(payload, false);
payloadType: "prefs", },
validateResponse: function(payload) { },
return checkSubmissionValue(payload, false); {
}, info: "Verifying we're still disabled",
}, event: "RequestCurrentPrefs",
{ payloadType: "prefs",
info: "Verifying we can get a payload while submission is disabled", validateResponse: function(payload) {
event: "RequestCurrentPayload", return checkSubmissionValue(payload, false);
payloadType: "payload", },
validateResponse: function(payload) { },
return validatePayload(payload); {
}, info: "Verifying we can get a payload while submission is disabled",
}, event: "RequestCurrentPayload",
{ payloadType: "payload",
info: "Verifying enabling works", validateResponse: function(payload) {
event: "EnableDataSubmission", return validatePayload(payload);
payloadType: "prefs", },
validateResponse: function(payload) { },
return checkSubmissionValue(payload, true); {
}, info: "Verifying enabling works",
}, event: "EnableDataSubmission",
{ payloadType: "prefs",
info: "Verifying we're still re-enabled", validateResponse: function(payload) {
event: "RequestCurrentPrefs", return checkSubmissionValue(payload, true);
payloadType: "prefs", },
validateResponse: function(payload) { },
return checkSubmissionValue(payload, true); {
}, info: "Verifying we're still re-enabled",
}, event: "RequestCurrentPrefs",
{ payloadType: "prefs",
info: "Verifying we can get a payload after re-enabling", validateResponse: function(payload) {
event: "RequestCurrentPayload", return checkSubmissionValue(payload, true);
payloadType: "payload", },
validateResponse: function(payload) { },
return validatePayload(payload); {
}, info: "Verifying we can get a payload after re-enabling",
}, event: "RequestCurrentPayload",
{ payloadType: "payload",
info: "Verifying that we can get the current Telemetry environment data", validateResponse: function(payload) {
event: "RequestCurrentEnvironment", return validatePayload(payload);
payloadType: "telemetry-current-environment-data", },
validateResponse: function(payload) { },
return validateCurrentTelemetryEnvironment(payload); {
}, info: "Verifying that we can get the current Telemetry environment data",
}, event: "RequestCurrentEnvironment",
{ payloadType: "telemetry-current-environment-data",
info: "Verifying that we can get the current Telemetry ping data", validateResponse: function(payload) {
event: "RequestCurrentPingData", return validateCurrentTelemetryEnvironment(payload);
payloadType: "telemetry-current-ping-data", },
validateResponse: function(payload) { },
return validateCurrentTelemetryPingData(payload); {
}, info: "Verifying that we can get the current Telemetry ping data",
}, event: "RequestCurrentPingData",
{ payloadType: "telemetry-current-ping-data",
info: "Verifying that we get the proper Telemetry ping list", validateResponse: function(payload) {
event: "RequestTelemetryPingList", return validateCurrentTelemetryPingData(payload);
payloadType: "telemetry-ping-list", },
validateResponse: function(payload) { },
// Validate the ping list {
if (!validateTelemetryPingList(payload)) { info: "Verifying that we get the proper Telemetry ping list",
return false; event: "RequestTelemetryPingList",
} payloadType: "telemetry-ping-list",
validateResponse: function(payload) {
// Now that we received the ping ids, set up additional test tasks // Validate the ping list
// that check loading the individual pings. if (!validateTelemetryPingList(payload)) {
for (let i=0; i<TEST_PINGS.length; ++i) { return false;
TEST_PINGS[i].id = payload[i].id; }
tests.push({
info: "Verifying that we can get the proper Telemetry ping data #" + (i + 1), // Now that we received the ping ids, set up additional test tasks
event: "RequestTelemetryPingData", // that check loading the individual pings.
eventData: { id: TEST_PINGS[i].id }, for (let i=0; i<TEST_PINGS.length; ++i) {
payloadType: "telemetry-ping-data", TEST_PINGS[i].id = payload[i].id;
validateResponse: function(payload) { tests.push({
return validateTelemetryPingData(TEST_PINGS[i], payload.pingData); 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 true; return validateTelemetryPingData(TEST_PINGS[i], payload.pingData);
}, },
}, });
]; }
var currentTest = -1; return true;
function doTest(evt) { },
if (evt) { },
if (currentTest < 0 || !evt.data.content) ];
return; // not yet testing
var currentTest = -1;
var test = tests[currentTest]; function doTest(evt) {
if (evt.data.type != test.payloadType) if (evt) {
return; // skip unrequested events if (currentTest < 0 || !evt.data.content)
return; // not yet testing
var error = JSON.stringify(evt.data.content);
var pass = false; var test = tests[currentTest];
try { if (evt.data.type != test.payloadType)
pass = test.validateResponse(evt.data.content) return; // skip unrequested events
} catch (e) {}
reportResult(test.info, pass, error); var error = JSON.stringify(evt.data.content);
} var pass = false;
// start the next test if there are any left try {
if (tests[++currentTest]) pass = test.validateResponse(evt.data.content)
sendToBrowser(tests[currentTest].event, tests[currentTest].eventData); } catch (e) {}
else reportResult(test.info, pass, error);
reportFinished(); }
} // start the next test if there are any left
if (tests[++currentTest])
function reportResult(info, pass, error) { sendToBrowser(tests[currentTest].event, tests[currentTest].eventData);
var data = {type: "testResult", info: info, pass: pass, error: error}; else
var event = new CustomEvent("FirefoxHealthReportTestResponse", {detail: {data: data}, bubbles: true}); reportFinished();
document.dispatchEvent(event); }
}
function reportResult(info, pass, error) {
function reportFinished(cmd) { var data = {type: "testResult", info: info, pass: pass, error: error};
var data = {type: "testsComplete", count: tests.length}; var event = new CustomEvent("FirefoxHealthReportTestResponse", {detail: {data: data}, bubbles: true});
var event = new CustomEvent("FirefoxHealthReportTestResponse", {detail: {data: data}, bubbles: true}); document.dispatchEvent(event);
document.dispatchEvent(event); }
}
function reportFinished(cmd) {
function sendToBrowser(type, eventData) { var data = {type: "testsComplete", count: tests.length};
eventData = eventData || {}; var event = new CustomEvent("FirefoxHealthReportTestResponse", {detail: {data: data}, bubbles: true});
let detail = {command: type}; document.dispatchEvent(event);
for (let key of Object.keys(eventData)) { }
detail[key] = eventData[key];
} function sendToBrowser(type, eventData) {
eventData = eventData || {};
var event = new CustomEvent("RemoteHealthReportCommand", {detail: detail, bubbles: true}); let detail = {command: type};
document.dispatchEvent(event); for (let key of Object.keys(eventData)) {
} detail[key] = eventData[key];
}
</script>
</head> var event = new CustomEvent("RemoteHealthReportCommand", {detail: detail, bubbles: true});
<body onload="init()"> document.dispatchEvent(event);
</body> }
</html>
</script>
</head>
<body onload="init()">
</body>
</html>

View File

@ -21,6 +21,7 @@ Cu.import("resource://gre/modules/Promise.jsm", this);
Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/Preferences.jsm");
const PING_FORMAT_VERSION = 4; const PING_FORMAT_VERSION = 4;
const DELETION_PING_TYPE = "deletion";
const TEST_PING_TYPE = "test-ping-type"; const TEST_PING_TYPE = "test-ping-type";
const PLATFORM_VERSION = "1.9.2"; const PLATFORM_VERSION = "1.9.2";
@ -174,6 +175,25 @@ add_task(function* test_simplePing() {
checkPingFormat(ping, TEST_PING_TYPE, false, false); checkPingFormat(ping, TEST_PING_TYPE, false, false);
}); });
add_task(function* test_deletionPing() {
const isUnified = Preferences.get(PREF_UNIFIED, false);
if (!isUnified) {
// Skipping the test if unified telemetry is off, as no deletion ping will
// be generated.
return;
}
// Disable FHR upload: this should trigger a deletion ping.
Preferences.set(PREF_FHR_UPLOAD_ENABLED, false);
let request = yield gRequestIterator.next();
let ping = decodeRequestPayload(request);
checkPingFormat(ping, DELETION_PING_TYPE, true, false);
// Restore FHR Upload.
Preferences.set(PREF_FHR_UPLOAD_ENABLED, true);
});
add_task(function* test_pingHasClientId() { add_task(function* test_pingHasClientId() {
// Send a ping with a clientId. // Send a ping with a clientId.
yield sendPing(true, false); yield sendPing(true, false);
@ -231,6 +251,14 @@ add_task(function* test_archivePings() {
const uploadPref = isUnified ? PREF_FHR_UPLOAD_ENABLED : PREF_ENABLED; const uploadPref = isUnified ? PREF_FHR_UPLOAD_ENABLED : PREF_ENABLED;
Preferences.set(uploadPref, false); Preferences.set(uploadPref, false);
// If we're using unified telemetry, disabling ping upload will generate a "deletion"
// ping. Catch it.
if (isUnified) {
let request = yield gRequestIterator.next();
let ping = decodeRequestPayload(request);
checkPingFormat(ping, DELETION_PING_TYPE, true, false);
}
// Register a new Ping Handler that asserts if a ping is received, then send a ping. // Register a new Ping Handler that asserts if a ping is received, then send a ping.
registerPingHandler(() => Assert.ok(false, "Telemetry must not send pings if not allowed to.")); registerPingHandler(() => Assert.ok(false, "Telemetry must not send pings if not allowed to."));
let pingId = yield sendPing(true, true); let pingId = yield sendPing(true, true);