fune/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js
Kris Maglione 96f3e16d1a Bug 1482091: Part 2 - Remove TelemetryStopwatch.jsm in favor of native implementation. r=chutten
Differential Revision: https://phabricator.services.mozilla.com/D9888

--HG--
extra : rebase_source : a9daea3a9efea37acdbcaecda8bf0b7f69631de4
extra : histedit_source : bb8b416b1387da9de3bd95c7a171f10426a22602
2018-10-25 19:04:01 -07:00

680 lines
28 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
*/
// This tests the public Telemetry API for submitting pings.
"use strict";
ChromeUtils.import("resource://gre/modules/TelemetryController.jsm", this);
ChromeUtils.import("resource://testing-common/ContentTaskUtils.jsm", this);
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetrySession.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetrySend.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetryStorage.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetryUtils.jsm", this);
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
ChromeUtils.import("resource://gre/modules/osfile.jsm", this);
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
ChromeUtils.defineModuleGetter(this, "TelemetryHealthPing",
"resource://gre/modules/HealthPing.jsm");
XPCOMUtils.defineLazyServiceGetter(Services, "cookies", "@mozilla.org/cookieService;1", "nsICookieService");
const MS_IN_A_MINUTE = 60 * 1000;
function countPingTypes(pings) {
let countByType = new Map();
for (let p of pings) {
countByType.set(p.type, 1 + (countByType.get(p.type) || 0));
}
return countByType;
}
function setPingLastModified(id, timestamp) {
const path = OS.Path.join(TelemetryStorage.pingDirectoryPath, id);
return OS.File.setDates(path, null, timestamp);
}
// Mock out the send timer activity.
function waitForTimer() {
return new Promise(resolve => {
fakePingSendTimer((callback, timeout) => {
resolve([callback, timeout]);
}, () => {});
});
}
// Allow easy faking of readable ping ids.
// This helps with debugging issues with e.g. ordering in the send logic.
function fakePingId(type, number) {
const HEAD = "93bd0011-2c8f-4e1c-bee0-";
const TAIL = "000000000000";
const N = String(number);
const id = HEAD + type + TAIL.slice(type.length, -N.length) + N;
fakeGeneratePingId(() => id);
return id;
}
var checkPingsSaved = async function(pingIds) {
let allFound = true;
for (let id of pingIds) {
const path = OS.Path.join(TelemetryStorage.pingDirectoryPath, id);
let exists = false;
try {
exists = await OS.File.exists(path);
} catch (ex) {}
if (!exists) {
dump("checkPingsSaved - failed to find ping: " + path + "\n");
allFound = false;
}
}
return allFound;
};
function histogramValueCount(h) {
return Object.values(h.values).reduce((a, b) => a + b, 0);
}
add_task(async function test_setup() {
// Trigger a proper telemetry init.
do_get_profile(true);
// Make sure we don't generate unexpected pings due to pref changes.
await setEmptyPrefWatchlist();
Services.prefs.setBoolPref(TelemetryUtils.Preferences.HealthPingEnabled, true);
TelemetryStopwatch.setTestModeEnabled(true);
});
// Test the ping sending logic.
add_task(async function test_sendPendingPings() {
const TYPE_PREFIX = "test-sendPendingPings-";
const TEST_TYPE_A = TYPE_PREFIX + "A";
const TEST_TYPE_B = TYPE_PREFIX + "B";
const TYPE_A_COUNT = 20;
const TYPE_B_COUNT = 5;
let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
histSuccess.clear();
histSendTimeSuccess.clear();
histSendTimeFail.clear();
// Fake a current date.
let now = TelemetryUtils.truncateToDays(new Date());
now = fakeNow(futureDate(now, 10 * 60 * MS_IN_A_MINUTE));
// Enable test-mode for TelemetrySend, otherwise we won't store pending pings
// before the module is fully initialized later.
TelemetrySend.setTestModeEnabled(true);
// Submit some pings without the server and telemetry started yet.
for (let i = 0; i < TYPE_A_COUNT; ++i) {
fakePingId("a", i);
const id = await TelemetryController.submitExternalPing(TEST_TYPE_A, {});
await setPingLastModified(id, now.getTime() + (i * 1000));
}
Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT,
"Should have correct pending ping count");
// Submit some more pings of a different type.
now = fakeNow(futureDate(now, 5 * MS_IN_A_MINUTE));
for (let i = 0; i < TYPE_B_COUNT; ++i) {
fakePingId("b", i);
const id = await TelemetryController.submitExternalPing(TEST_TYPE_B, {});
await setPingLastModified(id, now.getTime() + (i * 1000));
}
Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT + TYPE_B_COUNT,
"Should have correct pending ping count");
Assert.deepEqual(histSuccess.snapshot().values, {},
"Should not have recorded any sending in histograms yet.");
Assert.equal(histSendTimeSuccess.snapshot().sum, 0,
"Should not have recorded any sending in histograms yet.");
Assert.equal(histSendTimeFail.snapshot().sum, 0,
"Should not have recorded any sending in histograms yet.");
// Now enable sending to the ping server.
now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
PingServer.start();
Services.prefs.setStringPref(TelemetryUtils.Preferences.Server, "http://localhost:" + PingServer.port);
let timerPromise = waitForTimer();
await TelemetryController.testReset();
let [pingSendTimerCallback, pingSendTimeout] = await timerPromise;
Assert.ok(!!pingSendTimerCallback, "Should have a timer callback");
// We should have received 10 pings from the first send batch:
// 5 of type B and 5 of type A, as sending is newest-first.
// The other pings should be delayed by the 10-pings-per-minute limit.
let pings = await PingServer.promiseNextPings(10);
Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT - 5,
"Should have correct pending ping count");
PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
let countByType = countPingTypes(pings);
Assert.equal(countByType.get(TEST_TYPE_B), TYPE_B_COUNT,
"Should have received the correct amount of type B pings");
Assert.equal(countByType.get(TEST_TYPE_A), 10 - TYPE_B_COUNT,
"Should have received the correct amount of type A pings");
Assert.deepEqual(histSuccess.snapshot().values, {0: 0, 1: 10, 2: 0},
"Should have recorded sending success in histograms.");
Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 10,
"Should have recorded successful send times in histograms.");
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0,
"Should not have recorded any failed sending in histograms yet.");
// As we hit the ping send limit and still have pending pings, a send tick should
// be scheduled in a minute.
Assert.ok(!!pingSendTimerCallback, "Timer callback should be set");
Assert.equal(pingSendTimeout, MS_IN_A_MINUTE, "Send tick timeout should be correct");
// Trigger the next tick - we should receive the next 10 type A pings.
PingServer.resetPingHandler();
now = fakeNow(futureDate(now, pingSendTimeout));
timerPromise = waitForTimer();
pingSendTimerCallback();
[pingSendTimerCallback, pingSendTimeout] = await timerPromise;
pings = await PingServer.promiseNextPings(10);
PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
countByType = countPingTypes(pings);
Assert.equal(countByType.get(TEST_TYPE_A), 10, "Should have received the correct amount of type A pings");
// We hit the ping send limit again and still have pending pings, a send tick should
// be scheduled in a minute.
Assert.equal(pingSendTimeout, MS_IN_A_MINUTE, "Send tick timeout should be correct");
// Trigger the next tick - we should receive the remaining type A pings.
PingServer.resetPingHandler();
now = fakeNow(futureDate(now, pingSendTimeout));
await pingSendTimerCallback();
pings = await PingServer.promiseNextPings(5);
PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
countByType = countPingTypes(pings);
Assert.equal(countByType.get(TEST_TYPE_A), 5, "Should have received the correct amount of type A pings");
await TelemetrySend.testWaitOnOutgoingPings();
PingServer.resetPingHandler();
// Restore the default ping id generator.
fakeGeneratePingId(() => TelemetryUtils.generateUUID());
});
add_task(async function test_sendDateHeader() {
fakeNow(new Date(Date.UTC(2011, 1, 1, 11, 0, 0)));
await TelemetrySend.reset();
let pingId = await TelemetryController.submitExternalPing("test-send-date-header", {});
let req = await PingServer.promiseNextRequest();
let ping = decodeRequestPayload(req);
Assert.equal(req.getHeader("Date"), "Tue, 01 Feb 2011 11:00:00 GMT",
"Telemetry should send the correct Date header with requests.");
Assert.equal(ping.id, pingId, "Should have received the correct ping id.");
});
// Test the backoff timeout behavior after send failures.
add_task(async function test_backoffTimeout() {
const TYPE_PREFIX = "test-backoffTimeout-";
const TEST_TYPE_C = TYPE_PREFIX + "C";
const TEST_TYPE_D = TYPE_PREFIX + "D";
const TEST_TYPE_E = TYPE_PREFIX + "E";
let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
// Failing a ping send now should trigger backoff behavior.
let now = fakeNow(2010, 1, 1, 11, 0, 0);
await TelemetrySend.reset();
PingServer.stop();
histSuccess.clear();
histSendTimeSuccess.clear();
histSendTimeFail.clear();
fakePingId("c", 0);
now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
let sendAttempts = 0;
let timerPromise = waitForTimer();
await TelemetryController.submitExternalPing(TEST_TYPE_C, {});
let [pingSendTimerCallback, pingSendTimeout] = await timerPromise;
Assert.equal(TelemetrySend.pendingPingCount, 1, "Should have one pending ping.");
++sendAttempts;
const MAX_BACKOFF_TIMEOUT = 120 * MS_IN_A_MINUTE;
for (let timeout = 2 * MS_IN_A_MINUTE; timeout <= MAX_BACKOFF_TIMEOUT; timeout *= 2) {
Assert.ok(!!pingSendTimerCallback, "Should have received a timer callback");
Assert.equal(pingSendTimeout, timeout, "Send tick timeout should be correct");
let callback = pingSendTimerCallback;
now = fakeNow(futureDate(now, pingSendTimeout));
timerPromise = waitForTimer();
await callback();
[pingSendTimerCallback, pingSendTimeout] = await timerPromise;
++sendAttempts;
}
timerPromise = waitForTimer();
await pingSendTimerCallback();
[pingSendTimerCallback, pingSendTimeout] = await timerPromise;
Assert.equal(pingSendTimeout, MAX_BACKOFF_TIMEOUT, "Tick timeout should be capped");
++sendAttempts;
Assert.deepEqual(histSuccess.snapshot().values, {0: sendAttempts, 1: 0},
"Should have recorded sending failure in histograms.");
Assert.equal(histSendTimeSuccess.snapshot().sum, 0,
"Should not have recorded any sending success in histograms yet.");
Assert.greaterOrEqual(histSendTimeFail.snapshot().sum, 0,
"Should have recorded send failure times in histograms.");
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), sendAttempts,
"Should have recorded send failure times in histograms.");
// Submitting a new ping should reset the backoff behavior.
fakePingId("d", 0);
now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
timerPromise = waitForTimer();
await TelemetryController.submitExternalPing(TEST_TYPE_D, {});
[pingSendTimerCallback, pingSendTimeout] = await timerPromise;
Assert.equal(pingSendTimeout, 2 * MS_IN_A_MINUTE, "Send tick timeout should be correct");
sendAttempts += 2;
// With the server running again, we should send out the pending pings immediately
// when a new ping is submitted.
PingServer.start();
TelemetrySend.setServer("http://localhost:" + PingServer.port);
fakePingId("e", 0);
now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
timerPromise = waitForTimer();
await TelemetryController.submitExternalPing(TEST_TYPE_E, {});
let pings = await PingServer.promiseNextPings(3);
let countByType = countPingTypes(pings);
Assert.equal(countByType.get(TEST_TYPE_C), 1, "Should have received the correct amount of type C pings");
Assert.equal(countByType.get(TEST_TYPE_D), 1, "Should have received the correct amount of type D pings");
Assert.equal(countByType.get(TEST_TYPE_E), 1, "Should have received the correct amount of type E pings");
await TelemetrySend.testWaitOnOutgoingPings();
Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings left");
Assert.deepEqual(histSuccess.snapshot().values, {0: sendAttempts, 1: 3, 2: 0},
"Should have recorded sending failure in histograms.");
Assert.greaterOrEqual(histSendTimeSuccess.snapshot().sum, 0,
"Should have recorded sending success in histograms.");
Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 3,
"Should have recorded sending success in histograms.");
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), sendAttempts,
"Should have recorded send failure times in histograms.");
// Restore the default ping id generator.
fakeGeneratePingId(() => TelemetryUtils.generateUUID());
});
add_task(async function test_discardBigPings() {
const TEST_PING_TYPE = "test-ping-type";
let histSizeExceeded = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND");
let histDiscardedSize = Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB");
let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
for (let h of [histSizeExceeded, histDiscardedSize, histSuccess, histSendTimeSuccess, histSendTimeFail]) {
h.clear();
}
// Submit a ping of a normal size and check that we don't count it in the histogram.
await TelemetryController.submitExternalPing(TEST_PING_TYPE, { test: "test" });
await TelemetrySend.testWaitOnOutgoingPings();
await PingServer.promiseNextPing();
Assert.equal(histSizeExceeded.snapshot().sum, 0, "Telemetry must report no oversized ping submitted.");
Assert.equal(histDiscardedSize.snapshot().sum, 0, "Telemetry must report no oversized pings.");
Assert.deepEqual(histSuccess.snapshot().values, {0: 0, 1: 1, 2: 0}, "Should have recorded sending success.");
Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1, "Should have recorded send success time.");
Assert.greaterOrEqual(histSendTimeSuccess.snapshot().sum, 0, "Should have recorded send success time.");
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0, "Should not have recorded send failure time.");
// Submit an oversized ping and check that it gets discarded.
TelemetryHealthPing.testReset();
// Ensure next ping has a 2 MB gzipped payload.
fakeGzipCompressStringForNextPing(2 * 1024 * 1024);
const OVERSIZED_PAYLOAD = {"data": "empty on purpose - policy takes care of size"};
await TelemetryController.submitExternalPing(TEST_PING_TYPE, OVERSIZED_PAYLOAD);
await TelemetrySend.testWaitOnOutgoingPings();
let ping = await PingServer.promiseNextPing();
Assert.equal(ping.type, TelemetryHealthPing.HEALTH_PING_TYPE, "Should have received a health ping.");
Assert.equal(ping.payload.reason, TelemetryHealthPing.Reason.IMMEDIATE, "Health ping should have the right reason.");
Assert.deepEqual(ping.payload[TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE],
{[TEST_PING_TYPE]: 1}, "Should have recorded correct type of oversized ping.");
Assert.deepEqual(ping.payload.os, TelemetryHealthPing.OsInfo, "Should have correct os info.");
Assert.equal(histSizeExceeded.snapshot().sum, 1, "Telemetry must report 1 oversized ping submitted.");
Assert.equal(histDiscardedSize.snapshot().values[2], 1, "Telemetry must report a 2MB, oversized, ping submitted.");
Assert.deepEqual(histSuccess.snapshot().values, {0: 0, 1: 2, 2: 0}, "Should have recorded sending success.");
Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 2, "Should have recorded send success time.");
Assert.greaterOrEqual(histSendTimeSuccess.snapshot().sum, 0, "Should have recorded send success time.");
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0, "Should not have recorded send failure time.");
});
add_task(async function test_largeButWithinLimit() {
const TEST_PING_TYPE = "test-ping-type";
let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
histSuccess.clear();
// Next ping will have a 900KB gzip payload.
fakeGzipCompressStringForNextPing(900 * 1024);
const LARGE_PAYLOAD = {"data": "empty on purpose - policy takes care of size"};
await TelemetryController.submitExternalPing(TEST_PING_TYPE, LARGE_PAYLOAD);
await TelemetrySend.testWaitOnOutgoingPings();
await PingServer.promiseNextRequest();
Assert.deepEqual(histSuccess.snapshot().values, {0: 0, 1: 1, 2: 0}, "Should have sent large ping.");
});
add_task(async function test_evictedOnServerErrors() {
const TEST_TYPE = "test-evicted";
await TelemetrySend.reset();
let histEvicted = Telemetry.getHistogramById("TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS");
let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
for (let h of [histEvicted, histSuccess, histSendTimeSuccess, histSendTimeFail]) {
h.clear();
}
// Write a custom ping handler which will return 403. This will trigger ping eviction
// on client side.
PingServer.registerPingHandler((req, res) => {
res.setStatusLine(null, 403, "Forbidden");
res.processAsync();
res.finish();
});
// Clear the histogram and submit a ping.
let pingId = await TelemetryController.submitExternalPing(TEST_TYPE, {});
await TelemetrySend.testWaitOnOutgoingPings();
Assert.equal(histEvicted.snapshot().sum, 1,
"Telemetry must report a ping evicted due to server errors");
Assert.deepEqual(histSuccess.snapshot().values, {0: 0, 1: 1, 2: 0});
Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1);
Assert.greaterOrEqual(histSendTimeSuccess.snapshot().sum, 0);
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0);
// The ping should not be persisted.
await Assert.rejects(TelemetryStorage.loadPendingPing(pingId),
/TelemetryStorage.loadPendingPing - no ping with id/,
"The ping must not be persisted.");
// Reset the ping handler and submit a new ping.
PingServer.resetPingHandler();
pingId = await TelemetryController.submitExternalPing(TEST_TYPE, {});
let ping = await PingServer.promiseNextPings(1);
Assert.equal(ping[0].id, pingId, "The correct ping must be received");
// We should not have updated the error histogram.
await TelemetrySend.testWaitOnOutgoingPings();
Assert.equal(histEvicted.snapshot().sum, 1, "Telemetry must report only one ping evicted due to server errors");
Assert.deepEqual(histSuccess.snapshot().values, {0: 0, 1: 2, 2: 0});
Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 2);
Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0);
});
add_task(async function test_tooLateToSend() {
Assert.ok(true, "TEST BEGIN");
const TEST_TYPE = "test-too-late-to-send";
await TelemetrySend.reset();
PingServer.start();
PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings yet");
TelemetrySend.testTooLateToSend(true);
const id = await TelemetryController.submitExternalPing(TEST_TYPE, {});
// Triggering a shutdown should persist the pings
await TelemetrySend.shutdown();
const pendingPings = TelemetryStorage.getPendingPingList();
Assert.equal(pendingPings.length, 1, "Should have a pending ping in storage");
Assert.equal(pendingPings[0].id, id, "Should have pended our test's ping");
Assert.equal(Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE_TYPE").snapshot().values[7], 1,
"Should have registered the failed attempt to send");
await TelemetryStorage.reset();
Assert.equal(TelemetrySend.pendingPingCount, 0, "Should clean up after yourself");
});
// Test that the current, non-persisted pending pings are properly saved on shutdown.
add_task(async function test_persistCurrentPingsOnShutdown() {
const TEST_TYPE = "test-persistCurrentPingsOnShutdown";
const PING_COUNT = 5;
await TelemetrySend.reset();
PingServer.stop();
Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings yet");
// Submit new pings that shouldn't be persisted yet.
let ids = [];
for (let i = 0; i < 5; ++i) {
ids.push(fakePingId("f", i));
TelemetryController.submitExternalPing(TEST_TYPE, {});
}
Assert.equal(TelemetrySend.pendingPingCount, PING_COUNT, "Should have the correct pending ping count");
// Triggering a shutdown should persist the pings.
await TelemetrySend.shutdown();
Assert.ok((await checkPingsSaved(ids)), "All pending pings should have been persisted");
// After a restart the pings should have been found when scanning.
await TelemetrySend.reset();
Assert.equal(TelemetrySend.pendingPingCount, PING_COUNT, "Should have the correct pending ping count");
// Restore the default ping id generator.
fakeGeneratePingId(() => TelemetryUtils.generateUUID());
});
add_task(async function test_sendCheckOverride() {
const TEST_PING_TYPE = "test-sendCheckOverride";
// Clear any pending pings.
await TelemetryController.testShutdown();
await TelemetryStorage.testClearPendingPings();
// Enable the ping server.
PingServer.start();
Services.prefs.setStringPref(TelemetryUtils.Preferences.Server, "http://localhost:" + PingServer.port);
// Start Telemetry and disable the test-mode so pings don't get
// sent unless we enable the override.
await TelemetryController.testReset();
// Submit a test ping and make sure it doesn't get sent. We only do
// that if we're on unofficial builds: pings will always get sent otherwise.
if (!Services.telemetry.isOfficialTelemetry) {
TelemetrySend.setTestModeEnabled(false);
PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
await TelemetryController.submitExternalPing(TEST_PING_TYPE, { test: "test" });
Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings");
}
// Enable the override and try to send again.
Services.prefs.setBoolPref(TelemetryUtils.Preferences.OverrideOfficialCheck, true);
PingServer.resetPingHandler();
await TelemetrySend.reset();
await TelemetryController.submitExternalPing(TEST_PING_TYPE, { test: "test" });
// Make sure we received the ping.
const ping = await PingServer.promiseNextPing();
Assert.equal(ping.type, TEST_PING_TYPE, "Must receive a ping of the expected type");
// Restore the test mode and disable the override.
TelemetrySend.setTestModeEnabled(true);
Services.prefs.clearUserPref(TelemetryUtils.Preferences.OverrideOfficialCheck);
});
add_task(async function testCookies() {
const TEST_TYPE = "test-cookies";
await TelemetrySend.reset();
PingServer.clearRequests();
let uri = Services.io.newURI("http://localhost:" + PingServer.port);
Services.cookies.setCookieString(uri, null, "cookie-time=yes", null);
const id = await TelemetryController.submitExternalPing(TEST_TYPE, {});
let foundit = false;
while (!foundit) {
var request = await PingServer.promiseNextRequest();
var ping = decodeRequestPayload(request);
foundit = id === ping.id;
}
Assert.equal(id, ping.id, "We're testing the right ping's request, right?");
Assert.equal(false, request.hasHeader("Cookie"), "Request should not have Cookie header");
});
add_task(async function test_measurePingsSize() {
const TEST_TYPE = "test-measure-ping-size";
let histSuccessPingSize = Telemetry.getHistogramById("TELEMETRY_SUCCESSFUL_SEND_PINGS_SIZE_KB");
let histFailedPingSize = Telemetry.getHistogramById("TELEMETRY_FAILED_SEND_PINGS_SIZE_KB");
for (let h of [histSuccessPingSize, histFailedPingSize]) {
h.clear();
}
await TelemetryController.submitExternalPing(TEST_TYPE, {});
await TelemetrySend.testWaitOnOutgoingPings();
// Check that we recorded the ping sizes correctly into histograms.
Assert.equal(histogramValueCount(histSuccessPingSize.snapshot()), 1,
"Should have recorded 1 successful ping into histogram.");
Assert.equal(histogramValueCount(histFailedPingSize.snapshot()), 0,
"Should have recorded 0 failed ping into histogram.");
// Submit the same ping a second time.
await TelemetryController.submitExternalPing(TEST_TYPE, {});
await TelemetrySend.testWaitOnOutgoingPings();
// Check that we recorded the ping sizes correctly into histograms.
Assert.equal(histogramValueCount(histSuccessPingSize.snapshot()), 2,
"Should have recorded 2 successful ping into histogram.");
Assert.equal(histogramValueCount(histFailedPingSize.snapshot()), 0,
"Should have recorded 0 failed ping into histogram.");
// Register a custom ping handler which will return 601.
PingServer.registerPingHandler((req, res) => {
res.setStatusLine(null, 601, "Not Implemented");
res.processAsync();
res.finish();
});
await TelemetryController.submitExternalPing(TEST_TYPE, {});
await ContentTaskUtils.waitForCondition(() => {
return histogramValueCount(histFailedPingSize.snapshot()) > 0;
});
// Check that we recorded the ping sizes correctly into histograms.
Assert.equal(histogramValueCount(histSuccessPingSize.snapshot()), 2,
"Should have recorded 2 successful ping into histogram.");
Assert.equal(histogramValueCount(histFailedPingSize.snapshot()), 1,
"Should have recorded 1 failed ping into histogram.");
});
add_task(async function test_pref_observer() {
// This test requires the presence of the crash reporter component.
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
if (!registrar.isContractIDRegistered("@mozilla.org/toolkit/crash-reporter;1")) {
return;
}
await TelemetrySend.setup(true);
const IS_UNIFIED_TELEMETRY = Services.prefs.getBoolPref(TelemetryUtils.Preferences.Unified, false);
let origTelemetryEnabled = Services.prefs.getBoolPref(TelemetryUtils.Preferences.TelemetryEnabled);
let origFhrUploadEnabled = Services.prefs.getBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled);
if (!IS_UNIFIED_TELEMETRY) {
Services.prefs.setBoolPref(TelemetryUtils.Preferences.TelemetryEnabled, true);
}
Services.prefs.setBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, true);
function waitAnnotateCrashReport(expectedValue, trigger) {
return new Promise(function(resolve, reject) {
let keys = new Set(["TelemetryClientId", "TelemetryServerURL"]);
let crs = {
QueryInterface: ChromeUtils.generateQI([Ci.nsICrashReporter]),
annotateCrashReport(key, value) {
if (!keys.delete(key)) {
MockRegistrar.unregister(gMockCrs);
reject(Error(`Crash report annotation with unexpected key: "${key}".`));
}
if (expectedValue && value == "") {
MockRegistrar.unregister(gMockCrs);
reject(Error("Crash report annotation without expected value."));
}
if (keys.size == 0) {
MockRegistrar.unregister(gMockCrs);
resolve();
}
},
removeCrashReportAnnotation(key) {
if (!keys.delete(key)) {
MockRegistrar.unregister(gMockCrs);
}
if (keys.size == 0) {
MockRegistrar.unregister(gMockCrs);
resolve();
}
},
UpdateCrashEventsDir() {
},
};
let gMockCrs = MockRegistrar.register("@mozilla.org/toolkit/crash-reporter;1", crs);
registerCleanupFunction(function() {
MockRegistrar.unregister(gMockCrs);
});
trigger();
});
}
await waitAnnotateCrashReport(!IS_UNIFIED_TELEMETRY, () => Services.prefs.setBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, false));
await waitAnnotateCrashReport(true, () => Services.prefs.setBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, true));
if (!IS_UNIFIED_TELEMETRY) {
Services.prefs.setBoolPref(TelemetryUtils.Preferences.TelemetryEnabled, origTelemetryEnabled);
}
Services.prefs.setBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, origFhrUploadEnabled);
});
add_task(async function cleanup() {
await PingServer.stop();
});