зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1445921) for Linting failure on components/telemetry/tests/unit/test_TelemetryController.js on a CLOSED TREE
Backed out changeset b5bff80b9d18 (bug 1445921) Backed out changeset b859e76fcc67 (bug 1445921) Backed out changeset 7c23db3a5f53 (bug 1445921) Backed out changeset f3ef58bc6b38 (bug 1445921) --HG-- extra : rebase_source : 00bc0e17ea782a73c5067c1f8d615fc7b80bbabb
This commit is contained in:
Родитель
30f1ace53b
Коммит
dd9a507efe
|
@ -1359,20 +1359,6 @@ telemetry:
|
|||
record_in_processes:
|
||||
- 'main'
|
||||
|
||||
data_upload_optin:
|
||||
bug_numbers:
|
||||
- 1445921
|
||||
description: >
|
||||
User opted into sending Telemetry data again.
|
||||
expires: "never"
|
||||
kind: boolean
|
||||
notification_emails:
|
||||
- jrediger@mozilla.com
|
||||
- telemetry-client-dev@mozilla.com
|
||||
release_channel_collection: opt-out
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
|
||||
telemetry.discarded:
|
||||
accumulations:
|
||||
bug_numbers:
|
||||
|
|
|
@ -40,7 +40,7 @@ const NEWPROFILE_PING_DEFAULT_DELAY = 30 * 60 * 1000;
|
|||
|
||||
// Ping types.
|
||||
const PING_TYPE_MAIN = "main";
|
||||
const PING_TYPE_OPTOUT = "optout";
|
||||
const PING_TYPE_DELETION = "deletion";
|
||||
|
||||
// Session ping reasons.
|
||||
const REASON_GATHER_PAYLOAD = "gather-payload";
|
||||
|
@ -848,49 +848,28 @@ var Impl = {
|
|||
|
||||
/**
|
||||
* Called whenever the FHR Upload preference changes (e.g. when user disables FHR from
|
||||
* the preferences panel), this triggers sending the optout ping.
|
||||
* the preferences panel), this triggers sending the deletion ping.
|
||||
*/
|
||||
_onUploadPrefChange() {
|
||||
const uploadEnabled = Services.prefs.getBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, false);
|
||||
if (uploadEnabled) {
|
||||
this._log.trace("_onUploadPrefChange - upload was enabled again. Resetting client ID");
|
||||
|
||||
// Delete cached client ID immediately, so other usage is forced to refetch it.
|
||||
this._clientID = null;
|
||||
|
||||
// Generate a new client ID and make sure this module uses the new version
|
||||
let p = ClientID.resetClientID().then(id => {
|
||||
this._clientID = id;
|
||||
Telemetry.scalarSet("telemetry.data_upload_optin", true);
|
||||
});
|
||||
|
||||
this._shutdownBarrier.client.addBlocker(
|
||||
"TelemetryController: resetting client ID after data upload was enabled", p);
|
||||
|
||||
// There's nothing we should do if we are enabling upload.
|
||||
return;
|
||||
}
|
||||
|
||||
let p = (async () => {
|
||||
try {
|
||||
// 1. Cancel the current pings.
|
||||
// 2. Clear unpersisted pings
|
||||
// Clear the current pings.
|
||||
await TelemetrySend.clearCurrentPings();
|
||||
|
||||
// 3. Remove all pending pings
|
||||
await TelemetryStorage.removeAppDataPings();
|
||||
// Remove all the pending pings, but not the deletion ping.
|
||||
await TelemetryStorage.runRemovePendingPingsTask();
|
||||
} catch (e) {
|
||||
this._log.error("_onUploadPrefChange - error clearing pending pings", e);
|
||||
} finally {
|
||||
// 4. Reset session and subsession counter
|
||||
TelemetrySession.resetSubsessionCounter();
|
||||
|
||||
// 5. Set ClientID to a known value
|
||||
this._clientID = await ClientID.setClientID(TelemetryUtils.knownClientID);
|
||||
|
||||
// 6. Send the optout ping.
|
||||
this._log.trace("_onUploadPrefChange - Sending optout ping.");
|
||||
this.submitExternalPing(PING_TYPE_OPTOUT, {}, { addClientId: false });
|
||||
// Always send the deletion ping.
|
||||
this._log.trace("_onUploadPrefChange - Sending deletion ping.");
|
||||
this.submitExternalPing(PING_TYPE_DELETION, {}, { addClientId: true });
|
||||
}
|
||||
})();
|
||||
|
||||
|
@ -902,7 +881,7 @@ var Impl = {
|
|||
|
||||
_attachObservers() {
|
||||
if (IS_UNIFIED_TELEMETRY) {
|
||||
// Watch the FHR upload setting to trigger optout pings.
|
||||
// Watch the FHR upload setting to trigger deletion pings.
|
||||
Services.prefs.addObserver(TelemetryUtils.Preferences.FhrUploadEnabled, this, true);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -59,7 +59,7 @@ const PING_FORMAT_VERSION = 4;
|
|||
|
||||
const MS_IN_A_MINUTE = 60 * 1000;
|
||||
|
||||
const PING_TYPE_OPTOUT = "optout";
|
||||
const PING_TYPE_DELETION = "deletion";
|
||||
|
||||
// We try to spread "midnight" pings out over this interval.
|
||||
const MIDNIGHT_FUZZING_INTERVAL_MS = 60 * MS_IN_A_MINUTE;
|
||||
|
@ -118,20 +118,24 @@ function isV4PingFormat(aPing) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if the provided ping is an optout ping.
|
||||
* Check if the provided ping is a deletion ping.
|
||||
* @param {Object} aPing The ping to check.
|
||||
* @return {Boolean} True if the ping is an optout ping, false otherwise.
|
||||
* @return {Boolean} True if the ping is a deletion ping, false otherwise.
|
||||
*/
|
||||
function isOptoutPing(aPing) {
|
||||
return isV4PingFormat(aPing) && (aPing.type == PING_TYPE_OPTOUT);
|
||||
function isDeletionPing(aPing) {
|
||||
return isV4PingFormat(aPing) && (aPing.type == PING_TYPE_DELETION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the provided ping as a pending ping.
|
||||
* Save the provided ping as a pending ping. If it's a deletion ping, save it
|
||||
* to a special location.
|
||||
* @param {Object} aPing The ping to save.
|
||||
* @return {Promise} A promise resolved when the ping is saved.
|
||||
*/
|
||||
function savePing(aPing) {
|
||||
if (isDeletionPing(aPing)) {
|
||||
return TelemetryStorage.saveDeletionPing(aPing);
|
||||
}
|
||||
return TelemetryStorage.savePendingPing(aPing);
|
||||
}
|
||||
|
||||
|
@ -441,17 +445,16 @@ var SendScheduler = {
|
|||
}
|
||||
|
||||
// Get a list of pending pings, sorted by last modified, descending.
|
||||
// Filter out all the pings we can't send now. This addresses scenarios like "optout" pings
|
||||
// which can be sent even when upload is disabled.
|
||||
// Filter out all the pings we can't send now. This addresses scenarios like "deletion" pings
|
||||
// which can be send even when upload is disabled.
|
||||
let pending = TelemetryStorage.getPendingPingList();
|
||||
let current = TelemetrySendImpl.getUnpersistedPings();
|
||||
this._log.trace("_doSendTask - pending: " + pending.length + ", current: " + current.length);
|
||||
// Note that the two lists contain different kind of data. |pending| only holds ping
|
||||
// info, while |current| holds actual ping data.
|
||||
if (!TelemetrySendImpl.sendingEnabled()) {
|
||||
// If sending is disabled, only handle an unpersisted optout ping
|
||||
pending = [];
|
||||
current = current.filter(p => isOptoutPing(p));
|
||||
pending = pending.filter(pingInfo => TelemetryStorage.isDeletionPing(pingInfo.id));
|
||||
current = current.filter(p => isDeletionPing(p));
|
||||
}
|
||||
this._log.trace("_doSendTask - can send - pending: " + pending.length + ", current: " + current.length);
|
||||
|
||||
|
@ -944,13 +947,9 @@ var TelemetrySendImpl = {
|
|||
try {
|
||||
await this._doPing(ping, ping.id, false);
|
||||
} catch (ex) {
|
||||
if (isOptoutPing(ping)) {
|
||||
// Optout pings should only be tried once and then discarded.
|
||||
this._log.info("sendPings - optout ping " + ping.id + " not sent, discarding", ex);
|
||||
} else {
|
||||
this._log.info("sendPings - ping " + ping.id + " not sent, saving to disk", ex);
|
||||
await savePing(ping);
|
||||
}
|
||||
this._log.info("sendPings - ping " + ping.id + " not sent, saving to disk", ex);
|
||||
// Deletion pings must be saved to a special location.
|
||||
await savePing(ping);
|
||||
} finally {
|
||||
this._currentPings.delete(ping.id);
|
||||
}
|
||||
|
@ -1022,6 +1021,9 @@ var TelemetrySendImpl = {
|
|||
}
|
||||
|
||||
if (success && isPersisted) {
|
||||
if (TelemetryStorage.isDeletionPing(id)) {
|
||||
return TelemetryStorage.removeDeletionPing();
|
||||
}
|
||||
return TelemetryStorage.removePendingPing(id);
|
||||
}
|
||||
return Promise.resolve();
|
||||
|
@ -1224,7 +1226,7 @@ var TelemetrySendImpl = {
|
|||
/**
|
||||
* Check if sending is disabled. If FHR is not allowed to upload,
|
||||
* pings are not sent to the server (Telemetry is a sub-feature of FHR). If trying
|
||||
* to send an optout ping, don't block it.
|
||||
* to send a deletion ping, don't block it.
|
||||
* If unified telemetry is off, don't send pings if Telemetry is disabled.
|
||||
*
|
||||
* @param {Object} [ping=null] A ping to be checked.
|
||||
|
@ -1241,8 +1243,8 @@ var TelemetrySendImpl = {
|
|||
// With unified Telemetry, the FHR upload setting controls whether we can send pings.
|
||||
// The Telemetry pref enables sending extended data sets instead.
|
||||
if (IS_UNIFIED_TELEMETRY) {
|
||||
// Optout pings are sent once even if the upload is disabled.
|
||||
if (ping && isOptoutPing(ping)) {
|
||||
// Deletion pings are sent even if the upload is disabled.
|
||||
if (ping && isDeletionPing(ping)) {
|
||||
return true;
|
||||
}
|
||||
return Services.prefs.getBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, false);
|
||||
|
@ -1279,11 +1281,8 @@ var TelemetrySendImpl = {
|
|||
async _persistCurrentPings() {
|
||||
for (let [id, ping] of this._currentPings) {
|
||||
try {
|
||||
// Never save an optout ping to disk
|
||||
if (!isOptoutPing(ping)) {
|
||||
await savePing(ping);
|
||||
this._log.trace("_persistCurrentPings - saved ping " + id);
|
||||
}
|
||||
await savePing(ping);
|
||||
this._log.trace("_persistCurrentPings - saved ping " + id);
|
||||
} catch (ex) {
|
||||
this._log.error("_persistCurrentPings - failed to save ping " + id, ex);
|
||||
} finally {
|
||||
|
|
|
@ -566,17 +566,6 @@ var TelemetrySession = Object.freeze({
|
|||
getMetadata(reason) {
|
||||
return Impl.getMetadata(reason);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the subsession and profile subsession counter.
|
||||
* This should only be called when the profile should be considered completely new,
|
||||
* e.g. after opting out of sending Telemetry
|
||||
*/
|
||||
resetSubsessionCounter() {
|
||||
Impl._subsessionCounter = 0;
|
||||
Impl._profileSubsessionCounter = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Used only for testing purposes.
|
||||
*/
|
||||
|
|
|
@ -26,6 +26,7 @@ const Utils = TelemetryUtils;
|
|||
const DATAREPORTING_DIR = "datareporting";
|
||||
const PINGS_ARCHIVE_DIR = "archived";
|
||||
const ABORTED_SESSION_FILE_NAME = "aborted-session-ping";
|
||||
const DELETION_PING_FILE_NAME = "pending-deletion-ping";
|
||||
const SESSION_STATE_FILE_NAME = "session-state.json";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gDataReportingDir", function() {
|
||||
|
@ -37,6 +38,9 @@ XPCOMUtils.defineLazyGetter(this, "gPingsArchivePath", function() {
|
|||
XPCOMUtils.defineLazyGetter(this, "gAbortedSessionFilePath", function() {
|
||||
return OS.Path.join(gDataReportingDir, ABORTED_SESSION_FILE_NAME);
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "gDeletionPingFilePath", function() {
|
||||
return OS.Path.join(gDataReportingDir, DELETION_PING_FILE_NAME);
|
||||
});
|
||||
ChromeUtils.defineModuleGetter(this, "CommonUtils",
|
||||
"resource://services-common/utils.js");
|
||||
ChromeUtils.defineModuleGetter(this, "TelemetryHealthPing",
|
||||
|
@ -205,7 +209,7 @@ var TelemetryStorage = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Run the task to remove all the pending pings
|
||||
* Run the task to remove all the pending pings (except the deletion ping).
|
||||
*
|
||||
* @return {Promise} Resolved when the pings are removed.
|
||||
*/
|
||||
|
@ -213,14 +217,6 @@ var TelemetryStorage = {
|
|||
return TelemetryStorageImpl.runRemovePendingPingsTask();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all pings that are stored in the userApplicationDataDir
|
||||
* under the "Pending Pings" sub-directory.
|
||||
*/
|
||||
removeAppDataPings() {
|
||||
return TelemetryStorageImpl.removeAppDataPings();
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the storage state in tests.
|
||||
*/
|
||||
|
@ -338,6 +334,30 @@ var TelemetryStorage = {
|
|||
return TelemetryStorageImpl.loadAbortedSessionPing();
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the deletion ping.
|
||||
* @param ping The deletion ping.
|
||||
* @return {Promise} A promise resolved when the ping is saved.
|
||||
*/
|
||||
saveDeletionPing(ping) {
|
||||
return TelemetryStorageImpl.saveDeletionPing(ping);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the deletion ping.
|
||||
* @return {Promise} Resolved when the ping is deleted from the disk.
|
||||
*/
|
||||
removeDeletionPing() {
|
||||
return TelemetryStorageImpl.removeDeletionPing();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the ping id identifies a deletion ping.
|
||||
*/
|
||||
isDeletionPing(aPingId) {
|
||||
return TelemetryStorageImpl.isDeletionPing(aPingId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the aborted-session ping if present.
|
||||
*
|
||||
|
@ -540,6 +560,8 @@ var TelemetryStorageImpl = {
|
|||
_logger: null,
|
||||
// Used to serialize aborted session ping writes to disk.
|
||||
_abortedSessionSerializer: new SaveSerializer(),
|
||||
// Used to serialize deletion ping writes to disk.
|
||||
_deletionPingSerializer: new SaveSerializer(),
|
||||
// Used to serialize session state writes to disk.
|
||||
_stateSaveSerializer: new SaveSerializer(),
|
||||
|
||||
|
@ -593,6 +615,10 @@ var TelemetryStorageImpl = {
|
|||
this._log.error("shutdown - failed to flush aborted-session writes", ex);
|
||||
});
|
||||
|
||||
await this._deletionPingSerializer.flushTasks().catch(ex => {
|
||||
this._log.error("shutdown - failed to flush deletion ping writes", ex);
|
||||
});
|
||||
|
||||
if (this._cleanArchiveTask) {
|
||||
await this._cleanArchiveTask.catch(ex => {
|
||||
this._log.error("shutdown - the archive cleaning task failed", ex);
|
||||
|
@ -1398,7 +1424,7 @@ var TelemetryStorageImpl = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Run the task to remove all the pending pings
|
||||
* Run the task to remove all the pending pings (except the deletion ping).
|
||||
*
|
||||
* @return {Promise} Resolved when the pings are removed.
|
||||
*/
|
||||
|
@ -1450,17 +1476,17 @@ var TelemetryStorageImpl = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Iterate through all pings in the userApplicationDataDir under the "Pending Pings" sub-directory
|
||||
* and yield each file.
|
||||
* This function migrates pings that are stored in the userApplicationDataDir
|
||||
* under the "Pending Pings" sub-directory.
|
||||
*/
|
||||
async* _iterateAppDataPings() {
|
||||
this._log.trace("_iterateAppDataPings");
|
||||
async _migrateAppDataPings() {
|
||||
this._log.trace("_migrateAppDataPings");
|
||||
|
||||
// The test suites might not create and define the "UAppData" directory.
|
||||
// The tests suites might not create and define the "UAppData" directory.
|
||||
// We account for that here instead of manually going through each test using
|
||||
// telemetry to manually create the directory and define the constant.
|
||||
if (!OS.Constants.Path.userApplicationDataDir) {
|
||||
this._log.trace("_iterateAppDataPings - userApplicationDataDir is not defined. Is this a test?");
|
||||
this._log.trace("_migrateAppDataPings - userApplicationDataDir is not defined. Is this a test?");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1472,59 +1498,32 @@ var TelemetryStorageImpl = {
|
|||
try {
|
||||
// Check if appDataPendingPings exists and bail out if it doesn't.
|
||||
if (!(await iter.exists())) {
|
||||
this._log.trace("_iterateAppDataPings - the AppData pending pings directory doesn't exist.");
|
||||
this._log.trace("_migrateAppDataPings - the AppData pending pings directory doesn't exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
let files = (await iter.nextBatch()).filter(e => !e.isDir);
|
||||
for (let file of files) {
|
||||
yield file;
|
||||
try {
|
||||
// Load the ping data from the original file.
|
||||
const pingData = await this.loadPingFile(file.path);
|
||||
|
||||
// Save it among the pending pings in the user profile, overwrite on
|
||||
// ping id collision.
|
||||
await TelemetryStorage.savePing(pingData, true);
|
||||
|
||||
// Finally remove the file.
|
||||
await OS.File.remove(file.path);
|
||||
} catch (ex) {
|
||||
this._log.error("_migrateAppDataPings - failed to remove file " + file.path, ex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await iter.close();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all pings that are stored in the userApplicationDataDir
|
||||
* under the "Pending Pings" sub-directory.
|
||||
*/
|
||||
async removeAppDataPings() {
|
||||
this._log.trace("removeAppDataPings");
|
||||
|
||||
for await (const file of this._iterateAppDataPings()) {
|
||||
try {
|
||||
await OS.File.remove(file.path);
|
||||
} catch (ex) {
|
||||
this._log.error("removeAppDataPings - failed to remove file " + file.path, ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Migrate pings that are stored in the userApplicationDataDir
|
||||
* under the "Pending Pings" sub-directory.
|
||||
*/
|
||||
async _migrateAppDataPings() {
|
||||
this._log.trace("_migrateAppDataPings");
|
||||
|
||||
for await (const file of this._iterateAppDataPings()) {
|
||||
try {
|
||||
// Load the ping data from the original file.
|
||||
const pingData = await this.loadPingFile(file.path);
|
||||
|
||||
// Save it among the pending pings in the user profile, overwrite on
|
||||
// ping id collision.
|
||||
await TelemetryStorage.savePing(pingData, true);
|
||||
|
||||
// Finally remove the file.
|
||||
await OS.File.remove(file.path);
|
||||
} catch (ex) {
|
||||
this._log.error("_migrateAppDataPings - failed to remove file " + file.path, ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
loadPendingPingList() {
|
||||
// If we already have a pending scanning task active, return that.
|
||||
if (this._scanPendingPingsTask) {
|
||||
|
@ -1617,6 +1616,17 @@ var TelemetryStorageImpl = {
|
|||
await iter.close();
|
||||
}
|
||||
|
||||
// Explicitly load the deletion ping from its known path, if it's there.
|
||||
if (await OS.File.exists(gDeletionPingFilePath)) {
|
||||
this._log.trace("_scanPendingPings - Adding pending deletion ping.");
|
||||
// We can't get the ping id or the last modification date without hitting the disk.
|
||||
// Since deletion has a special handling, we don't really need those.
|
||||
this._pendingPings.set(Utils.generateUUID(), {
|
||||
path: gDeletionPingFilePath,
|
||||
lastModificationDate: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
this._scannedPendingDirectory = true;
|
||||
return this._buildPingList();
|
||||
},
|
||||
|
@ -1760,6 +1770,53 @@ var TelemetryStorageImpl = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the deletion ping.
|
||||
* @param ping The deletion ping.
|
||||
* @return {Promise} Resolved when the ping is saved.
|
||||
*/
|
||||
async saveDeletionPing(ping) {
|
||||
this._log.trace("saveDeletionPing - ping path: " + gDeletionPingFilePath);
|
||||
await OS.File.makeDir(gDataReportingDir, { ignoreExisting: true });
|
||||
|
||||
let p = this._deletionPingSerializer.enqueueTask(() =>
|
||||
this.savePingToFile(ping, gDeletionPingFilePath, true));
|
||||
this._trackPendingPingSaveTask(p);
|
||||
return p;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the deletion ping.
|
||||
* @return {Promise} Resolved when the ping is deleted from the disk.
|
||||
*/
|
||||
async removeDeletionPing() {
|
||||
return this._deletionPingSerializer.enqueueTask(async () => {
|
||||
try {
|
||||
await OS.File.remove(gDeletionPingFilePath, { ignoreAbsent: false });
|
||||
this._log.trace("removeDeletionPing - success");
|
||||
} catch (ex) {
|
||||
if (ex.becauseNoSuchFile) {
|
||||
this._log.trace("removeDeletionPing - no such file");
|
||||
} else {
|
||||
this._log.error("removeDeletionPing - error removing ping", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
isDeletionPing(aPingId) {
|
||||
let pingInfo = this._pendingPings.get(aPingId);
|
||||
if (!pingInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pingInfo.path != gDeletionPingFilePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove FHR database files. This is temporary and will be dropped in
|
||||
* the future.
|
||||
|
|
|
@ -120,13 +120,6 @@ var TelemetryUtils = {
|
|||
FirstRunURL: "datareporting.policy.firstRunURL",
|
||||
}),
|
||||
|
||||
/**
|
||||
* A fixed valid client ID used when Telemetry upload is disabled.
|
||||
*/
|
||||
get knownClientID() {
|
||||
return "c0ffeec0-ffee-c0ff-eec0-ffeec0ffeec0";
|
||||
},
|
||||
|
||||
/**
|
||||
* True if this is a content process.
|
||||
*/
|
||||
|
|
|
@ -26,4 +26,4 @@ Important examples are:
|
|||
* :doc:`crash <../data/crash-ping>` - a ping that is captured and sent after a Firefox process crashes.
|
||||
* :doc:`new-profile <../data/new-profile-ping>` - sent on the first run of a new profile.
|
||||
* :doc:`update <../data/update-ping>` - sent right after an update is downloaded.
|
||||
* :doc:`optout <../data/optout-ping>` - sent when FHR upload is disabled
|
||||
* :doc:`deletion <../data/deletion-ping>` - sent when FHR upload is disabled, requesting deletion of the data associated with this user.
|
||||
|
|
|
@ -19,7 +19,7 @@ Structure:
|
|||
.. code-block:: js
|
||||
|
||||
{
|
||||
type: <string>, // "main", "activation", "optout", "saved-session", ...
|
||||
type: <string>, // "main", "activation", "deletion", "saved-session", ...
|
||||
id: <UUID>, // a UUID that identifies this ping
|
||||
creationDate: <ISO date>, // the date the ping was generated
|
||||
version: <number>, // the version of the ping format, currently 4
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
"deletion" ping (obsolete)
|
||||
==========================
|
||||
"deletion" ping
|
||||
===============
|
||||
|
||||
This ping is generated when a user turns off FHR upload from the Preferences panel, changing the related ``datareporting.healthreport.uploadEnabled`` preference. This requests that all associated data from that user be deleted.
|
||||
|
||||
|
@ -17,10 +17,3 @@ Structure:
|
|||
clientId: <UUID>,
|
||||
payload: { }
|
||||
}
|
||||
|
||||
Version History
|
||||
---------------
|
||||
|
||||
- Firefox 63:
|
||||
|
||||
- Replaced by "optout" ping (`bug 1445921 <https://bugzilla.mozilla.org/show_bug.cgi?id=1445921>`_).
|
||||
|
|
|
@ -10,7 +10,6 @@ Data documentation
|
|||
common-ping
|
||||
environment
|
||||
main-ping
|
||||
optout-ping
|
||||
deletion-ping
|
||||
crash-ping
|
||||
backgroundhangmonitor-ping
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
"optout" ping
|
||||
=============
|
||||
|
||||
This ping is generated when a user turns off FHR upload from the Preferences panel, changing the related ``datareporting.healthreport.uploadEnabled`` :doc:`preference <../internals/preferences>`.
|
||||
|
||||
This ping contains no client id and no environment data.
|
||||
|
||||
Structure:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
{
|
||||
version: 4,
|
||||
type: "optout",
|
||||
... common ping data
|
||||
payload: { }
|
||||
}
|
||||
|
||||
Expected behaviours
|
||||
-------------------
|
||||
The following is a list of expected behaviours for the ``optout`` ping:
|
||||
|
||||
- Sending the "optout" ping is best-effort. Telemetry tries to send the ping once and discards it immediately if sending fails.
|
||||
- The ping might be delayed if ping sending is throttled (e.g. around midnight).
|
||||
- The ping can be lost if the browser is shutdown before the ping is sent out the "optout" ping is discarded.
|
||||
|
||||
Version History
|
||||
---------------
|
||||
|
||||
- Firefox 63:
|
||||
|
||||
- "optout" ping replaced the "deletion" ping (`bug 1445921 <https://bugzilla.mozilla.org/show_bug.cgi?id=1445921>`_).
|
|
@ -165,9 +165,6 @@ function decodeRequestPayload(request) {
|
|||
payload = JSON.parse((new TextDecoder()).decode(bytes));
|
||||
}
|
||||
|
||||
// Check for canary value
|
||||
Assert.notEqual(OPTOUT_KNOWN_CLIENTID, payload.clientId, "Known clientId should never appear in a ping on the server");
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,9 @@ ChromeUtils.import("resource://gre/modules/TelemetrySend.jsm", this);
|
|||
ChromeUtils.import("resource://gre/modules/TelemetryArchive.jsm", this);
|
||||
ChromeUtils.import("resource://gre/modules/TelemetryUtils.jsm", this);
|
||||
ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
ChromeUtils.import("resource://testing-common/ContentTaskUtils.jsm", this);
|
||||
|
||||
const PING_FORMAT_VERSION = 4;
|
||||
const OPTOUT_PING_TYPE = "optout";
|
||||
const DELETION_PING_TYPE = "deletion";
|
||||
const TEST_PING_TYPE = "test-ping-type";
|
||||
|
||||
const PLATFORM_VERSION = "1.9.2";
|
||||
|
@ -138,58 +137,31 @@ add_task(async function test_simplePing() {
|
|||
});
|
||||
|
||||
add_task(async function test_disableDataUpload() {
|
||||
const OPTIN_PROBE = "telemetry.data_upload_optin";
|
||||
const isUnified = Preferences.get(TelemetryUtils.Preferences.Unified, false);
|
||||
if (!isUnified) {
|
||||
// Skipping the test if unified telemetry is off, as no optout ping will
|
||||
// Skipping the test if unified telemetry is off, as no deletion ping will
|
||||
// be generated.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that the optin probe is not set, there should be other data in the snapshot though
|
||||
let snapshot = Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false).parent;
|
||||
Assert.ok(!(OPTIN_PROBE in snapshot), "Data optin scalar should not be set at start");
|
||||
|
||||
// Send a first ping to get the current used client id
|
||||
await sendPing(true, false);
|
||||
let ping = await PingServer.promiseNextPing();
|
||||
checkPingFormat(ping, TEST_PING_TYPE, true, false);
|
||||
let firstClientId = ping.clientId;
|
||||
Assert.ok(firstClientId, "Test ping needs a client ID");
|
||||
Assert.notEqual(TelemetryUtils.knownClientID, firstClientId, "Client ID should be valid and random");
|
||||
|
||||
// Disable FHR upload: this should trigger a optout ping.
|
||||
// Disable FHR upload: this should trigger a deletion ping.
|
||||
Preferences.set(TelemetryUtils.Preferences.FhrUploadEnabled, false);
|
||||
|
||||
ping = await PingServer.promiseNextPing();
|
||||
checkPingFormat(ping, OPTOUT_PING_TYPE, false, false);
|
||||
let ping = await PingServer.promiseNextPing();
|
||||
checkPingFormat(ping, DELETION_PING_TYPE, true, false);
|
||||
// Wait on ping activity to settle.
|
||||
await TelemetrySend.testWaitOnOutgoingPings();
|
||||
|
||||
snapshot = Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false).parent;
|
||||
Assert.ok(!(OPTIN_PROBE in snapshot), "Data optin scalar should not be set after optout");
|
||||
|
||||
// Restore FHR Upload.
|
||||
Preferences.set(TelemetryUtils.Preferences.FhrUploadEnabled, true);
|
||||
|
||||
// We need to wait until the scalar is set
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
const snapshot =
|
||||
Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
|
||||
return Object.keys(snapshot).includes("parent") &&
|
||||
OPTIN_PROBE in snapshot.parent;
|
||||
});
|
||||
|
||||
snapshot = Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false).parent;
|
||||
Assert.ok(snapshot[OPTIN_PROBE], "Enabling data upload should set optin probe");
|
||||
|
||||
// Simulate a failure in sending the optout ping by disabling the HTTP server.
|
||||
// Simulate a failure in sending the deletion ping by disabling the HTTP server.
|
||||
await PingServer.stop();
|
||||
|
||||
// Try to send a ping. It will be saved as pending and get deleted when disabling upload.
|
||||
TelemetryController.submitExternalPing(TEST_PING_TYPE, {});
|
||||
|
||||
// Disable FHR upload to send a optout ping again.
|
||||
// Disable FHR upload to send a deletion ping again.
|
||||
Preferences.set(TelemetryUtils.Preferences.FhrUploadEnabled, false);
|
||||
|
||||
// Wait on sending activity to settle, as |TelemetryController.testReset()| doesn't do that.
|
||||
|
@ -202,8 +174,8 @@ add_task(async function test_disableDataUpload() {
|
|||
|
||||
// Disabling Telemetry upload must clear out all the pending pings.
|
||||
let pendingPings = await TelemetryStorage.loadPendingPingList();
|
||||
Assert.equal(pendingPings.length, 0,
|
||||
"All the pending pings should have been deleted, including the optout ping");
|
||||
Assert.equal(pendingPings.length, 1,
|
||||
"All the pending pings but the deletion ping should have been deleted");
|
||||
|
||||
// Enable the ping server again.
|
||||
PingServer.start();
|
||||
|
@ -215,20 +187,8 @@ add_task(async function test_disableDataUpload() {
|
|||
await TelemetrySend.shutdown();
|
||||
// Reset the controller to spin the ping sending task.
|
||||
await TelemetryController.testReset();
|
||||
|
||||
// Re-enable Telemetry
|
||||
Preferences.set(TelemetryUtils.Preferences.FhrUploadEnabled, true);
|
||||
|
||||
// Send a test ping
|
||||
await sendPing(true, false);
|
||||
|
||||
// We should have only received the test ping
|
||||
ping = await PingServer.promiseNextPing();
|
||||
checkPingFormat(ping, TEST_PING_TYPE, true, false);
|
||||
|
||||
// The data in the test ping should be different than before
|
||||
Assert.notEqual(TelemetryUtils.knownClientID, ping.clientId, "Client ID should be reset to a random value");
|
||||
Assert.notEqual(firstClientId, ping.clientId, "Client ID should be different from the previous value");
|
||||
checkPingFormat(ping, DELETION_PING_TYPE, true, false);
|
||||
|
||||
// Wait on ping activity to settle before moving on to the next test. If we were
|
||||
// to shut down telemetry, even though the PingServer caught the expected pings,
|
||||
|
@ -236,6 +196,8 @@ add_task(async function test_disableDataUpload() {
|
|||
// a couple of ticks). Shutting down would cancel the request and save them as
|
||||
// pending pings.
|
||||
await TelemetrySend.testWaitOnOutgoingPings();
|
||||
// Restore FHR Upload.
|
||||
Preferences.set(TelemetryUtils.Preferences.FhrUploadEnabled, true);
|
||||
});
|
||||
|
||||
add_task(async function test_pingHasClientId() {
|
||||
|
@ -331,11 +293,11 @@ add_task(async function test_archivePings() {
|
|||
const uploadPref = isUnified ? TelemetryUtils.Preferences.FhrUploadEnabled : TelemetryUtils.Preferences.TelemetryEnabled;
|
||||
Preferences.set(uploadPref, false);
|
||||
|
||||
// If we're using unified telemetry, disabling ping upload will generate a "optout"
|
||||
// If we're using unified telemetry, disabling ping upload will generate a "deletion"
|
||||
// ping. Catch it.
|
||||
if (isUnified) {
|
||||
let ping = await PingServer.promiseNextPing();
|
||||
checkPingFormat(ping, OPTOUT_PING_TYPE, false, false);
|
||||
checkPingFormat(ping, DELETION_PING_TYPE, true, false);
|
||||
}
|
||||
|
||||
// Register a new Ping Handler that asserts if a ping is received, then send a ping.
|
||||
|
|
|
@ -352,7 +352,7 @@ add_task(async function test_pendingPingsQuota() {
|
|||
await TelemetrySend.testWaitOnOutgoingPings();
|
||||
await TelemetryStorage.testPendingQuotaTaskPromise();
|
||||
|
||||
// Remove the pending optout ping generated when flipping FHR upload off.
|
||||
// Remove the pending deletion ping generated when flipping FHR upload off.
|
||||
await TelemetryStorage.testClearPendingPings();
|
||||
|
||||
let expectedPrunedPings = [];
|
||||
|
|
|
@ -56,7 +56,7 @@ var ClientID = Object.freeze({
|
|||
return ClientIDImpl.getClientID();
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the client id synchronously without hitting the disk.
|
||||
* This returns:
|
||||
* - the current on-disk client id if it was already loaded
|
||||
|
@ -67,31 +67,6 @@ var ClientID = Object.freeze({
|
|||
return ClientIDImpl.getCachedClientID();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a specific client id asynchronously, writing it to disk
|
||||
* and updating the cached version.
|
||||
*
|
||||
* Should only ever be used when a known client ID value should be set.
|
||||
* Use `resetClientID` to generate a new random one if required.
|
||||
*
|
||||
* @return {Promise<string>} The stable client ID.
|
||||
*/
|
||||
setClientID(id) {
|
||||
return ClientIDImpl.setClientID(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the client id asynchronously, writing it to disk
|
||||
* and updating the cached version.
|
||||
*
|
||||
* Should only be used if a reset is explicitely requested by the user.
|
||||
*
|
||||
* @return {Promise<string>} A new stable client ID.
|
||||
*/
|
||||
resetClientID() {
|
||||
return ClientIDImpl.resetClientID();
|
||||
},
|
||||
|
||||
/**
|
||||
* Only used for testing. Invalidates the client ID so that it gets read
|
||||
* again from file.
|
||||
|
@ -105,7 +80,6 @@ var ClientIDImpl = {
|
|||
_clientID: null,
|
||||
_loadClientIdTask: null,
|
||||
_saveClientIdTask: null,
|
||||
_removeClientIdTask: null,
|
||||
_logger: null,
|
||||
|
||||
_loadClientID() {
|
||||
|
@ -124,9 +98,6 @@ var ClientIDImpl = {
|
|||
* If no Client ID is found, we generate a new one.
|
||||
*/
|
||||
async _doLoadClientID() {
|
||||
// If there's a removal in progress, let's wait for it
|
||||
await this._removeClientIdTask;
|
||||
|
||||
// Try to load the client id from the DRS state file.
|
||||
try {
|
||||
let state = await CommonUtils.readJSON(gStateFilePath);
|
||||
|
@ -221,40 +192,6 @@ var ClientIDImpl = {
|
|||
this._clientID = null;
|
||||
},
|
||||
|
||||
async setClientID(id) {
|
||||
if (!this.updateClientID(id)) {
|
||||
throw ("Invalid client ID: " + id);
|
||||
}
|
||||
|
||||
this._saveClientIdTask = this._saveClientID();
|
||||
await this._saveClientIdTask;
|
||||
return this._clientID;
|
||||
},
|
||||
|
||||
async _doRemoveClientID() {
|
||||
// Reset stored id.
|
||||
this._clientID = null;
|
||||
|
||||
// Clear the client id from the preference cache.
|
||||
Services.prefs.clearUserPref(PREF_CACHED_CLIENTID);
|
||||
|
||||
// Remove the client id from disk
|
||||
await OS.File.remove(gStateFilePath, {ignoreAbsent: true});
|
||||
},
|
||||
|
||||
async resetClientID() {
|
||||
// Wait for the removal.
|
||||
// Asynchronous calls to getClientID will also be blocked on this.
|
||||
this._removeClientIdTask = this._doRemoveClientID();
|
||||
let clear = () => this._removeClientIdTask = null;
|
||||
this._removeClientIdTask.then(clear, clear);
|
||||
|
||||
await this._removeClientIdTask;
|
||||
|
||||
// Generate a new id.
|
||||
return this.getClientID();
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the client id to the given value and updates the value cached in
|
||||
* preferences only if the given id is a valid.
|
||||
|
|
|
@ -8,8 +8,6 @@ ChromeUtils.import("resource://services-common/utils.js");
|
|||
ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const PREF_CACHED_CLIENTID = "toolkit.telemetry.cachedClientID";
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
run_next_test();
|
||||
|
@ -26,6 +24,7 @@ add_task(async function() {
|
|||
["", "setStringPref"],
|
||||
["3d1e1560-682a-4043-8cf2-aaaaaaaaaaaZ", "setStringPref"],
|
||||
];
|
||||
const PREF_CACHED_CLIENTID = "toolkit.telemetry.cachedClientID";
|
||||
|
||||
// If there is no DRS file, we should get a new client ID.
|
||||
await ClientID._reset();
|
||||
|
@ -61,72 +60,3 @@ add_task(async function() {
|
|||
"ClientID should reset invalid cached IDs");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_setClientID() {
|
||||
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
const invalidIDs = [
|
||||
-1,
|
||||
0.5,
|
||||
"INVALID-UUID",
|
||||
true,
|
||||
"",
|
||||
"3d1e1560-682a-4043-8cf2-aaaaaaaaaaaZ",
|
||||
];
|
||||
const KNOWN_UUID = "c0ffeec0-ffee-c0ff-eec0-ffeec0ffeec0";
|
||||
|
||||
await ClientID._reset();
|
||||
|
||||
// We should be able to set a valid UUID
|
||||
await ClientID.setClientID(KNOWN_UUID);
|
||||
let clientID = await ClientID.getClientID();
|
||||
Assert.equal(KNOWN_UUID, clientID);
|
||||
|
||||
// Setting invalid UUIDs should always fail and not modify the client ID
|
||||
for (let invalidID of invalidIDs) {
|
||||
await ClientID._reset();
|
||||
let prevClientID = await ClientID.getClientID();
|
||||
await ClientID.setClientID(invalidID)
|
||||
.then(() => Assert.ok(false, `Invalid client ID '${invalidID}' should be rejected`))
|
||||
.catch(() => Assert.ok(true));
|
||||
|
||||
clientID = await ClientID.getClientID();
|
||||
Assert.equal(typeof(clientID), "string");
|
||||
Assert.ok(uuidRegex.test(clientID));
|
||||
Assert.equal(prevClientID, clientID);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_resetClientID() {
|
||||
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
|
||||
// We should get a valid UUID after reset
|
||||
await ClientID._reset();
|
||||
let firstClientID = await ClientID.getClientID();
|
||||
Assert.equal(typeof(firstClientID), "string");
|
||||
Assert.ok(uuidRegex.test(firstClientID));
|
||||
|
||||
// When resetting again we should get a new ID
|
||||
let nextClientID = await ClientID.resetClientID();
|
||||
Assert.equal(typeof(nextClientID), "string");
|
||||
Assert.ok(uuidRegex.test(nextClientID));
|
||||
Assert.notEqual(firstClientID, nextClientID, "After reset client ID should be different.");
|
||||
|
||||
let cachedID = ClientID.getCachedClientID();
|
||||
Assert.equal(nextClientID, cachedID);
|
||||
|
||||
let prefClientID = Services.prefs.getStringPref(PREF_CACHED_CLIENTID, null);
|
||||
Assert.equal(nextClientID, prefClientID);
|
||||
});
|
||||
|
||||
add_task(async function test_resetParallelGet() {
|
||||
// We should get a valid UUID after reset
|
||||
let firstClientID = await ClientID.resetClientID();
|
||||
|
||||
// We should get the same ID twice when requesting it in parallel to a reset.
|
||||
let p = ClientID.resetClientID();
|
||||
let newClientID = await ClientID.getClientID();
|
||||
let otherClientID = await p;
|
||||
|
||||
Assert.notEqual(firstClientID, newClientID, "After reset client ID should be different.");
|
||||
Assert.equal(newClientID, otherClientID, "Getting the client ID in parallel to a reset should give the same id.");
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче