From ea2a18d757eea50b482eb6d85f555b6de25c6778 Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Mon, 29 Mar 2021 20:03:38 +0000 Subject: [PATCH] Bug 1697555 - Remove Telemetry portions of Accounts Ecosystem Telemetry r=Dexter Differential Revision: https://phabricator.services.mozilla.com/D110091 --- .eslintrc.js | 1 - browser/app/profile/firefox.js | 2 - browser/modules/test/unit/test_discovery.js | 2 +- .../mozperftest/system/pingserver.py | 1 - .../defaults/backgroundtasks.js | 1 - toolkit/components/telemetry/app/ClientID.jsm | 208 +++------ .../app/TelemetryControllerParent.jsm | 12 +- .../telemetry/app/TelemetryScheduler.jsm | 4 - .../telemetry/app/TelemetryUtils.jsm | 5 - .../telemetry/docs/internals/preferences.rst | 14 - toolkit/components/telemetry/moz.build | 1 - .../telemetry/pings/EcosystemTelemetry.jsm | 406 ----------------- .../components/telemetry/tests/unit/head.js | 7 - .../tests/unit/test_EcosystemTelemetry.js | 430 ------------------ .../tests/unit/test_TelemetryController.js | 11 - .../telemetry/tests/unit/test_client_id.js | 142 +----- .../telemetry/tests/unit/xpcshell.ini | 2 - 17 files changed, 71 insertions(+), 1178 deletions(-) delete mode 100644 toolkit/components/telemetry/pings/EcosystemTelemetry.jsm delete mode 100644 toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js diff --git a/.eslintrc.js b/.eslintrc.js index c7d2b3dadd4b..eba3bef247e4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -612,7 +612,6 @@ module.exports = { "toolkit/components/passwordmgr/test/unit/test_getUserNameAndPasswordFields.js", "toolkit/components/processsingleton/MainProcessSingleton.jsm", "toolkit/components/telemetry/tests/unit/head.js", - "toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js", "toolkit/components/telemetry/tests/unit/test_EventPing.js", "toolkit/components/telemetry/tests/unit/test_HealthPing.js", "toolkit/components/telemetry/tests/unit/test_PingAPI.js", diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 81c91b10bba8..85374ca1dd01 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1681,8 +1681,6 @@ pref("toolkit.telemetry.newProfilePing.enabled", true); pref("toolkit.telemetry.updatePing.enabled", true); // Enables sending 'bhr' pings when the browser hangs. pref("toolkit.telemetry.bhrPing.enabled", true); -// Whether to enable Ecosystem Telemetry, requires a restart. -pref("toolkit.telemetry.ecosystemtelemetry.enabled", false); // Ping Centre Telemetry settings. pref("browser.ping-centre.telemetry", true); diff --git a/browser/modules/test/unit/test_discovery.js b/browser/modules/test/unit/test_discovery.js index 2d3205abfbf8..0bc1fe25b690 100644 --- a/browser/modules/test/unit/test_discovery.js +++ b/browser/modules/test/unit/test_discovery.js @@ -126,7 +126,7 @@ add_task(async function test_discovery() { equal(cookie.host, uri.host, "cookie exists for host"); return true; }); - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); await ClientID.getClientID(); await changed; diff --git a/python/mozperftest/mozperftest/system/pingserver.py b/python/mozperftest/mozperftest/system/pingserver.py index 6273e2e4bc02..2e33351e182d 100644 --- a/python/mozperftest/mozperftest/system/pingserver.py +++ b/python/mozperftest/mozperftest/system/pingserver.py @@ -68,7 +68,6 @@ class PingServer(Layer): "toolkit.telemetry.enabled": True, "toolkit.telemetry.unified": True, "toolkit.telemetry.shutdownPingSender.enabled": True, - "toolkit.telemetry.ecosystemtelemetry.enabled": True, "datareporting.policy.dataSubmissionPolicyBypassNotification": True, "toolkit.telemetry.send.overrideOfficialCheck": True, } diff --git a/toolkit/components/backgroundtasks/defaults/backgroundtasks.js b/toolkit/components/backgroundtasks/defaults/backgroundtasks.js index a52c1b117873..9f95c31fea2e 100644 --- a/toolkit/components/backgroundtasks/defaults/backgroundtasks.js +++ b/toolkit/components/backgroundtasks/defaults/backgroundtasks.js @@ -12,7 +12,6 @@ pref("toolkit.telemetry.firstShutdownPing.enabled", false); pref("toolkit.telemetry.healthping.enabled", false); pref("toolkit.telemetry.newProfilePing.enabled", false); pref("toolkit.telemetry.eventping.enabled", false); -pref("toolkit.telemetry.ecosystemtelemetry.enabled", false); pref("toolkit.telemetry.prioping.enabled", false); pref("datareporting.policy.dataSubmissionEnabled", false); pref("datareporting.healthreport.uploadEnabled", false); diff --git a/toolkit/components/telemetry/app/ClientID.jsm b/toolkit/components/telemetry/app/ClientID.jsm index 0b4db3310a44..36d846982dd7 100644 --- a/toolkit/components/telemetry/app/ClientID.jsm +++ b/toolkit/components/telemetry/app/ClientID.jsm @@ -47,9 +47,6 @@ XPCOMUtils.defineLazyGetter(this, "gStateFilePath", () => { const PREF_CACHED_CLIENTID = "toolkit.telemetry.cachedClientID"; -const SCALAR_DELETION_REQUEST_ECOSYSTEM_CLIENT_ID = - "deletion.request.ecosystem_client_id"; - /** * Checks if client ID has a valid format. * @@ -78,16 +75,6 @@ var ClientID = Object.freeze({ return ClientIDImpl.getClientID(); }, - /** - * Returns a promise resolving to the ecosystem client ID, used in ecosystem - * pings as a stable identifier for this profile. - * - * @return {Promise} The ecosystem client ID. - */ - getEcosystemClientID() { - return ClientIDImpl.getEcosystemClientID(); - }, - /** * This returns true if the client ID prior to the last client ID reset was a canary client ID. * Android only. Always returns null on Desktop. @@ -111,62 +98,39 @@ var ClientID = Object.freeze({ return ClientIDImpl.getCachedClientID(); }, - /** - * Gets the in-memory cached ecosystem client ID if it was already loaded; - * `null` otherwise. - */ - getCachedEcosystemClientID() { - return ClientIDImpl.getCachedEcosystemClientID(); - }, - async getClientIdHash() { return ClientIDImpl.getClientIdHash(); }, /** - * Sets the main and ecosystem client IDs to the canary (known) client ID, - * writing them to disk and updating the cached versions. + * Sets the client ID to the canary (known) client ID, + * writing it to disk and updating the cached version. * - * Use `removeClientIDs` followed by `get{Ecosystem}ClientID` to clear the - * existing IDs and generate new, random ones if required. + * Use `removeClientID` followed by `getClientID` to clear the + * existing ID and generate a new, random one if required. * * @return {Promise} */ - setCanaryClientIDs() { - return ClientIDImpl.setCanaryClientIDs(); + setCanaryClientID() { + return ClientIDImpl.setCanaryClientID(); }, /** - * Sets the ecosystem client IDs to a new random value while leaving other IDs - * unchanged, writing the result to disk and updating the cached identifier. - * This can be used when a user signs out, to avoid linking telemetry between - * different accounts. - * - * Use `removeClientIDs` followed by `get{Ecosystem}ClientID` to reset *all* the - * identifiers rather than just the ecosystem client id. - * - * @return {Promise} Resolves when the change has been saved to disk. - */ - resetEcosystemClientID() { - return ClientIDImpl.resetEcosystemClientID(); - }, - - /** - * Clears the main and ecosystem client IDs asynchronously, removing them - * from disk. Use `getClientID()` and `getEcosystemClientID()` to generate - * fresh IDs after calling this method. + * Clears the client ID asynchronously, removing it + * from disk. Use `getClientID()` to generate + * a fresh ID after calling this method. * * Should only be used if a reset is explicitly requested by the user. * * @return {Promise} */ - removeClientIDs() { - return ClientIDImpl.removeClientIDs(); + removeClientID() { + return ClientIDImpl.removeClientID(); }, /** - * Only used for testing. Invalidates the cached client IDs so that they're - * read again from file, but doesn't remove the existing IDs from disk. + * Only used for testing. Invalidates the cached client ID so that it is + * read again from file, but doesn't remove the existing ID from disk. */ _reset() { return ClientIDImpl._reset(); @@ -176,37 +140,34 @@ var ClientID = Object.freeze({ var ClientIDImpl = { _clientID: null, _clientIDHash: null, - _ecosystemClientID: null, - _loadClientIdsTask: null, - _saveClientIdsTask: null, - _removeClientIdsTask: null, + _loadClientIdTask: null, + _saveClientIdTask: null, + _removeClientIdTask: null, _logger: null, _wasCanary: null, - _loadClientIDs() { - if (this._loadClientIdsTask) { - return this._loadClientIdsTask; + _loadClientID() { + if (this._loadClientIdTask) { + return this._loadClientIdTask; } - this._loadClientIdsTask = this._doLoadClientIDs(); - let clear = () => (this._loadClientIdsTask = null); - this._loadClientIdsTask.then(clear, clear); - return this._loadClientIdsTask; + this._loadClientIdTask = this._doLoadClientID(); + let clear = () => (this._loadClientIdTask = null); + this._loadClientIdTask.then(clear, clear); + return this._loadClientIdTask; }, /** - * Load the client IDs (Telemetry Client ID and Ecosystem Client ID) from the - * DataReporting Service state file. If either ID is missing, we generate a - * new one. + * Load the client ID from the DataReporting Service state file. If it is + * missing, we generate a new one. */ - async _doLoadClientIDs() { - this._log.trace(`_doLoadClientIDs`); + async _doLoadClientID() { + this._log.trace(`_doLoadClientID`); // If there's a removal in progress, let's wait for it - await this._removeClientIdsTask; + await this._removeClientIdTask; // Try to load the client id from the DRS state file. let hasCurrentClientID = false; - let hasCurrentEcosystemClientID = false; try { let state = await CommonUtils.readJSON(gStateFilePath); if (AppConstants.platform == "android" && state && "wasCanary" in state) { @@ -230,14 +191,10 @@ var ClientIDImpl = { // This data collection's not that important. } hasCurrentClientID = this.updateClientID(state.clientID); - hasCurrentEcosystemClientID = this.updateEcosystemClientID( - state.ecosystemClientID - ); - if (hasCurrentClientID && hasCurrentEcosystemClientID) { - this._log.trace(`_doLoadClientIDs: Client IDs loaded from state.`); + if (hasCurrentClientID) { + this._log.trace(`_doLoadClientID: Client IDs loaded from state.`); return { clientID: this._clientID, - ecosystemClientID: this._ecosystemClientID, }; } } @@ -256,27 +213,23 @@ var ClientIDImpl = { } } - // We're missing one or both IDs from the DRS state file and prefs. - // Generate new ones. + // We're missing the ID from the DRS state file and prefs. + // Generate a new one. if (!hasCurrentClientID) { Services.telemetry.scalarSet("telemetry.generated_new_client_id", true); this.updateClientID(CommonUtils.generateUUID()); } - if (!hasCurrentEcosystemClientID) { - this.updateEcosystemClientID(CommonUtils.generateUUID()); - } - this._saveClientIdsTask = this._saveClientIDs(); + this._saveClientIdTask = this._saveClientID(); // Wait on persisting the id. Otherwise failure to save the ID would result in // the client creating and subsequently sending multiple IDs to the server. // This would appear as multiple clients submitting similar data, which would // result in orphaning. - await this._saveClientIdsTask; + await this._saveClientIdTask; - this._log.trace("_doLoadClientIDs: New client IDs loaded and persisted."); + this._log.trace("_doLoadClientID: New client ID loaded and persisted."); return { clientID: this._clientID, - ecosystemClientID: this._ecosystemClientID, }; }, @@ -285,12 +238,11 @@ var ClientIDImpl = { * * @return {Promise} A promise resolved when the client ID is saved to disk. */ - async _saveClientIDs() { + async _saveClientID() { try { - this._log.trace(`_saveClientIDs`); + this._log.trace(`_saveClientID`); let obj = { clientID: this._clientID, - ecosystemClientID: this._ecosystemClientID, }; // We detected a canary client ID when resetting, storing this as a flag if (AppConstants.platform == "android" && this._wasCanary) { @@ -304,7 +256,7 @@ var ClientIDImpl = { } } await CommonUtils.writeJSON(obj, gStateFilePath); - this._saveClientIdsTask = null; + this._saveClientIdTask = null; } catch (ex) { Services.telemetry.scalarAdd("telemetry.state_file_save_errors", 1); throw ex; @@ -319,22 +271,13 @@ var ClientIDImpl = { */ async getClientID() { if (!this._clientID) { - let { clientID } = await this._loadClientIDs(); + let { clientID } = await this._loadClientID(); return clientID; } return Promise.resolve(this._clientID); }, - async getEcosystemClientID() { - if (!this._ecosystemClientID) { - let { ecosystemClientID } = await this._loadClientIDs(); - return ecosystemClientID; - } - - return Promise.resolve(this._ecosystemClientID); - }, - /** * This returns true if the client ID prior to the last client ID reset was a canary client ID. * Android only. Always returns null on Desktop. @@ -387,10 +330,6 @@ var ClientIDImpl = { return id; }, - getCachedEcosystemClientID() { - return this._ecosystemClientID; - }, - async getClientIdHash() { if (!this._clientIDHash) { let byteArr = new TextEncoder().encode(await this.getClientID()); @@ -402,70 +341,53 @@ var ClientIDImpl = { }, /* - * Resets the provider. This is for testing only. + * Resets the module. This is for testing only. */ async _reset() { - await this._loadClientIdsTask; - await this._saveClientIdsTask; + await this._loadClientIdTask; + await this._saveClientIdTask; this._clientID = null; this._clientIDHash = null; - this._ecosystemClientID = null; }, - async setCanaryClientIDs() { - this._log.trace("setCanaryClientIDs"); + async setCanaryClientID() { + this._log.trace("setCanaryClientID"); this.updateClientID(CANARY_CLIENT_ID); - this.updateEcosystemClientID(CANARY_CLIENT_ID); - this._saveClientIdsTask = this._saveClientIDs(); - await this._saveClientIdsTask; + this._saveClientIdTask = this._saveClientID(); + await this._saveClientIdTask; return this._clientID; }, - async resetEcosystemClientID() { - this._log.trace("resetEcosystemClientID"); - this.updateEcosystemClientID(CommonUtils.generateUUID()); - this._saveClientIdsTask = this._saveClientIDs(); - await this._saveClientIdsTask; - return this._ecosystemClientID; - }, + async _doRemoveClientID() { + this._log.trace("_doRemoveClientID"); - async _doRemoveClientIDs() { - this._log.trace("_doRemoveClientIDs"); - - // Reset the cached main and ecosystem client IDs. + // Reset the cached client ID. this._clientID = null; this._clientIDHash = null; - this._ecosystemClientID = null; // Clear the client id from the preference cache. Services.prefs.clearUserPref(PREF_CACHED_CLIENTID); - // Clear the old ecosystem client ID from the deletion request scalar store. - Services.telemetry.scalarSet( - SCALAR_DELETION_REQUEST_ECOSYSTEM_CLIENT_ID, - "" - ); - // If there is a save in progress, wait for it to complete. - await this._saveClientIdsTask; + await this._saveClientIdTask; - // Remove the client id from disk + // Remove the client-id-containing state file from disk await IOUtils.remove(gStateFilePath); }, - async removeClientIDs() { - this._log.trace("removeClientIDs"); + async removeClientID() { + this._log.trace("removeClientID"); Services.telemetry.scalarAdd("telemetry.removed_client_ids", 1); let oldClientId = this._clientID; // Wait for the removal. // Asynchronous calls to getClientID will also be blocked on this. - this._removeClientIdsTask = this._doRemoveClientIDs(); - let clear = () => (this._removeClientIdsTask = null); - this._removeClientIdsTask.then(clear, clear); + this._removeClientIdTask = this._doRemoveClientID(); + let clear = () => (this._removeClientIdTask = null); + this._removeClientIdTask.then(clear, clear); - await this._removeClientIdsTask; + await this._removeClientIdTask; // On Android we detect resets after a canary client ID. if (AppConstants.platform == "android") { @@ -494,22 +416,6 @@ var ClientIDImpl = { return true; }, - updateEcosystemClientID(id) { - if (!isValidClientID(id)) { - this._log.error( - "updateEcosystemClientID - invalid ecosystem client ID", - id - ); - return false; - } - this._ecosystemClientID = id; - Services.telemetry.scalarSet( - SCALAR_DELETION_REQUEST_ECOSYSTEM_CLIENT_ID, - id - ); - return true; - }, - /** * A helper for getting access to telemetry logger. */ diff --git a/toolkit/components/telemetry/app/TelemetryControllerParent.jsm b/toolkit/components/telemetry/app/TelemetryControllerParent.jsm index 4dfa8507b65b..3eda96e9b63b 100644 --- a/toolkit/components/telemetry/app/TelemetryControllerParent.jsm +++ b/toolkit/components/telemetry/app/TelemetryControllerParent.jsm @@ -78,7 +78,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { UpdatePing: "resource://gre/modules/UpdatePing.jsm", TelemetryHealthPing: "resource://gre/modules/HealthPing.jsm", TelemetryEventPing: "resource://gre/modules/EventPing.jsm", - EcosystemTelemetry: "resource://gre/modules/EcosystemTelemetry.jsm", TelemetryPrioPing: "resource://gre/modules/PrioPing.jsm", UninstallPing: "resource://gre/modules/UninstallPing.jsm", OS: "resource://gre/modules/osfile.jsm", @@ -850,13 +849,13 @@ var Impl = { this._log.trace( "Upload enabled, but got canary client ID. Resetting." ); - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); this._clientID = await ClientID.getClientID(); } else if (!uploadEnabled && this._clientID != Utils.knownClientID) { this._log.trace( "Upload disabled, but got a valid client ID. Setting canary client ID." ); - await ClientID.setCanaryClientIDs(); + await ClientID.setCanaryClientID(); this._clientID = await ClientID.getClientID(); } @@ -904,7 +903,6 @@ var Impl = { } TelemetryEventPing.startup(); - EcosystemTelemetry.startup(); TelemetryPrioPing.startup(); if (uploadEnabled) { @@ -962,8 +960,6 @@ var Impl = { this._shutdownStep = "Event" + now(); TelemetryEventPing.shutdown(); - this._shutdownStep = "Ecosystem" + now(); - EcosystemTelemetry.shutdown(); this._shutdownStep = "Prio" + now(); await TelemetryPrioPing.shutdown(); @@ -1118,7 +1114,7 @@ var Impl = { // Generate a new client ID and make sure this module uses the new version let p = (async () => { - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); let id = await ClientID.getClientID(); this._clientID = id; Telemetry.scalarSet("telemetry.data_upload_optin", true); @@ -1164,7 +1160,7 @@ var Impl = { // 6. Set ClientID to a known value let oldClientId = await ClientID.getClientID(); - await ClientID.setCanaryClientIDs(); + await ClientID.setCanaryClientID(); this._clientID = await ClientID.getClientID(); // 7. Send the deletion-request ping. diff --git a/toolkit/components/telemetry/app/TelemetryScheduler.jsm b/toolkit/components/telemetry/app/TelemetryScheduler.jsm index 9a422336f103..451c5b9ff7ca 100644 --- a/toolkit/components/telemetry/app/TelemetryScheduler.jsm +++ b/toolkit/components/telemetry/app/TelemetryScheduler.jsm @@ -21,9 +21,6 @@ const { clearTimeout, setTimeout } = ChromeUtils.import( "resource://gre/modules/Timer.jsm" ); // Other pings -const { EcosystemTelemetry } = ChromeUtils.import( - "resource://gre/modules/EcosystemTelemetry.jsm" -); const { TelemetryPrioPing } = ChromeUtils.import( "resource://gre/modules/PrioPing.jsm" ); @@ -374,7 +371,6 @@ var TelemetryScheduler = { this._log.trace("_schedulerTickLogic - Periodic ping due."); this._lastPeriodicPingTime = now; // Send other pings. - EcosystemTelemetry.periodicPing(); TelemetryPrioPing.periodicPing(); } diff --git a/toolkit/components/telemetry/app/TelemetryUtils.jsm b/toolkit/components/telemetry/app/TelemetryUtils.jsm index 6b8b93590100..a9a55ae464d6 100644 --- a/toolkit/components/telemetry/app/TelemetryUtils.jsm +++ b/toolkit/components/telemetry/app/TelemetryUtils.jsm @@ -82,11 +82,6 @@ var TelemetryUtils = { EventPingMinimumFrequency: "toolkit.telemetry.eventping.minimumFrequency", EventPingMaximumFrequency: "toolkit.telemetry.eventping.maximumFrequency", - // Ecosystem Telemetry Preferences - EcosystemTelemetryEnabled: "toolkit.telemetry.ecosystemtelemetry.enabled", - EcosystemTelemetryAllowForNonProductionFxA: - "toolkit.telemetry.ecosystemtelemetry.allowForNonProductionFxA", - // Prio Ping Preferences PrioPingEnabled: "toolkit.telemetry.prioping.enabled", PrioPingDataLimit: "toolkit.telemetry.prioping.dataLimit", diff --git a/toolkit/components/telemetry/docs/internals/preferences.rst b/toolkit/components/telemetry/docs/internals/preferences.rst index a7c5a0bb4975..f91c2397a15e 100644 --- a/toolkit/components/telemetry/docs/internals/preferences.rst +++ b/toolkit/components/telemetry/docs/internals/preferences.rst @@ -148,20 +148,6 @@ Preferences The maximum frequency at which an :doc:`../data/event-ping` will be sent. Default is 10 (minutes). -``toolkit.telemetry.ecosystemtelemetry.enabled`` - - Whether :doc:`../data/ecosystem-telemetry` is enabled. - Default is false. Change requires restart. - -``toolkit.telemetry.ecosystemtelemetry.allowForNonProductionFx`` - - Whether :doc:`../data/ecosystem-telemetry` will be submitted if Firefox is - configured to use non-production FxA servers. Non-production servers includes - servers run by Mozilla (eg, the "staging" or "dev" instances) and servers run - externally (eg, self-hosted users). The expectation is that this will - primarily be used for QA. - Default is false. Change requires restart. - ``toolkit.telemetry.overrideUpdateChannel`` Override the ``channel`` value that is reported via Telemetry. diff --git a/toolkit/components/telemetry/moz.build b/toolkit/components/telemetry/moz.build index 32e670b76b18..3eee4e938c4e 100644 --- a/toolkit/components/telemetry/moz.build +++ b/toolkit/components/telemetry/moz.build @@ -106,7 +106,6 @@ EXTRA_JS_MODULES += [ "app/TelemetryTimestamps.jsm", "app/TelemetryUtils.jsm", "pings/CoveragePing.jsm", - "pings/EcosystemTelemetry.jsm", "pings/EventPing.jsm", "pings/HealthPing.jsm", "pings/ModulesPing.jsm", diff --git a/toolkit/components/telemetry/pings/EcosystemTelemetry.jsm b/toolkit/components/telemetry/pings/EcosystemTelemetry.jsm deleted file mode 100644 index b855acef372c..000000000000 --- a/toolkit/components/telemetry/pings/EcosystemTelemetry.jsm +++ /dev/null @@ -1,406 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * This module sends the Telemetry Ecosystem pings periodically: - * https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/ecosystem-telemetry.html - * - * Note that ecosystem pings are only sent when the preference - * `toolkit.telemetry.ecosystemtelemetry.enabled` is set to `true` - eventually - * that will be the default, but you should check! - * - * Note also that these pings are currently only sent for users signed in to - * Firefox with a Firefox account. - * - * If you are using the non-production FxA stack, pings are not sent by default. - * To force them, you should set: - * - toolkit.telemetry.ecosystemtelemetry.allowForNonProductionFxA: true - * - * If you are trying to debug this, you might also find the following - * preferences useful: - * - toolkit.telemetry.log.level: "Trace" - * - toolkit.telemetry.log.dump: true - */ - -"use strict"; - -var EXPORTED_SYMBOLS = ["EcosystemTelemetry"]; - -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -XPCOMUtils.defineLazyModuleGetters(this, { - ONLOGIN_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", - ONLOGOUT_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", - ONVERIFIED_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", - ON_PRELOGOUT_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", - TelemetryController: "resource://gre/modules/TelemetryController.jsm", - TelemetryUtils: "resource://gre/modules/TelemetryUtils.jsm", - TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", - Log: "resource://gre/modules/Log.jsm", - Services: "resource://gre/modules/Services.jsm", - fxAccounts: "resource://gre/modules/FxAccounts.jsm", - FxAccounts: "resource://gre/modules/FxAccounts.jsm", - ClientID: "resource://gre/modules/ClientID.jsm", -}); - -XPCOMUtils.defineLazyServiceGetters(this, { - Telemetry: ["@mozilla.org/base/telemetry;1", "nsITelemetry"], -}); - -const LOGGER_NAME = "Toolkit.Telemetry"; -const LOGGER_PREFIX = "EcosystemTelemetry::"; - -XPCOMUtils.defineLazyGetter(this, "log", () => { - return Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX); -}); - -var Policy = { - sendPing: (type, payload, options) => - TelemetryController.submitExternalPing(type, payload, options), - monotonicNow: () => TelemetryUtils.monotonicNow(), - // Returns a promise that resolves with the Ecosystem anonymized id. - // Never rejects - will log an error and resolve with null on error. - async getEcosystemAnonId() { - try { - let userData = await fxAccounts.getSignedInUser(); - if (!userData || !userData.verified) { - log.debug("No ecosystem anonymized ID - no user or unverified user"); - return null; - } - return await fxAccounts.telemetry.ensureEcosystemAnonId(); - } catch (ex) { - log.error("Failed to fetch the ecosystem anonymized ID", ex); - return null; - } - }, - // Returns a promise that resolves with the current ecosystem client id. - getEcosystemClientId() { - return ClientID.getEcosystemClientID(); - }, - // Returns a promise that resolves when the ecosystem client id has been reset. - resetEcosystemClientId() { - return ClientID.resetEcosystemClientID(); - }, -}; - -var EcosystemTelemetry = { - Reason: Object.freeze({ - PERIODIC: "periodic", // Send the ping in regular intervals - SHUTDOWN: "shutdown", // Send the ping on shutdown - LOGOUT: "logout", // Send after FxA logout - }), - PING_TYPE: "account-ecosystem", - METRICS_STORE: "account-ecosystem", - _lastSendTime: 0, - // Indicates that the Ecosystem ping is configured and ready to send pings. - _initialized: false, - // The promise returned by Policy.getEcosystemAnonId() - _promiseEcosystemAnonId: null, - // Sets up _promiseEcosystemAnonId in the hope that it will be resolved by the - // time we need it, and also already resolved when the user logs out. - prepareEcosystemAnonId() { - this._promiseEcosystemAnonId = Policy.getEcosystemAnonId(); - }, - - enabled() { - // Never enabled when not Unified Telemetry (e.g. not enabled on Fennec) - // If not enabled, then it doesn't become enabled until the preferences - // are adjusted and the browser is restarted. - // Not enabled is different to "should I send pings?" - if enabled, then - // observers will still be setup so we are ready to transition from not - // sending pings into sending them. - if ( - !Services.prefs.getBoolPref(TelemetryUtils.Preferences.Unified, false) - ) { - return false; - } - - if ( - !Services.prefs.getBoolPref( - TelemetryUtils.Preferences.EcosystemTelemetryEnabled, - false - ) - ) { - return false; - } - - if ( - !FxAccounts.config.isProductionConfig() && - !Services.prefs.getBoolPref( - TelemetryUtils.Preferences.EcosystemTelemetryAllowForNonProductionFxA, - false - ) - ) { - log.info("Ecosystem telemetry disabled due to FxA non-production user"); - return false; - } - // We are enabled (although may or may not want to send pings.) - return true; - }, - - /** - * In what is an unfortunate level of coupling, FxA has hacks to call this - * function before it sends any account related notifications. This allows us - * to work correctly when logging out by ensuring we have the anonymized - * ecosystem ID by then (as *at* logout time it's too late) - */ - async prepareForFxANotification() { - // Telemetry might not have initialized yet, so make sure we have. - this.startup(); - // We need to ensure the promise fetching the anon ecosystem id has - // resolved (but if we are pref'd off it will remain null.) - if (this._promiseEcosystemAnonId) { - await this._promiseEcosystemAnonId; - } - }, - - /** - * On startup, register all observers. - */ - startup() { - if (!this.enabled() || this._initialized) { - return; - } - log.trace("Starting up."); - - // We "prime" the ecosystem id here - if it's not currently available, it - // will be done in the background, so should be ready by the time we - // actually need it. - this.prepareEcosystemAnonId(); - - this._addObservers(); - - this._initialized = true; - }, - - /** - * Shutdown this ping. - * - * This will send a final ping with the SHUTDOWN reason. - */ - shutdown() { - if (!this._initialized) { - return; - } - log.trace("Shutting down."); - this._submitPing(this.Reason.SHUTDOWN); - - this._removeObservers(); - this._initialized = false; - }, - - _addObservers() { - // FxA login, verification and logout. - Services.obs.addObserver(this, ONLOGIN_NOTIFICATION); - Services.obs.addObserver(this, ONVERIFIED_NOTIFICATION); - Services.obs.addObserver(this, ONLOGOUT_NOTIFICATION); - Services.obs.addObserver(this, ON_PRELOGOUT_NOTIFICATION); - }, - - _removeObservers() { - try { - // removeObserver may throw, which could interrupt shutdown. - Services.obs.removeObserver(this, ONLOGIN_NOTIFICATION); - Services.obs.removeObserver(this, ONVERIFIED_NOTIFICATION); - Services.obs.removeObserver(this, ONLOGOUT_NOTIFICATION); - Services.obs.removeObserver(this, ON_PRELOGOUT_NOTIFICATION); - } catch (ex) {} - }, - - observe(subject, topic, data) { - log.trace(`observe, topic: ${topic}`); - - switch (topic) { - // This is a bit messy - an already verified user will get - // ONLOGIN_NOTIFICATION but *not* ONVERIFIED_NOTIFICATION. However, an - // unverified user can't do the ecosystem dance with the profile server. - // The only way to determine if the user is verified or not is via an - // async method, and this isn't async, so... - // Sadly, we just end up kicking off prepareEcosystemAnonId() twice in - // that scenario, which will typically be rare and is handled by FxA. Note - // also that we are just "priming" the ecosystem id here - if it's not - // currently available, it will be done in the background, so should be - // ready by the time we actually need it. - case ONLOGIN_NOTIFICATION: - case ONVERIFIED_NOTIFICATION: - // If we sent these pings for non-account users and this is a login - // notification, we'd want to submit now, so we have a fresh set of data - // for the user. - // But for now, all we need to do is start the promise to fetch the anon - // ID. - this.prepareEcosystemAnonId(); - break; - - case ONLOGOUT_NOTIFICATION: - // On logout we submit what we have, then switch to the "no anon id" - // state. - // Returns the promise for tests. - return this._submitPing(this.Reason.LOGOUT) - .then(async () => { - // Ensure _promiseEcosystemAnonId() is now going to resolve as null. - this.prepareEcosystemAnonId(); - // Change the ecosystemClientId value on logout, so that if a different user signs in - // we cannot link the two anon_id values together via a shared client_id. - // (We are still confirming approval to perform such linking between accounts, and - // this code can be removed once confirmed). - await Policy.resetEcosystemClientId(); - }) - .catch(e => { - log.error("ONLOGOUT promise chain failed", e); - }); - - case ON_PRELOGOUT_NOTIFICATION: - // We don't need to do anything here - everything was done in startup. - // However, we keep this here so someone doesn't erroneously think the - // notification serves no purposes - it's the `observerPreloads` in - // FxAccounts that matters! - break; - } - return null; - }, - - // Called by TelemetryScheduler.jsm when periodic pings should be sent. - periodicPing() { - log.trace("periodic ping triggered"); - return this._submitPing(this.Reason.PERIODIC); - }, - - /** - * Submit an ecosystem ping. - * - * It will not send a ping if Ecosystem Telemetry is disabled - * the module is not fully initialized or if the ping type is missing. - * - * It will automatically assemble the right payload and clear out Telemetry stores. - * - * @param {String} reason The reason we're sending the ping. One of TelemetryEcosystemPing.Reason. - */ - async _submitPing(reason) { - if (!this.enabled()) { - // It's possible we will end up here if FxA was using the production - // stack at startup but no longer is. - log.trace(`_submitPing was called, but ping is not enabled.`); - return; - } - - if (!this._initialized) { - log.trace(`Not initialized when sending. Bug?`); - return; - } - - log.trace(`_submitPing, reason: ${reason}`); - - let now = Policy.monotonicNow(); - - // Duration in seconds - let duration = Math.round((now - this._lastSendTime) / 1000); - this._lastSendTime = now; - - let payload = await this._payload(reason, duration); - if (!payload) { - // The reason for returning null will already have been logged. - return; - } - - // Never include the client ID. - // We provide our own environment. - const options = { - addClientId: false, - addEnvironment: true, - overrideEnvironment: this._environment(), - usePingSender: reason === this.Reason.SHUTDOWN, - }; - - let id = await Policy.sendPing(this.PING_TYPE, payload, options); - log.info(`submitted ping ${id}`); - }, - - /** - * Assemble payload for a new ping - * - * @param {String} reason The reason we're sending the ping. One of TelemetryEcosystemPing.Reason. - * @param {Number} duration The duration since ping was last send in seconds. - */ - async _payload(reason, duration) { - let ecosystemAnonId = await this._promiseEcosystemAnonId; - if (!ecosystemAnonId) { - // This typically just means no user is logged in, so don't make too - // much noise. - log.info("Unable to determine the ecosystem anon id; skipping this ping"); - return null; - } - - let payload = { - reason, - ecosystemAnonId, - ecosystemClientId: await Policy.getEcosystemClientId(), - duration, - - scalars: Telemetry.getSnapshotForScalars( - this.METRICS_STORE, - /* clear */ true, - /* filter test */ true - ), - keyedScalars: Telemetry.getSnapshotForKeyedScalars( - this.METRICS_STORE, - /* clear */ true, - /* filter test */ true - ), - histograms: Telemetry.getSnapshotForHistograms( - this.METRICS_STORE, - /* clear */ true, - /* filter test */ true - ), - keyedHistograms: Telemetry.getSnapshotForKeyedHistograms( - this.METRICS_STORE, - /* clear */ true, - /* filter test */ true - ), - }; - - return payload; - }, - - /** - * Get the minimal environment to include in the ping - */ - _environment() { - let currentEnv = TelemetryEnvironment.currentEnvironment; - let environment = { - settings: { - locale: currentEnv.settings.locale, - }, - system: { - memoryMB: currentEnv.system.memoryMB, - os: { - name: currentEnv.system.os.name, - version: currentEnv.system.os.version, - locale: currentEnv.system.os.locale, - }, - cpu: { - speedMHz: currentEnv.system.cpu.speedMHz, - }, - }, - profile: {}, // added conditionally - }; - - if (currentEnv.profile.creationDate) { - environment.profile.creationDate = currentEnv.profile.creationDate; - } - - if (currentEnv.profile.firstUseDate) { - environment.profile.firstUseDate = currentEnv.profile.firstUseDate; - } - - return environment; - }, - - testReset() { - this._initialized = false; - this._lastSendTime = 0; - this.startup(); - }, -}; diff --git a/toolkit/components/telemetry/tests/unit/head.js b/toolkit/components/telemetry/tests/unit/head.js index 48c797840c2b..4ddb672d7672 100644 --- a/toolkit/components/telemetry/tests/unit/head.js +++ b/toolkit/components/telemetry/tests/unit/head.js @@ -527,13 +527,6 @@ if (runningInParent) { // Speed up child process accumulations Services.prefs.setIntPref(TelemetryUtils.Preferences.IPCBatchTimeout, 10); - // Make sure ecosystem telemetry is disabled, no matter which build - // Individual tests will enable it when appropriate - Services.prefs.setBoolPref( - TelemetryUtils.Preferences.EcosystemTelemetryEnabled, - false - ); - // Non-unified Telemetry (e.g. Fennec on Android) needs the preference to be set // in order to enable Telemetry. if (Services.prefs.getBoolPref(TelemetryUtils.Preferences.Unified, false)) { diff --git a/toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js b/toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js deleted file mode 100644 index 44741b9cd203..000000000000 --- a/toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js +++ /dev/null @@ -1,430 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ - */ - -"use strict"; - -ChromeUtils.import("resource://gre/modules/TelemetryController.jsm", this); -ChromeUtils.import("resource://gre/modules/TelemetryUtils.jsm", this); -ChromeUtils.import("resource://gre/modules/Preferences.jsm", this); - -XPCOMUtils.defineLazyModuleGetters(this, { - ONLOGIN_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", - ONLOGOUT_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", - ONVERIFIED_NOTIFICATION: "resource://gre/modules/FxAccountsCommon.js", -}); -ChromeUtils.defineModuleGetter( - this, - "EcosystemTelemetry", - "resource://gre/modules/EcosystemTelemetry.jsm" -); - -const TEST_PING_TYPE = "test-ping-type"; - -const RE_VALID_GUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; - -function fakeIdleNotification(topic) { - let scheduler = ChromeUtils.import( - "resource://gre/modules/TelemetryScheduler.jsm", - null - ); - return scheduler.TelemetryScheduler.observe(null, topic, null); -} - -async function promiseNoPing() { - // We check there's not one of our pings pending by sending a test ping, then - // immediately fetching a pending ping and checking it's that test one. - TelemetryController.submitExternalPing(TEST_PING_TYPE, {}, {}); - let ping = await PingServer.promiseNextPing(); - Assert.equal(ping.type, TEST_PING_TYPE, "Should be a test ping."); -} - -function checkPingStructure(ping, reason) { - Assert.equal( - ping.type, - EcosystemTelemetry.PING_TYPE, - "Should be an ecosystem ping." - ); - - Assert.ok(!("clientId" in ping), "Ping must not contain a client ID."); - Assert.ok("environment" in ping, "Ping must contain an environment."); - let environment = ping.environment; - - // Check that the environment is indeed minimal - const ALLOWED_ENVIRONMENT_KEYS = ["settings", "system", "profile"]; - Assert.deepEqual( - ALLOWED_ENVIRONMENT_KEYS, - Object.keys(environment), - "Environment should only contain a limited set of keys." - ); - - // Check that fields of the environment are indeed minimal - Assert.deepEqual( - ["locale"], - Object.keys(environment.settings), - "Settings environment should only contain locale" - ); - Assert.deepEqual( - ["cpu", "memoryMB", "os"], - Object.keys(environment.system).sort(), - "System environment should contain a limited set of keys" - ); - Assert.deepEqual( - ["locale", "name", "version"], - Object.keys(environment.system.os).sort(), - "system.environment.os should contain a limited set of keys" - ); - - // Check the payload for required fields. - let payload = ping.payload; - Assert.equal(payload.reason, reason, "Ping reason must match."); - Assert.ok( - payload.duration >= 0, - "Payload must have a duration greater or equal to 0" - ); - Assert.ok("ecosystemAnonId" in payload, "payload must have ecosystemAnonId"); - Assert.ok( - RE_VALID_GUID.test(payload.ecosystemClientId), - "ecosystemClientId must be a valid GUID" - ); - - Assert.ok("scalars" in payload, "Payload must contain scalars"); - Assert.ok("keyedScalars" in payload, "Payload must contain keyed scalars"); - Assert.ok("histograms" in payload, "Payload must contain histograms"); - Assert.ok( - "keyedHistograms" in payload, - "Payload must contain keyed histograms" - ); -} - -function fakeAnonId(fn) { - const m = ChromeUtils.import( - "resource://gre/modules/EcosystemTelemetry.jsm", - null - ); - let oldFn = m.Policy.getEcosystemAnonId; - m.Policy.getEcosystemAnonId = fn; - return oldFn; -} - -registerCleanupFunction(function() { - PingServer.stop(); -}); - -add_task(async function setup() { - // Trigger a proper telemetry init. - do_get_profile(true); - // Make sure we don't generate unexpected pings due to pref changes. - await setEmptyPrefWatchlist(); - - // Start the local ping server and setup Telemetry to use it during the tests. - PingServer.start(); - Preferences.set( - TelemetryUtils.Preferences.Server, - "http://localhost:" + PingServer.port - ); - TelemetrySend.setServer("http://localhost:" + PingServer.port); - - await TelemetryController.testSetup(); -}); - -// We make absolute sure the Ecosystem ping is never triggered on Fennec/Non-unified Telemetry -add_task( - { - skip_if: () => !gIsAndroid, - }, - async function test_no_ecosystem_ping_on_fennec() { - // Force preference to true, we should have an additional check on Android/Unified Telemetry - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - EcosystemTelemetry.testReset(); - - // This is invoked in regular intervals by the timer. - // Would trigger ping sending. - EcosystemTelemetry.periodicPing(); - await promiseNoPing(); - } -); - -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_disabled_non_fxa_production() { - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - Assert.ok(EcosystemTelemetry.enabled(), "enabled by default"); - Preferences.set("identity.fxaccounts.autoconfig.uri", "http://"); - Assert.ok(!EcosystemTelemetry.enabled(), "disabled if non-prod"); - Preferences.set( - TelemetryUtils.Preferences.EcosystemTelemetryAllowForNonProductionFxA, - true - ); - Assert.ok( - EcosystemTelemetry.enabled(), - "enabled for non-prod but preference override" - ); - Preferences.reset("identity.fxaccounts.autoconfig.uri"); - Preferences.reset( - TelemetryUtils.Preferences.EcosystemTelemetryAllowForNonProductionFxA - ); - } -); - -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_nosending_if_disabled() { - Preferences.set( - TelemetryUtils.Preferences.EcosystemTelemetryEnabled, - false - ); - EcosystemTelemetry.testReset(); - - // This is invoked in regular intervals by the timer. - // Would trigger ping sending. - EcosystemTelemetry.periodicPing(); - await promiseNoPing(); - } -); - -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_no_default_send() { - // No user's logged in, nothing is mocked, so nothing is sent. - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - EcosystemTelemetry.testReset(); - - // This is invoked in regular intervals by the timer. - EcosystemTelemetry.periodicPing(); - - await promiseNoPing(); - } -); - -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_login_workflow() { - // Fake the whole login/logout workflow by triggering the events directly. - - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - EcosystemTelemetry.testReset(); - - let originalAnonId = fakeAnonId(() => null); - let ping; - - // 1. No user, timer invoked - EcosystemTelemetry.periodicPing(); - await promiseNoPing(); - - // 2. User logs in, but we fail to obtain a valid uid. - // No ping will be generated. - fakeAnonId(() => null); - EcosystemTelemetry.observe(null, ONLOGIN_NOTIFICATION, null); - - EcosystemTelemetry.periodicPing(); - await promiseNoPing(); - - // Once we've failed to get the ID, we don't try again until next startup - // or another login-related event - so... - // 3. uid becomes available after verification. - fakeAnonId(() => "test_login_workflow:my.anon.id"); - EcosystemTelemetry.observe(null, ONVERIFIED_NOTIFICATION, null); - print("triggering ping now that we have an anon-id"); - EcosystemTelemetry.periodicPing(); - ping = await PingServer.promiseNextPing(); - checkPingStructure(ping, "periodic"); - Assert.equal( - ping.payload.ecosystemAnonId, - "test_login_workflow:my.anon.id" - ); - const origClientId = ping.payload.ecosystemClientId; - - // 4. User disconnects account, should get an immediate ping. - print("user disconnects"); - // We need to arrange for the new empty anonid before the notification. - fakeAnonId(() => null); - await EcosystemTelemetry.observe(null, ONLOGOUT_NOTIFICATION, null); - ping = await PingServer.promiseNextPing(); - checkPingStructure(ping, "logout"); - Assert.equal( - ping.payload.ecosystemAnonId, - "test_login_workflow:my.anon.id", - "should have been submitted with the old anonid" - ); - Assert.equal( - ping.payload.ecosystemClientId, - origClientId, - "should have been submitted with the old clientid" - ); - Assert.equal( - await EcosystemTelemetry.promiseEcosystemAnonId, - null, - "should resolve to null immediately after logout" - ); - - // 5. No user, timer invoked - print("timer fires after disconnection"); - EcosystemTelemetry.periodicPing(); - await promiseNoPing(); - - // 6. Transition back to logged in, pings should again be sent. - fakeAnonId(() => "test_login_workflow:my.anon.id.2"); - EcosystemTelemetry.observe(null, ONVERIFIED_NOTIFICATION, null); - print("triggering ping now the user has logged back in"); - EcosystemTelemetry.periodicPing(); - ping = await PingServer.promiseNextPing(); - checkPingStructure(ping, "periodic"); - Assert.equal( - ping.payload.ecosystemAnonId, - "test_login_workflow:my.anon.id.2" - ); - Assert.notEqual( - ping.payload.ecosystemClientId, - origClientId, - "should have a different clientid after signing out then back in" - ); - - // Reset policy. - fakeAnonId(originalAnonId); - } -); - -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_shutdown_logged_in() { - // Check shutdown when a user's logged in does the right thing. - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - EcosystemTelemetry.testReset(); - - let originalAnonId = fakeAnonId(() => - Promise.resolve("test_shutdown_logged_in:my.anon.id") - ); - - EcosystemTelemetry.observe(null, ONLOGIN_NOTIFICATION, null); - - // No ping expected yet. - await promiseNoPing(); - - // Shutdown - EcosystemTelemetry.shutdown(); - let ping = await PingServer.promiseNextPing(); - checkPingStructure(ping, "shutdown"); - Assert.equal( - ping.payload.ecosystemAnonId, - "test_shutdown_logged_in:my.anon.id", - "our anon ID is in the ping" - ); - fakeAnonId(originalAnonId); - } -); - -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_shutdown_not_logged_in() { - // Check shutdown when no user is logged in does the right thing. - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - EcosystemTelemetry.testReset(); - - let originalAnonId = fakeAnonId(() => Promise.resolve(null)); - - // No ping expected yet. - await promiseNoPing(); - - // Shutdown - EcosystemTelemetry.shutdown(); - - // Still no ping. - await promiseNoPing(); - fakeAnonId(originalAnonId); - } -); - -// Test that a periodic ping is triggered by the scheduler at midnight -// -// Based on `test_TelemetrySession#test_DailyDueAndIdle`. -add_task( - { - skip_if: () => gIsAndroid, - }, - async function test_periodic_ping() { - await TelemetryStorage.testClearPendingPings(); - PingServer.clearRequests(); - - let receivedPing = null; - // Register a ping handler that will assert when receiving multiple ecosystem pings. - // We can ignore other pings, such as the periodic ping. - PingServer.registerPingHandler(req => { - const ping = decodeRequestPayload(req); - if (ping.type == EcosystemTelemetry.PING_TYPE) { - Assert.ok( - !receivedPing, - "Telemetry must only send one periodic ecosystem ping." - ); - receivedPing = ping; - } - }); - - // Faking scheduler timer has to happen before resetting TelemetryController - // to be effective. - let schedulerTickCallback = null; - let now = new Date(2040, 1, 1, 0, 0, 0); - fakeNow(now); - // Fake scheduler functions to control periodic collection flow in tests. - fakeSchedulerTimer( - callback => (schedulerTickCallback = callback), - () => {} - ); - await TelemetryController.testReset(); - - Preferences.set(TelemetryUtils.Preferences.EcosystemTelemetryEnabled, true); - EcosystemTelemetry.testReset(); - - // Have to arrange for an anon-id to be configured. - let originalAnonId = fakeAnonId(() => "test_periodic_ping:my.anon.id"); - EcosystemTelemetry.observe(null, ONLOGIN_NOTIFICATION, null); - - // As a sanity check we trigger a keyedHistogram and scalar declared as - // being in our ping, just to help ensure that the payload was assembled - // in the correct shape. - let h = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); - h.add("test-key"); - Telemetry.scalarSet("browser.engagement.total_uri_count", 2); - - // Trigger the periodic ecosystem ping. - let firstPeriodicDue = new Date(2040, 1, 2, 0, 0, 0); - fakeNow(firstPeriodicDue); - - // Run a scheduler tick: it should trigger the periodic ping. - Assert.ok(!!schedulerTickCallback); - let tickPromise = schedulerTickCallback(); - - // Send an idle and then an active user notification. - fakeIdleNotification("idle"); - fakeIdleNotification("active"); - - // Wait on the tick promise. - await tickPromise; - - await TelemetrySend.testWaitOnOutgoingPings(); - - // Decode the ping contained in the request and check that's a periodic ping. - Assert.ok(receivedPing, "Telemetry must send one ecosystem periodic ping."); - checkPingStructure(receivedPing, "periodic"); - // And check the content we expect is there. - Assert.ok(receivedPing.payload.keyedHistograms.parent.SEARCH_COUNTS); - Assert.equal( - receivedPing.payload.scalars.parent["browser.engagement.total_uri_count"], - 2 - ); - - fakeAnonId(originalAnonId); - } -); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js b/toolkit/components/telemetry/tests/unit/test_TelemetryController.js index 3ffd8eba544d..c468f5737ddf 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryController.js @@ -265,8 +265,6 @@ add_task(async function test_disableDataUpload() { secondClientId, "The client id must have changed" ); - let secondEcosystemClientId = await ClientID.getEcosystemClientID(); - // Simulate a failure in sending the deletion-request ping by disabling the HTTP server. await PingServer.stop(); @@ -338,15 +336,6 @@ add_task(async function test_disableDataUpload() { ping.clientId, "Deletion must be requested for correct client id" ); - if (AppConstants.MOZ_APP_NAME != "thunderbird") { - // We don't record the old ecosystem client ID on Thunderbird, - // since the FxA and telemetry infrastructure is different there. - Assert.equal( - secondEcosystemClientId, - ping.payload.scalars.parent["deletion.request.ecosystem_client_id"], - "Deletion must be requested for correct ecosystem client ID" - ); - } // 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, diff --git a/toolkit/components/telemetry/tests/unit/test_client_id.js b/toolkit/components/telemetry/tests/unit/test_client_id.js index 38ddb3a83348..93e4aea4805f 100644 --- a/toolkit/components/telemetry/tests/unit/test_client_id.js +++ b/toolkit/components/telemetry/tests/unit/test_client_id.js @@ -11,9 +11,6 @@ const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm"); const PREF_CACHED_CLIENTID = "toolkit.telemetry.cachedClientID"; -const SCALAR_DELETION_REQUEST_ECOSYSTEM_CLIENT_ID = - "deletion.request.ecosystem_client_id"; - var drsPath; const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; @@ -37,33 +34,6 @@ function run_test() { run_next_test(); } -add_task(async function test_ecosystemClientID() { - await ClientID._reset(); - Assert.ok(!ClientID.getCachedEcosystemClientID()); - let ecosystemClientID = await ClientID.getEcosystemClientID(); - Assert.equal(typeof ecosystemClientID, "string"); - Assert.equal(ClientID.getCachedEcosystemClientID(), ecosystemClientID); - - let clientID = await ClientID.getClientID(); - await ClientID._reset(); - await OS.File.writeAtomic( - drsPath, - JSON.stringify({ - clientID, - }), - { - encoding: "utf-8", - tmpPath: drsPath + ".tmp", - } - ); - - let newClientID = await ClientID.getClientID(); - Assert.equal(newClientID, clientID); - - let newEcosystemClientID = await ClientID.getEcosystemClientID(); - Assert.notEqual(newEcosystemClientID, ecosystemClientID); -}); - add_task(async function test_client_id() { const invalidIDs = [ [-1, "setIntPref"], @@ -169,121 +139,27 @@ add_task(async function test_client_id() { } }); -add_task(async function test_setCanaryClientIDs() { +add_task(async function test_setCanaryClientID() { const KNOWN_UUID = "c0ffeec0-ffee-c0ff-eec0-ffeec0ffeec0"; await ClientID._reset(); // We should be able to set a valid UUID - await ClientID.setCanaryClientIDs(); + await ClientID.setCanaryClientID(); let clientID = await ClientID.getClientID(); Assert.equal(KNOWN_UUID, clientID); }); -add_task(async function test_resetEcosystemClientID() { - await ClientID._reset(); - - let firstClientID = await ClientID.getClientID(); - let firstEcosystemClientID = await ClientID.getEcosystemClientID(); - Assert.ok(firstClientID); - Assert.ok(firstEcosystemClientID); - - // We should reset the ecosystem client id, but not the main client id. - await ClientID.resetEcosystemClientID(); - let secondClientID = await ClientID.getClientID(); - let secondEcosystemClientID = await ClientID.getEcosystemClientID(); - Assert.equal(firstClientID, secondClientID); - Assert.notEqual(firstEcosystemClientID, secondEcosystemClientID); - - // The new id should have been persisted to disk. - await ClientID._reset(); - let thirdClientID = await ClientID.getClientID(); - let thirdEcosystemClientID = await ClientID.getEcosystemClientID(); - Assert.equal(thirdClientID, secondClientID); - Assert.equal(thirdEcosystemClientID, secondEcosystemClientID); -}); - -add_task(async function test_removeClientIDs() { - // We should get a valid UUID after reset - await ClientID._reset(); - let firstClientID = await ClientID.getClientID(); - let firstEcosystemClientID = await ClientID.getEcosystemClientID(); - Assert.equal(typeof firstClientID, "string"); - Assert.equal(typeof firstEcosystemClientID, "string"); - Assert.ok(uuidRegex.test(firstClientID)); - Assert.ok(uuidRegex.test(firstEcosystemClientID)); - - await ClientID.removeClientIDs(); - - if ( - AppConstants.platform != "android" && - AppConstants.MOZ_APP_NAME != "thunderbird" - ) { - // We don't record the old ecosystem client ID on Android or Thunderbird, - // since the FxA and telemetry infrastructure is different there. - let prefClientID = Services.prefs.getStringPref(PREF_CACHED_CLIENTID, null); - let scalarsDeletionRequest = Services.telemetry.getSnapshotForScalars( - "deletion-request" - ); - Assert.ok(!prefClientID); - Assert.ok( - !scalarsDeletionRequest.parent?.[ - SCALAR_DELETION_REQUEST_ECOSYSTEM_CLIENT_ID - ] - ); - } - - // When resetting again we should get a new ID - let nextClientID = await ClientID.getClientID(); - let nextEcosystemClientID = await ClientID.getEcosystemClientID(); - Assert.equal(typeof nextClientID, "string"); - Assert.equal(typeof nextEcosystemClientID, "string"); - Assert.ok(uuidRegex.test(nextClientID)); - Assert.ok(uuidRegex.test(nextEcosystemClientID)); - Assert.notEqual( - firstClientID, - nextClientID, - "After reset client ID should be different." - ); - Assert.notEqual( - firstEcosystemClientID, - nextEcosystemClientID, - "After reset ecosystem client ID should be different." - ); - - let cachedID = ClientID.getCachedClientID(); - Assert.equal(nextClientID, cachedID); - - let cachedEcosystemID = ClientID.getCachedEcosystemClientID(); - Assert.equal(nextEcosystemClientID, cachedEcosystemID); - - let prefClientID = Services.prefs.getStringPref(PREF_CACHED_CLIENTID, null); - Assert.equal(nextClientID, prefClientID); - - if ( - AppConstants.platform != "android" && - AppConstants.MOZ_APP_NAME != "thunderbird" - ) { - let scalarsDeletionRequest = Services.telemetry.getSnapshotForScalars( - "deletion-request" - ); - Assert.equal( - nextEcosystemClientID, - scalarsDeletionRequest.parent[SCALAR_DELETION_REQUEST_ECOSYSTEM_CLIENT_ID] - ); - } -}); - add_task(async function test_removeParallelGet() { // We should get a valid UUID after reset - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); let firstClientID = await ClientID.getClientID(); // We should get the same ID twice when requesting it in parallel to a reset. - let promiseRemoveClientIDs = ClientID.removeClientIDs(); + let promiseRemoveClientID = ClientID.removeClientID(); let p = ClientID.getClientID(); let newClientID = await ClientID.getClientID(); - await promiseRemoveClientIDs; + await promiseRemoveClientID; let otherClientID = await p; Assert.notEqual( @@ -306,19 +182,19 @@ add_task( const KNOWN_UUID = "c0ffeec0-ffee-c0ff-eec0-ffeec0ffeec0"; // We should get a valid UUID after reset - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); let firstClientID = await ClientID.getClientID(); Assert.notEqual(KNOWN_UUID, firstClientID, "Client ID should be random."); // Set the canary client ID. - await ClientID.setCanaryClientIDs(); + await ClientID.setCanaryClientID(); Assert.equal( KNOWN_UUID, await ClientID.getClientID(), "Client ID should be known canary." ); - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); let newClientID = await ClientID.getClientID(); Assert.notEqual( KNOWN_UUID, @@ -335,7 +211,7 @@ add_task( "After reset we should have detected a canary client ID" ); - await ClientID.removeClientIDs(); + await ClientID.removeClientID(); let clientID = await ClientID.getClientID(); Assert.notEqual( KNOWN_UUID, diff --git a/toolkit/components/telemetry/tests/unit/xpcshell.ini b/toolkit/components/telemetry/tests/unit/xpcshell.ini index d901212ead19..7f36b4d52123 100644 --- a/toolkit/components/telemetry/tests/unit/xpcshell.ini +++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini @@ -91,8 +91,6 @@ skip-if = (os == "android") || (os == "linux" && bits == 32) [test_TelemetryUtils.js] [test_ThirdPartyModulesPing.js] run-if = nightly_build && (os == 'win') -[test_EcosystemTelemetry.js] -skip-if = appname == "thunderbird" [test_EventPing.js] tags = coverage [test_CoveragePing.js]