Bug 1134272 - Enable TelemetryPing.jsm to send pings in the old format. r=gfritzsche

This commit is contained in:
Alessio Placitelli 2015-02-25 23:54:34 +01:00
parent b7fe82a149
commit 450d6f4085
3 changed files with 112 additions and 9 deletions

View File

@ -259,7 +259,9 @@ this.TelemetryFile = {
///// Utility functions
function pingFilePath(ping) {
return OS.Path.join(TelemetryFile.pingDirectoryPath, ping.id);
// Support legacy ping formats, who don't have an "id" field, but a "slug" field.
let pingIdentifier = (ping.slug) ? ping.slug : ping.id;
return OS.Path.join(TelemetryFile.pingDirectoryPath, pingIdentifier);
}
function getPingDirectory() {

View File

@ -94,6 +94,14 @@ function generateUUID() {
return str.substring(1, str.length - 1);
}
/**
* Determine if the ping has new ping format or a legacy one.
*/
function isNewPingFormat(aPing) {
return ("id" in aPing) && ("application" in aPing) &&
("version" in aPing) && (aPing.version >= 2);
}
this.EXPORTED_SYMBOLS = ["TelemetryPing"];
this.TelemetryPing = Object.freeze({
@ -511,13 +519,35 @@ let Impl = {
},
submissionPath: function submissionPath(ping) {
let app = ping.application;
// We insert the Ping id in the URL to simplify server handling of duplicated
// pings.
let pathComponents = [ping.id, ping.type, app.name, app.version,
app.channel, app.buildId];
let slug = pathComponents.join("/");
// The new ping format contains an "application" section, the old one doesn't.
let pathComponents;
if (isNewPingFormat(ping)) {
// We insert the Ping id in the URL to simplify server handling of duplicated
// pings.
let app = ping.application;
pathComponents = [
ping.id, ping.type, app.name, app.version, app.channel, app.buildId
];
} else {
// This is a ping in the old format.
if (!("slug" in ping)) {
// That's odd, we don't have a slug. Generate one so that TelemetryFile.jsm works.
ping.slug = generateUUID();
}
// Do we have enough info to build a submission URL?
let payload = ("payload" in ping) ? ping.payload : null;
if (payload && ("info" in payload)) {
let info = ping.payload.info;
pathComponents = [ ping.slug, info.reason, info.appName, info.appVersion,
info.appUpdateChannel, info.appBuildID ];
} else {
// Only use the UUID as the slug.
pathComponents = [ ping.slug ];
}
}
let slug = pathComponents.join("/");
return "/submit/telemetry/" + slug;
},
@ -556,11 +586,13 @@ let Impl = {
request.addEventListener("error", handler(false).bind(this), false);
request.addEventListener("load", handler(true).bind(this), false);
// If that's a legacy ping format, just send its payload.
let networkPayload = isNewPingFormat(ping) ? ping : ping.payload;
request.setRequestHeader("Content-Encoding", "gzip");
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let utf8Payload = converter.ConvertFromUnicode(JSON.stringify(ping));
let utf8Payload = converter.ConvertFromUnicode(JSON.stringify(networkPayload));
utf8Payload += converter.Finish();
let payloadStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);

View File

@ -43,10 +43,11 @@ const PING_SAVE_FOLDER = "saved-telemetry-pings";
const PING_TIMEOUT_LENGTH = 5000;
const EXPIRED_PINGS = 5;
const OVERDUE_PINGS = 6;
const OLD_FORMAT_PINGS = 4;
const RECENT_PINGS = 4;
const LRU_PINGS = TelemetryFile.MAX_LRU_PINGS;
const TOTAL_EXPECTED_PINGS = OVERDUE_PINGS + RECENT_PINGS;
const TOTAL_EXPECTED_PINGS = OVERDUE_PINGS + RECENT_PINGS + OLD_FORMAT_PINGS;
let gHttpServer = new HttpServer();
let gCreatedPings = 0;
@ -262,6 +263,74 @@ add_task(function* test_most_recent_pings_kept() {
yield clearPings(pings);
});
/**
* Create an overdue ping in the old format and try to send it.
*/
add_task(function* test_overdue_old_format() {
// A test ping in the old, standard format.
const PING_OLD_FORMAT = {
slug: "1234567abcd",
reason: "test-ping",
payload: {
info: {
reason: "test-ping",
OS: "XPCShell",
appID: "SomeId",
appVersion: "1.0",
appName: "XPCShell",
appBuildID: "123456789",
appUpdateChannel: "Test",
platformBuildID: "987654321",
},
},
};
// A ping with no info section, but with a slug.
const PING_NO_INFO = {
slug: "1234-no-info-ping",
reason: "test-ping",
payload: {}
};
// A ping with no payload.
const PING_NO_PAYLOAD = {
slug: "5678-no-payload",
reason: "test-ping",
};
// A ping with no info and no slug.
const PING_NO_SLUG = {
reason: "test-ping",
payload: {}
};
const PING_FILES_PATHS = [
Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, PING_OLD_FORMAT.slug),
Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, PING_NO_INFO.slug),
Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, PING_NO_PAYLOAD.slug),
Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, "no-slug-file"),
];
// Write the ping to file and make it overdue.
yield TelemetryFile.savePing(PING_OLD_FORMAT, true);
yield TelemetryFile.savePing(PING_NO_INFO, true);
yield TelemetryFile.savePing(PING_NO_PAYLOAD, true);
yield TelemetryFile.savePingToFile(PING_NO_SLUG, PING_FILES_PATHS[3], true);
for (let f in PING_FILES_PATHS) {
yield File.setDates(PING_FILES_PATHS[f], null, Date.now() - OVERDUE_PING_FILE_AGE);
}
yield startTelemetry();
assertReceivedPings(OLD_FORMAT_PINGS);
// |TelemetryFile.cleanup| doesn't know how to remove a ping with no slug or id,
// so remove it manually so that the next test doesn't fail.
yield OS.File.remove(PING_FILES_PATHS[3]);
yield resetTelemetry();
});
/**
* Create some recent, expired and overdue pings. The overdue pings should
* trigger a send of all recent and overdue pings, but the expired pings