gecko-dev/toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js
Mike de Boer 481ae95c00 Bug 1524593 - nsISearchService (aka nsIBrowserSearchService, previously) refactor to be mostly an asynchronous, in preparation of WebExtension engines. r=daleharvey
This is a rollup of all the patches that have landed on the cedar project branch:

891252fdd0
Bug 1492475 - Part 1: Migrate most, if not all nsSearchService consumers to use async APIs. r=florian

79b2eb2367
Bug 1492475 - Part 2: Move nsIBrowserSearchService.idl to toolkit/components/search/nsISearchService.idl and update references. r=florian

a947d3cdf0
Bug 1492475 - Part 3: The search service init() method should simply return a Promise. r=florian

c1e172dfac
Bug 1492475 - Part 4: Remove the synchronous initialization flow. r=florian

cd41189eac
Bug 1492475 - Part 5: Since async initialization of the search service now is implicit behavior, remove the distinctive verbiage used internally. r=florian

2ae7189dfa
Bug 1492475 - Part 6: Update the cache build task to work with an actual Promise and re-initialize only once at the same time - all to fix race conditions here. r=florian

c8ee92973f
Bug 1492475 - Part 7: Make the region fetch not block the init flow, to ensure it's as fast as possible. r=florian

c44e674e16
Bug 1492475 - Part 8: Introduce an init flag, which can only be used privately, that allows to explicitly skip waiting for the region check process to complete. r=florian

6c79eaf1d3
Bug 1492475 - Part 9: Update unit tests to stop using 'currentEngine', in favor of 'defaultEngine'. r=Standard8

21b3aa17ee
Bug 1492475 - Part 10: Update unit tests to be fully aware of the new, async signatures of the search service API and remove sync init flow tests. r=mkaply,florian

ce5ba69019
Bug 1492475 - Part 11: Repair incorrect usage of the `identifier` property of nsISearchEngine instances. r=florian

fd177a7994
Bug 1518543 - Fix up the Android (Fennec) nsISearchService shim to work with the new asynchronous API. r=florian

3653d8ee22
Bug 1523708 - Change the search service interaction in the show-heartbeat action to use the new async API. r=florian

Differential Revision: https://phabricator.services.mozilla.com/D18355

--HG--
rename : netwerk/base/nsIBrowserSearchService.idl => toolkit/components/search/nsISearchService.idl
extra : moz-landing-system : lando
2019-02-02 11:27:21 +00:00

233 lines
9.6 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
*/
ChromeUtils.import("resource://gre/modules/Preferences.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetryArchive.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetryController.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
ChromeUtils.import("resource://gre/modules/osfile.jsm", this);
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
const MS_IN_ONE_HOUR = 60 * 60 * 1000;
const MS_IN_ONE_DAY = 24 * MS_IN_ONE_HOUR;
const PREF_BRANCH = "toolkit.telemetry.";
const REASON_ABORTED_SESSION = "aborted-session";
const REASON_DAILY = "daily";
const REASON_ENVIRONMENT_CHANGE = "environment-change";
const REASON_SHUTDOWN = "shutdown";
XPCOMUtils.defineLazyGetter(this, "DATAREPORTING_PATH", function() {
return OS.Path.join(OS.Constants.Path.profileDir, "datareporting");
});
var promiseValidateArchivedPings = async function(aExpectedReasons) {
// The list of ping reasons which mark the session end (and must reset the subsession
// count).
const SESSION_END_PING_REASONS = new Set([ REASON_ABORTED_SESSION, REASON_SHUTDOWN ]);
let list = await TelemetryArchive.promiseArchivedPingList();
// We're just interested in the "main" pings.
list = list.filter(p => p.type == "main");
Assert.equal(aExpectedReasons.length, list.length, "All the expected pings must be received.");
let previousPing = await TelemetryArchive.promiseArchivedPingById(list[0].id);
Assert.equal(aExpectedReasons.shift(), previousPing.payload.info.reason,
"Telemetry should only get pings with expected reasons.");
Assert.equal(previousPing.payload.info.previousSessionId, null,
"The first session must report a null previous session id.");
Assert.equal(previousPing.payload.info.previousSubsessionId, null,
"The first subsession must report a null previous subsession id.");
Assert.equal(previousPing.payload.info.profileSubsessionCounter, 1,
"profileSubsessionCounter must be 1 the first time.");
Assert.equal(previousPing.payload.info.subsessionCounter, 1,
"subsessionCounter must be 1 the first time.");
let expectedSubsessionCounter = 1;
let expectedPreviousSessionId = previousPing.payload.info.sessionId;
for (let i = 1; i < list.length; i++) {
let currentPing = await TelemetryArchive.promiseArchivedPingById(list[i].id);
let currentInfo = currentPing.payload.info;
let previousInfo = previousPing.payload.info;
info("Archive entry " + i + " - id: " + currentPing.id + ", reason: " + currentInfo.reason);
Assert.equal(aExpectedReasons.shift(), currentInfo.reason,
"Telemetry should only get pings with expected reasons.");
Assert.equal(currentInfo.previousSessionId, expectedPreviousSessionId,
"Telemetry must correctly chain session identifiers.");
Assert.equal(currentInfo.previousSubsessionId, previousInfo.subsessionId,
"Telemetry must correctly chain subsession identifiers.");
Assert.equal(currentInfo.profileSubsessionCounter, previousInfo.profileSubsessionCounter + 1,
"Telemetry must correctly track the profile subsessions count.");
Assert.equal(currentInfo.subsessionCounter, expectedSubsessionCounter,
"The subsession counter should be monotonically increasing.");
// Store the current ping as previous.
previousPing = currentPing;
// Reset the expected subsession counter, if required. Otherwise increment the expected
// subsession counter.
// If this is the final subsession of a session we need to update expected values accordingly.
if (SESSION_END_PING_REASONS.has(currentInfo.reason)) {
expectedSubsessionCounter = 1;
expectedPreviousSessionId = currentInfo.sessionId;
} else {
expectedSubsessionCounter++;
}
}
};
add_task(async function test_setup() {
do_test_pending();
// Addon manager needs a profile directory
do_get_profile();
loadAddonManager("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
finishAddonManagerStartup();
fakeIntlReady();
// Make sure we don't generate unexpected pings due to pref changes.
await setEmptyPrefWatchlist();
});
add_task(async function test_subsessionsChaining() {
if (gIsAndroid) {
// We don't support subsessions yet on Android, so skip the next checks.
return;
}
const PREF_TEST = PREF_BRANCH + "test.pref1";
const PREFS_TO_WATCH = new Map([
[PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
]);
Preferences.reset(PREF_TEST);
// Fake the clock data to manually trigger an aborted-session ping and a daily ping.
// This is also helpful to make sure we get the archived pings in an expected order.
let now = fakeNow(2009, 9, 18, 0, 0, 0);
let monotonicNow = fakeMonotonicNow(1000);
let moveClockForward = (minutes) => {
let ms = minutes * MILLISECONDS_PER_MINUTE;
now = fakeNow(futureDate(now, ms));
monotonicNow = fakeMonotonicNow(monotonicNow + ms);
};
// Keep track of the ping reasons we're expecting in this test.
let expectedReasons = [];
// Start and shut down Telemetry. We expect a shutdown ping with profileSubsessionCounter: 1,
// subsessionCounter: 1, subsessionId: A, and previousSubsessionId: null to be archived.
await TelemetryController.testSetup();
await TelemetryController.testShutdown();
expectedReasons.push(REASON_SHUTDOWN);
// Start Telemetry but don't wait for it to initialise before shutting down. We expect a
// shutdown ping with profileSubsessionCounter: 2, subsessionCounter: 1, subsessionId: B
// and previousSubsessionId: A to be archived.
moveClockForward(30);
TelemetryController.testReset();
await TelemetryController.testShutdown();
expectedReasons.push(REASON_SHUTDOWN);
// Start Telemetry and simulate an aborted-session ping. We expect an aborted-session ping
// with profileSubsessionCounter: 3, subsessionCounter: 1, subsessionId: C and
// previousSubsessionId: B to be archived.
let schedulerTickCallback = null;
fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
await TelemetryController.testReset();
moveClockForward(6);
// Trigger the an aborted session ping save. When testing,we are not saving the aborted-session
// ping as soon as Telemetry starts, otherwise we would end up with unexpected pings being
// sent when calling |TelemetryController.testReset()|, thus breaking some tests.
Assert.ok(!!schedulerTickCallback);
await schedulerTickCallback();
expectedReasons.push(REASON_ABORTED_SESSION);
// Start Telemetry and trigger an environment change through a pref modification. We expect
// an environment-change ping with profileSubsessionCounter: 4, subsessionCounter: 1,
// subsessionId: D and previousSubsessionId: C to be archived.
moveClockForward(30);
await TelemetryController.testReset();
await TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
moveClockForward(30);
Preferences.set(PREF_TEST, 1);
expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
// Shut down Telemetry. We expect a shutdown ping with profileSubsessionCounter: 5,
// subsessionCounter: 2, subsessionId: E and previousSubsessionId: D to be archived.
moveClockForward(30);
await TelemetryController.testShutdown();
expectedReasons.push(REASON_SHUTDOWN);
// Start Telemetry and trigger a daily ping. We expect a daily ping with
// profileSubsessionCounter: 6, subsessionCounter: 1, subsessionId: F and
// previousSubsessionId: E to be archived.
moveClockForward(30);
await TelemetryController.testReset();
// Delay the callback around midnight.
now = fakeNow(futureDate(now, MS_IN_ONE_DAY));
// Trigger the daily ping.
await schedulerTickCallback();
expectedReasons.push(REASON_DAILY);
// Trigger an environment change ping. We expect an environment-changed ping with
// profileSubsessionCounter: 7, subsessionCounter: 2, subsessionId: G and
// previousSubsessionId: F to be archived.
moveClockForward(30);
Preferences.set(PREF_TEST, 0);
expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
// Shut down Telemetry and trigger a shutdown ping.
moveClockForward(30);
await TelemetryController.testShutdown();
expectedReasons.push(REASON_SHUTDOWN);
// Start Telemetry and trigger an environment change.
await TelemetryController.testReset();
await TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
moveClockForward(30);
Preferences.set(PREF_TEST, 1);
expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
// Don't shut down, instead trigger an aborted-session ping.
moveClockForward(6);
// Trigger the an aborted session ping save.
await schedulerTickCallback();
expectedReasons.push(REASON_ABORTED_SESSION);
// Start Telemetry and trigger a daily ping.
moveClockForward(30);
await TelemetryController.testReset();
// Delay the callback around midnight.
now = futureDate(now, MS_IN_ONE_DAY);
fakeNow(now);
// Trigger the daily ping.
await schedulerTickCallback();
expectedReasons.push(REASON_DAILY);
// Trigger an environment change.
moveClockForward(30);
Preferences.set(PREF_TEST, 0);
expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
// And an aborted-session ping again.
moveClockForward(6);
// Trigger the an aborted session ping save.
await schedulerTickCallback();
expectedReasons.push(REASON_ABORTED_SESSION);
// Make sure the aborted-session ping gets archived.
await TelemetryController.testReset();
await promiseValidateArchivedPings(expectedReasons);
});
add_task(async function() {
await TelemetryController.testShutdown();
do_test_finished();
});