From 441e819b1de56c70256241739447e2becf469d19 Mon Sep 17 00:00:00 2001 From: Alessio Placitelli Date: Tue, 5 Jan 2016 02:01:00 +0100 Subject: [PATCH] Bug 1234522 - Remove services/datareporting. r=gfritzsche --- .../browser-data-submission-info-bar.js | 5 +- browser/installer/package-manifest.in | 4 - modules/libpref/greprefs.js | 2 +- services/datareporting/DataReporting.manifest | 16 - .../datareporting/DataReportingService.js | 296 ------ .../datareporting/modules-testing/mocks.jsm | 52 - services/datareporting/moz.build | 23 - services/datareporting/policy.jsm | 927 ------------------ services/datareporting/tests/xpcshell/head.js | 16 - .../tests/xpcshell/test_policy.js | 689 ------------- .../datareporting/tests/xpcshell/xpcshell.ini | 6 - services/docs/datareporting.rst | 28 - services/docs/index.rst | 1 - services/moz.build | 3 - .../telemetry}/datareporting-prefs.js | 2 - toolkit/modules/SessionRecorder.jsm | 5 +- 16 files changed, 9 insertions(+), 2066 deletions(-) delete mode 100644 services/datareporting/DataReporting.manifest delete mode 100644 services/datareporting/DataReportingService.js delete mode 100644 services/datareporting/modules-testing/mocks.jsm delete mode 100644 services/datareporting/moz.build delete mode 100644 services/datareporting/policy.jsm delete mode 100644 services/datareporting/tests/xpcshell/head.js delete mode 100644 services/datareporting/tests/xpcshell/test_policy.js delete mode 100644 services/datareporting/tests/xpcshell/xpcshell.ini delete mode 100644 services/docs/datareporting.rst rename {services/datareporting => toolkit/components/telemetry}/datareporting-prefs.js (85%) diff --git a/browser/base/content/browser-data-submission-info-bar.js b/browser/base/content/browser-data-submission-info-bar.js index 93f79d092d5..cd7cddd9e46 100644 --- a/browser/base/content/browser-data-submission-info-bar.js +++ b/browser/base/content/browser-data-submission-info-bar.js @@ -2,6 +2,9 @@ * 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/. */ +const LOGGER_NAME = "Toolkit.Telemetry"; +const LOGGER_PREFIX = "DataNotificationInfoBar::"; + /** * Represents an info bar that shows a data submission notification. */ @@ -21,7 +24,7 @@ var gDataNotificationInfoBar = { get _log() { let Log = Cu.import("resource://gre/modules/Log.jsm", {}).Log; delete this._log; - return this._log = Log.repository.getLogger("Services.DataReporting.InfoBar"); + return this._log = Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX); }, init: function() { diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 80803fbffe6..265619d7859 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -501,10 +501,6 @@ @RESPATH@/components/nsINIProcessor.js @RESPATH@/components/nsPrompter.manifest @RESPATH@/components/nsPrompter.js -#ifdef MOZ_DATA_REPORTING -@RESPATH@/components/DataReporting.manifest -@RESPATH@/components/DataReportingService.js -#endif #ifdef MOZ_SERVICES_HEALTHREPORT @RESPATH@/components/HealthReportComponents.manifest @RESPATH@/browser/components/SelfSupportService.manifest diff --git a/modules/libpref/greprefs.js b/modules/libpref/greprefs.js index 5f0b68c70d2..e56527cd126 100644 --- a/modules/libpref/greprefs.js +++ b/modules/libpref/greprefs.js @@ -1,7 +1,7 @@ #include ../../netwerk/base/security-prefs.js #include init/all.js #ifdef MOZ_DATA_REPORTING -#include ../../services/datareporting/datareporting-prefs.js +#include ../../toolkit/components/telemetry/datareporting-prefs.js #endif #ifdef MOZ_SERVICES_HEALTHREPORT #if MOZ_WIDGET_TOOLKIT == android diff --git a/services/datareporting/DataReporting.manifest b/services/datareporting/DataReporting.manifest deleted file mode 100644 index 327ac6ca032..00000000000 --- a/services/datareporting/DataReporting.manifest +++ /dev/null @@ -1,16 +0,0 @@ -# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61} -# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384} -# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110} -# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66} -# suite (comm): {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} -# graphene: {d1bfe7d9-c01e-4237-998b-7b5f960a4314} - -# The Data Reporting Service drives collection and submission of metrics -# and other useful data to Mozilla. It drives the display of the data -# submission notification info bar and thus is required by Firefox Health -# Report and Telemetry. - -component {41f6ae36-a79f-4613-9ac3-915e70f83789} DataReportingService.js -contract @mozilla.org/datareporting/service;1 {41f6ae36-a79f-4613-9ac3-915e70f83789} -category app-startup DataReportingService service,@mozilla.org/datareporting/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314} - diff --git a/services/datareporting/DataReportingService.js b/services/datareporting/DataReportingService.js deleted file mode 100644 index dd86a8e48b0..00000000000 --- a/services/datareporting/DataReportingService.js +++ /dev/null @@ -1,296 +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/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/ClientID.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Log", - "resource://gre/modules/Log.jsm"); - -const ROOT_BRANCH = "datareporting."; -const POLICY_BRANCH = ROOT_BRANCH + "policy."; -const HEALTHREPORT_BRANCH = ROOT_BRANCH + "healthreport."; -const HEALTHREPORT_LOGGING_BRANCH = HEALTHREPORT_BRANCH + "logging."; -const DEFAULT_LOAD_DELAY_MSEC = 10 * 1000; -const DEFAULT_LOAD_DELAY_FIRST_RUN_MSEC = 60 * 1000; - -/** - * The Firefox Health Report XPCOM service. - * - * External consumers will be interested in the "reporter" property of this - * service. This property is a `HealthReporter` instance that powers the - * service. The property may be null if the Health Report service is not - * enabled. - * - * EXAMPLE USAGE - * ============= - * - * let reporter = Cc["@mozilla.org/datareporting/service;1"] - * .getService(Ci.nsISupports) - * .wrappedJSObject - * .healthReporter; - * - * if (reporter.haveRemoteData) { - * // ... - * } - * - * IMPLEMENTATION NOTES - * ==================== - * - * In order to not adversely impact application start time, the `HealthReporter` - * instance is not initialized until a few seconds after "final-ui-startup." - * The exact delay is configurable via preferences so it can be adjusted with - * a hotfix extension if the default value is ever problematic. Because of the - * overhead with the initial creation of the database, the first run is delayed - * even more than subsequent runs. This does mean that the first moments of - * browser activity may be lost by FHR. - * - * Shutdown of the `HealthReporter` instance is handled completely within the - * instance (it registers observers on initialization). See the notes on that - * type for more. - */ -this.DataReportingService = function () { - this.wrappedJSObject = this; - - this._quitting = false; - - this._os = Cc["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService); -} - -DataReportingService.prototype = Object.freeze({ - classID: Components.ID("{41f6ae36-a79f-4613-9ac3-915e70f83789}"), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, - Ci.nsISupportsWeakReference]), - - //--------------------------------------------- - // Start of policy listeners. - //--------------------------------------------- - - /** - * Called when policy requests data upload. - */ - onRequestDataUpload: function (request) { - if (!this.healthReporter) { - return; - } - - this.healthReporter.requestDataUpload(request); - }, - - onNotifyDataPolicy: function (request) { - Observers.notify("datareporting:notify-data-policy:request", request); - }, - - onRequestRemoteDelete: function (request) { - if (!this.healthReporter) { - return; - } - - this.healthReporter.deleteRemoteData(request); - }, - - //--------------------------------------------- - // End of policy listeners. - //--------------------------------------------- - - observe: function observe(subject, topic, data) { - switch (topic) { - case "app-startup": - this._os.addObserver(this, "profile-after-change", true); - break; - - case "profile-after-change": - this._os.removeObserver(this, "profile-after-change"); - - try { - this._prefs = new Preferences(HEALTHREPORT_BRANCH); - - // We can't interact with prefs until after the profile is present. - let policyPrefs = new Preferences(POLICY_BRANCH); - this.policy = new DataReportingPolicy(policyPrefs, this._prefs, this); - - this._os.addObserver(this, "sessionstore-windows-restored", true); - } catch (ex) { - Cu.reportError("Exception when initializing data reporting service: " + - Log.exceptionStr(ex)); - } - break; - - case "sessionstore-windows-restored": - this._os.removeObserver(this, "sessionstore-windows-restored"); - this._os.addObserver(this, "quit-application", false); - - let policy = this.policy; - policy.startPolling(); - - // Don't initialize Firefox Health Reporter collection and submission - // service unless it is enabled. - if (!this._prefs.get("service.enabled", true)) { - return; - } - - let haveFirstRun = this._prefs.get("service.firstRun", false); - let delayInterval; - - if (haveFirstRun) { - delayInterval = this._prefs.get("service.loadDelayMsec") || - DEFAULT_LOAD_DELAY_MSEC; - } else { - delayInterval = this._prefs.get("service.loadDelayFirstRunMsec") || - DEFAULT_LOAD_DELAY_FIRST_RUN_MSEC; - } - - // Delay service loading a little more so things have an opportunity - // to cool down first. - this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this.timer.initWithCallback({ - notify: function notify() { - delete this.timer; - - // There could be a race between "quit-application" firing and - // this callback being invoked. We close that door. - if (this._quitting) { - return; - } - - // Side effect: instantiates the reporter instance if not already - // accessed. - // - // The instance installs its own shutdown observers. So, we just - // fire and forget: it will clean itself up. - let reporter = this.healthReporter; - policy.ensureUserNotified(); - }.bind(this), - }, delayInterval, this.timer.TYPE_ONE_SHOT); - - break; - - case "quit-application": - this._os.removeObserver(this, "quit-application"); - this._quitting = true; - - // Shutdown doesn't clear pending timers. So, we need to explicitly - // cancel our health reporter initialization timer or else it will - // attempt initialization after shutdown has commenced. This would - // likely lead to stalls or crashes. - if (this.timer) { - this.timer.cancel(); - } - - if (this.policy) { - this.policy.stopPolling(); - } - break; - } - }, - - /** - * The HealthReporter instance associated with this service. - * - * If the service is disabled, this will return null. - * - * The obtained instance may not be fully initialized. - */ - get healthReporter() { - if (!this._prefs.get("service.enabled", true)) { - return null; - } - - if ("_healthReporter" in this) { - return this._healthReporter; - } - - try { - this._loadHealthReporter(); - } catch (ex) { - this._healthReporter = null; - Cu.reportError("Exception when obtaining health reporter: " + - Log.exceptionStr(ex)); - } - - return this._healthReporter; - }, - - _loadHealthReporter: function () { - // This should never happen. It was added to help trace down bug 924307. - if (!this.policy) { - throw new Error("this.policy not set."); - } - - let ns = {}; - // Lazy import so application startup isn't adversely affected. - - Cu.import("resource://gre/modules/HealthReport.jsm", ns); - - // How many times will we rewrite this code before rolling it up into a - // generic module? See also bug 451283. - const LOGGERS = [ - "Services.DataReporting", - "Services.HealthReport", - "Services.Metrics", - "Services.BagheeraClient", - "Sqlite.Connection.healthreport", - ]; - - let loggingPrefs = new Preferences(HEALTHREPORT_LOGGING_BRANCH); - if (loggingPrefs.get("consoleEnabled", true)) { - let level = loggingPrefs.get("consoleLevel", "Warn"); - let appender = new Log.ConsoleAppender(); - appender.level = Log.Level[level] || Log.Level.Warn; - - for (let name of LOGGERS) { - let logger = Log.repository.getLogger(name); - logger.addAppender(appender); - } - } - - if (loggingPrefs.get("dumpEnabled", false)) { - let level = loggingPrefs.get("dumpLevel", "Debug"); - let appender = new Log.DumpAppender(); - appender.level = Log.Level[level] || Log.Level.Debug; - - for (let name of LOGGERS) { - let logger = Log.repository.getLogger(name); - logger.addAppender(appender); - } - } - - this._healthReporter = new ns.HealthReporter(HEALTHREPORT_BRANCH, this.policy); - - // Wait for initialization to finish so if a shutdown occurs before init - // has finished we don't adversely affect app startup on next run. - this._healthReporter.init().then(function onInit() { - this._prefs.set("service.firstRun", true); - }.bind(this)); - }, - - /** - * This returns a promise resolving to the the stable client ID we use for - * data reporting (FHR & Telemetry). Previously exising FHR client IDs are - * migrated to this. - * - * @return Promise The stable client ID. - */ - getClientID: function() { - return ClientID.getClientID(); - }, -}); - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataReportingService]); - -#define MERGED_COMPARTMENT - -#include ../common/observers.js -; -#include policy.jsm -; - diff --git a/services/datareporting/modules-testing/mocks.jsm b/services/datareporting/modules-testing/mocks.jsm deleted file mode 100644 index 1fba9225112..00000000000 --- a/services/datareporting/modules-testing/mocks.jsm +++ /dev/null @@ -1,52 +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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["MockPolicyListener"]; - -const {utils: Cu} = Components; - -Cu.import("resource://gre/modules/Log.jsm"); - - -this.MockPolicyListener = function MockPolicyListener() { - this._log = Log.repository.getLogger("Services.DataReporting.Testing.MockPolicyListener"); - this._log.level = Log.Level["Debug"]; - - this.requestDataUploadCount = 0; - this.lastDataRequest = null; - - this.requestRemoteDeleteCount = 0; - this.lastRemoteDeleteRequest = null; - - this.notifyUserCount = 0; - this.lastNotifyRequest = null; -} - -MockPolicyListener.prototype = { - onRequestDataUpload: function (request) { - this._log.info("onRequestDataUpload invoked."); - this.requestDataUploadCount++; - this.lastDataRequest = request; - }, - - onRequestRemoteDelete: function (request) { - this._log.info("onRequestRemoteDelete invoked."); - this.requestRemoteDeleteCount++; - this.lastRemoteDeleteRequest = request; - }, - - onNotifyDataPolicy: function (request, rejectMessage=null) { - this._log.info("onNotifyDataPolicy invoked."); - this.notifyUserCount++; - this.lastNotifyRequest = request; - if (rejectMessage) { - request.onUserNotifyFailed(rejectMessage); - } else { - request.onUserNotifyComplete(); - } - }, -}; - diff --git a/services/datareporting/moz.build b/services/datareporting/moz.build deleted file mode 100644 index 2d12bd8a356..00000000000 --- a/services/datareporting/moz.build +++ /dev/null @@ -1,23 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini'] - -EXTRA_COMPONENTS += [ - 'DataReporting.manifest', -] - -EXTRA_PP_COMPONENTS += [ - 'DataReportingService.js', -] - -EXTRA_PP_JS_MODULES.services.datareporting += [ - 'policy.jsm', -] - -TESTING_JS_MODULES.services.datareporting += [ - 'modules-testing/mocks.jsm', -] diff --git a/services/datareporting/policy.jsm b/services/datareporting/policy.jsm deleted file mode 100644 index 37133b6f7f4..00000000000 --- a/services/datareporting/policy.jsm +++ /dev/null @@ -1,927 +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 file is in transition. Most of its content needs to be moved under - * /services/healthreport. - */ - -#ifndef MERGED_COMPARTMENT - -"use strict"; - -this.EXPORTED_SYMBOLS = [ - "DataSubmissionRequest", // For test use only. - "DataReportingPolicy", - "DATAREPORTING_POLICY_VERSION", -]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -#endif - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://services-common/utils.js"); -Cu.import("resource://gre/modules/UpdateUtils.jsm"); - -// The current policy version number. If the version number stored in the prefs -// is smaller than this, data upload will be disabled until the user is re-notified -// about the policy changes. -const DATAREPORTING_POLICY_VERSION = 1; - -const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000; - -// Used as a sanity lower bound for dates stored in prefs. This module was -// implemented in 2012, so any earlier dates indicate an incorrect clock. -const OLDEST_ALLOWED_YEAR = 2012; - -/** - * Represents a request to display data policy. - * - * Receivers of these instances are expected to call one or more of the on* - * functions when events occur. - * - * When one of these requests is received, the first thing a callee should do - * is present notification to the user of the data policy. When the notice - * is displayed to the user, the callee should call `onUserNotifyComplete`. - * - * If for whatever reason the callee could not display a notice, - * it should call `onUserNotifyFailed`. - * - * @param policy - * (DataReportingPolicy) The policy instance this request came from. - * @param deferred - * (deferred) The promise that will be fulfilled when display occurs. - */ -function NotifyPolicyRequest(policy, deferred) { - this.policy = policy; - this.deferred = deferred; -} -NotifyPolicyRequest.prototype = Object.freeze({ - /** - * Called when the user is notified of the policy. - */ - onUserNotifyComplete: function () { - return this.deferred.resolve(); - }, - - /** - * Called when there was an error notifying the user about the policy. - * - * @param error - * (Error) Explains what went wrong. - */ - onUserNotifyFailed: function (error) { - return this.deferred.reject(error); - }, -}); - -/** - * Represents a request to submit data. - * - * Instances of this are created when the policy requests data upload or - * deletion. - * - * Receivers are expected to call one of the provided on* functions to signal - * completion of the request. - * - * Instances of this type should not be instantiated outside of this file. - * Receivers of instances of this type should not attempt to do anything with - * the instance except call one of the on* methods. - */ -this.DataSubmissionRequest = function (promise, expiresDate, isDelete) { - this.promise = promise; - this.expiresDate = expiresDate; - this.isDelete = isDelete; - - this.state = null; - this.reason = null; -} - -this.DataSubmissionRequest.prototype = Object.freeze({ - NO_DATA_AVAILABLE: "no-data-available", - SUBMISSION_SUCCESS: "success", - SUBMISSION_FAILURE_SOFT: "failure-soft", - SUBMISSION_FAILURE_HARD: "failure-hard", - UPLOAD_IN_PROGRESS: "upload-in-progress", - - /** - * No submission was attempted because no data was available. - * - * In the case of upload, this means there is no data to upload (perhaps - * it isn't available yet). In case of remote deletion, it means that there - * is no remote data to delete. - */ - onNoDataAvailable: function onNoDataAvailable() { - this.state = this.NO_DATA_AVAILABLE; - this.promise.resolve(this); - return this.promise.promise; - }, - - /** - * Data submission has completed successfully. - * - * In case of upload, this means the upload completed successfully. In case - * of deletion, the data was deleted successfully. - * - * @param date - * (Date) When data submission occurred. - */ - onSubmissionSuccess: function onSubmissionSuccess(date) { - this.state = this.SUBMISSION_SUCCESS; - this.submissionDate = date; - this.promise.resolve(this); - return this.promise.promise; - }, - - /** - * There was a recoverable failure when submitting data. - * - * Perhaps the server was down. Perhaps the network wasn't available. The - * policy may request submission again after a short delay. - * - * @param reason - * (string) Why the failure occurred. For logging purposes only. - */ - onSubmissionFailureSoft: function onSubmissionFailureSoft(reason=null) { - this.state = this.SUBMISSION_FAILURE_SOFT; - this.reason = reason; - this.promise.resolve(this); - return this.promise.promise; - }, - - /** - * There was an unrecoverable failure when submitting data. - * - * Perhaps the client is misconfigured. Perhaps the server rejected the data. - * Attempts at performing submission again will yield the same result. So, - * the policy should not try again (until the next day). - * - * @param reason - * (string) Why the failure occurred. For logging purposes only. - */ - onSubmissionFailureHard: function onSubmissionFailureHard(reason=null) { - this.state = this.SUBMISSION_FAILURE_HARD; - this.reason = reason; - this.promise.resolve(this); - return this.promise.promise; - }, - - /** - * The request was aborted because an upload was already in progress. - */ - onUploadInProgress: function (reason=null) { - this.state = this.UPLOAD_IN_PROGRESS; - this.reason = reason; - this.promise.resolve(this); - return this.promise.promise; - }, -}); - -/** - * Manages scheduling of Firefox Health Report data submission. - * - * The rules of data submission are as follows: - * - * 1. Do not submit data more than once every 24 hours. - * 2. Try to submit as close to 24 hours apart as possible. - * 3. Do not submit too soon after application startup so as to not negatively - * impact performance at startup. - * 4. Before first ever data submission, the user should be notified about - * data collection practices. - * 5. User should have opportunity to react to this notification before - * data submission. - * 6. If data submission fails, try at most 2 additional times before giving - * up on that day's submission. - * - * The listener passed into the instance must have the following properties - * (which are callbacks that will be invoked at certain key events): - * - * * onRequestDataUpload(request) - Called when the policy is requesting - * data to be submitted. The function is passed a `DataSubmissionRequest`. - * The listener should call one of the special resolving functions on that - * instance (see the documentation for that type). - * - * * onRequestRemoteDelete(request) - Called when the policy is requesting - * deletion of remotely stored data. The function is passed a - * `DataSubmissionRequest`. The listener should call one of the special - * resolving functions on that instance (just like `onRequestDataUpload`). - * - * * onNotifyDataPolicy(request) - Called when the policy is requesting the - * user to be notified that data submission will occur. The function - * receives a `NotifyPolicyRequest` instance. The callee should call one or - * more of the functions on that instance when specific events occur. See - * the documentation for that type for more. - * - * Note that the notification method is abstracted. Different applications - * can have different mechanisms by which they notify the user of data - * submission practices. - * - * @param policyPrefs - * (Preferences) Handle on preferences branch on which state will be - * queried and stored. - * @param healthReportPrefs - * (Preferences) Handle on preferences branch holding Health Report state. - * @param listener - * (object) Object with callbacks that will be invoked at certain key - * events. - */ -this.DataReportingPolicy = function (prefs, healthReportPrefs, listener) { - this._log = Log.repository.getLogger("Services.DataReporting.Policy"); - this._log.level = Log.Level["Debug"]; - - for (let handler of this.REQUIRED_LISTENERS) { - if (!listener[handler]) { - throw new Error("Passed listener does not contain required handler: " + - handler); - } - } - - this._prefs = prefs; - this._healthReportPrefs = healthReportPrefs; - this._listener = listener; - this._userNotifyPromise = null; - - this._migratePrefs(); - - if (!this.firstRunDate.getTime()) { - // If we've never run before, record the current time. - this.firstRunDate = this.now(); - } - - // Install an observer so that we can act on changes from external - // code (such as Android UI). - // Use a function because this is the only place where the Preferences - // abstraction is way less usable than nsIPrefBranch. - // - // Hang on to the observer here so that tests can reach it. - this.uploadEnabledObserver = function onUploadEnabledChanged() { - if (this.pendingDeleteRemoteData || this.healthReportUploadEnabled) { - // Nothing to do: either we're already deleting because the caller - // came through the front door (rHRUE), or they set the flag to true. - return; - } - this._log.info("uploadEnabled pref changed. Scheduling deletion."); - this.deleteRemoteData(); - }.bind(this); - - healthReportPrefs.observe("uploadEnabled", this.uploadEnabledObserver); - - // Ensure we are scheduled to submit. - if (!this.nextDataSubmissionDate.getTime()) { - this.nextDataSubmissionDate = this._futureDate(MILLISECONDS_PER_DAY); - } - - // Record when we last requested for submitted data to be sent. This is - // to avoid having multiple outstanding requests. - this._inProgressSubmissionRequest = null; -}; - -this.DataReportingPolicy.prototype = Object.freeze({ - /** - * How often to poll to see if we need to do something. - * - * The interval needs to be short enough such that short-lived applications - * have an opportunity to submit data. But, it also needs to be long enough - * to not negatively impact performance. - * - * The random bit is to ensure that other systems scheduling around the same - * interval don't all get scheduled together. - */ - POLL_INTERVAL_MSEC: (60 * 1000) + Math.floor(2.5 * 1000 * Math.random()), - - /** - * How long individual data submission requests live before expiring. - * - * Data submission requests have this long to complete before we give up on - * them and try again. - * - * We want this to be short enough that we retry frequently enough but long - * enough to give slow networks and systems time to handle it. - */ - SUBMISSION_REQUEST_EXPIRE_INTERVAL_MSEC: 10 * 60 * 1000, - - /** - * Our backoff schedule in case of submission failure. - * - * This dictates both the number of times we retry a daily submission and - * when to retry after each failure. - * - * Each element represents how long to wait after each recoverable failure. - * After the first failure, we wait the time in element 0 before trying - * again. After the second failure, we wait the time in element 1. Once - * we run out of values in this array, we give up on that day's submission - * and schedule for a day out. - */ - FAILURE_BACKOFF_INTERVALS: [ - 15 * 60 * 1000, - 60 * 60 * 1000, - ], - - REQUIRED_LISTENERS: [ - "onRequestDataUpload", - "onRequestRemoteDelete", - "onNotifyDataPolicy", - ], - - /** - * The first time the health report policy came into existence. - * - * This is used for scheduling of the initial submission. - */ - get firstRunDate() { - return CommonUtils.getDatePref(this._prefs, "firstRunTime", 0, this._log, - OLDEST_ALLOWED_YEAR); - }, - - set firstRunDate(value) { - this._log.debug("Setting first-run date: " + value); - CommonUtils.setDatePref(this._prefs, "firstRunTime", value, - OLDEST_ALLOWED_YEAR); - }, - - get dataSubmissionPolicyNotifiedDate() { - return CommonUtils.getDatePref(this._prefs, - "dataSubmissionPolicyNotifiedTime", 0, - this._log, OLDEST_ALLOWED_YEAR); - }, - - set dataSubmissionPolicyNotifiedDate(value) { - this._log.debug("Setting user notified date: " + value); - CommonUtils.setDatePref(this._prefs, "dataSubmissionPolicyNotifiedTime", - value, OLDEST_ALLOWED_YEAR); - }, - - get dataSubmissionPolicyBypassNotification() { - return this._prefs.get("dataSubmissionPolicyBypassNotification", false); - }, - - set dataSubmissionPolicyBypassNotification(value) { - return this._prefs.set("dataSubmissionPolicyBypassNotification", !!value); - }, - - /** - * Whether submission of data is allowed. - * - * This is the master switch for remote server communication. If it is - * false, we never request upload or deletion. - */ - get dataSubmissionEnabled() { - // Default is true because we are opt-out. - return this._prefs.get("dataSubmissionEnabled", true); - }, - - set dataSubmissionEnabled(value) { - this._prefs.set("dataSubmissionEnabled", !!value); - }, - - /** - * Whether submission of data is allowed for v2. - * - * This is used to gently turn off data submission for FHR v2 in Firefox 42+. - */ - get dataSubmissionEnabledV2() { - // Default is true because we are opt-out. - return this._prefs.get("dataSubmissionEnabled.v2", true); - }, - - get currentPolicyVersion() { - return this._prefs.get("currentPolicyVersion", DATAREPORTING_POLICY_VERSION); - }, - - /** - * The minimum policy version which for dataSubmissionPolicyAccepted to - * to be valid. - */ - get minimumPolicyVersion() { - // First check if the current channel has an ove - let channel = UpdateUtils.getUpdateChannel(false); - let channelPref = this._prefs.get("minimumPolicyVersion.channel-" + channel); - return channelPref !== undefined ? - channelPref : this._prefs.get("minimumPolicyVersion", 1); - }, - - get dataSubmissionPolicyAcceptedVersion() { - return this._prefs.get("dataSubmissionPolicyAcceptedVersion", 0); - }, - - set dataSubmissionPolicyAcceptedVersion(value) { - this._prefs.set("dataSubmissionPolicyAcceptedVersion", value); - }, - - /** - * Checks to see if the user has been notified about data submission - * @return {bool} - */ - get userNotifiedOfCurrentPolicy() { - return this.dataSubmissionPolicyNotifiedDate.getTime() > 0 && - this.dataSubmissionPolicyAcceptedVersion >= this.currentPolicyVersion; - }, - - /** - * When this policy last requested data submission. - * - * This is used mainly for forensics purposes and should have no bearing - * on scheduling or run-time behavior. - */ - get lastDataSubmissionRequestedDate() { - return CommonUtils.getDatePref(this._healthReportPrefs, - "lastDataSubmissionRequestedTime", 0, - this._log, OLDEST_ALLOWED_YEAR); - }, - - set lastDataSubmissionRequestedDate(value) { - CommonUtils.setDatePref(this._healthReportPrefs, - "lastDataSubmissionRequestedTime", - value, OLDEST_ALLOWED_YEAR); - }, - - /** - * When the last data submission actually occurred. - * - * This is used mainly for forensics purposes and should have no bearing on - * actual scheduling. - */ - get lastDataSubmissionSuccessfulDate() { - return CommonUtils.getDatePref(this._healthReportPrefs, - "lastDataSubmissionSuccessfulTime", 0, - this._log, OLDEST_ALLOWED_YEAR); - }, - - set lastDataSubmissionSuccessfulDate(value) { - CommonUtils.setDatePref(this._healthReportPrefs, - "lastDataSubmissionSuccessfulTime", - value, OLDEST_ALLOWED_YEAR); - }, - - /** - * When we last encountered a submission failure. - * - * This is used for forensics purposes and should have no bearing on - * scheduling. - */ - get lastDataSubmissionFailureDate() { - return CommonUtils.getDatePref(this._healthReportPrefs, - "lastDataSubmissionFailureTime", - 0, this._log, OLDEST_ALLOWED_YEAR); - }, - - set lastDataSubmissionFailureDate(value) { - CommonUtils.setDatePref(this._healthReportPrefs, - "lastDataSubmissionFailureTime", - value, OLDEST_ALLOWED_YEAR); - }, - - /** - * When the next data submission is scheduled to occur. - * - * This is maintained internally by this type. External users should not - * mutate this value. - */ - get nextDataSubmissionDate() { - return CommonUtils.getDatePref(this._healthReportPrefs, - "nextDataSubmissionTime", 0, - this._log, OLDEST_ALLOWED_YEAR); - }, - - set nextDataSubmissionDate(value) { - CommonUtils.setDatePref(this._healthReportPrefs, - "nextDataSubmissionTime", value, - OLDEST_ALLOWED_YEAR); - }, - - /** - * The number of submission failures for this day's upload. - * - * This is used to drive backoff and scheduling. - */ - get currentDaySubmissionFailureCount() { - let v = this._healthReportPrefs.get("currentDaySubmissionFailureCount", 0); - - if (!Number.isInteger(v)) { - v = 0; - } - - return v; - }, - - set currentDaySubmissionFailureCount(value) { - if (!Number.isInteger(value)) { - throw new Error("Value must be integer: " + value); - } - - this._healthReportPrefs.set("currentDaySubmissionFailureCount", value); - }, - - /** - * Whether a request to delete remote data is awaiting completion. - * - * If this is true, the policy will request that remote data be deleted. - * Furthermore, no new data will be uploaded (if it's even allowed) until - * the remote deletion is fulfilled. - */ - get pendingDeleteRemoteData() { - return !!this._healthReportPrefs.get("pendingDeleteRemoteData", false); - }, - - set pendingDeleteRemoteData(value) { - this._healthReportPrefs.set("pendingDeleteRemoteData", !!value); - }, - - /** - * Whether upload of Firefox Health Report data is enabled. - */ - get healthReportUploadEnabled() { - return !!this._healthReportPrefs.get("uploadEnabled", true); - }, - - // External callers should update this via `recordHealthReportUploadEnabled` - // to ensure appropriate side-effects are performed. - set healthReportUploadEnabled(value) { - this._healthReportPrefs.set("uploadEnabled", !!value); - }, - - /** - * Whether the FHR upload enabled setting is locked and can't be changed. - */ - get healthReportUploadLocked() { - return this._healthReportPrefs.locked("uploadEnabled"); - }, - - /** - * Record the user's intent for whether FHR should upload data. - * - * This is the preferred way for XUL applications to record a user's - * preference on whether Firefox Health Report should upload data to - * a server. - * - * If upload is disabled through this API, a request for remote data - * deletion is initiated automatically. - * - * If upload is being disabled and this operation is scheduled to - * occur immediately, a promise will be returned. This promise will be - * fulfilled when the deletion attempt finishes. If upload is being - * disabled and a promise is not returned, callers must poll - * `haveRemoteData` on the HealthReporter instance to see if remote - * data has been deleted. - * - * @param flag - * (bool) Whether data submission is enabled or disabled. - * @param reason - * (string) Why this value is being adjusted. For logging - * purposes only. - */ - recordHealthReportUploadEnabled: function (flag, reason="no-reason") { - let result = null; - if (!flag) { - result = this.deleteRemoteData(reason); - } - - this.healthReportUploadEnabled = flag; - return result; - }, - - /** - * Request that remote data be deleted. - * - * This will record an intent that previously uploaded data is to be deleted. - * The policy will eventually issue a request to the listener for data - * deletion. It will keep asking for deletion until the listener acknowledges - * that data has been deleted. - */ - deleteRemoteData: function deleteRemoteData(reason="no-reason") { - this._log.info("Remote data deletion requested: " + reason); - - this.pendingDeleteRemoteData = true; - - // We want delete deletion to occur as soon as possible. Move up any - // pending scheduled data submission and try to trigger. - this.nextDataSubmissionDate = this.now(); - return this.checkStateAndTrigger(); - }, - - /** - * Start background polling for activity. - * - * This will set up a recurring timer that will periodically check if - * activity is warranted. - * - * You typically call this function for each constructed instance. - */ - startPolling: function startPolling() { - this.stopPolling(); - - this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._timer.initWithCallback({ - notify: function notify() { - this.checkStateAndTrigger(); - }.bind(this) - }, this.POLL_INTERVAL_MSEC, this._timer.TYPE_REPEATING_SLACK); - }, - - /** - * Stop background polling for activity. - * - * This should be called when the instance is no longer needed. - */ - stopPolling: function stopPolling() { - if (this._timer) { - this._timer.cancel(); - this._timer = null; - } - }, - - /** - * Abstraction for obtaining current time. - * - * The purpose of this is to facilitate testing. Testing code can monkeypatch - * this on instances instead of modifying the singleton Date object. - */ - now: function now() { - return new Date(); - }, - - /** - * Check state and trigger actions, if necessary. - * - * This is what enforces the submission and notification policy detailed - * above. You can think of this as the driver for health report data - * submission. - * - * Typically this function is called automatically by the background polling. - * But, it can safely be called manually as needed. - */ - checkStateAndTrigger: function checkStateAndTrigger() { - // If the master data submission kill switch is toggled, we have nothing - // to do. We don't notify about data policies because this would have - // no effect. - if (!this.dataSubmissionEnabled || !this.dataSubmissionEnabledV2) { - this._log.debug("Data submission is disabled. Doing nothing."); - return; - } - - let now = this.now(); - let nowT = now.getTime(); - let nextSubmissionDate = this.nextDataSubmissionDate; - - // If the system clock were ever set to a time in the distant future, - // it's possible our next schedule date is far out as well. We know - // we shouldn't schedule for more than a day out, so we reset the next - // scheduled date appropriately. 3 days was chosen arbitrarily. - if (nextSubmissionDate.getTime() >= nowT + 3 * MILLISECONDS_PER_DAY) { - this._log.warn("Next data submission time is far away. Was the system " + - "clock recently readjusted? " + nextSubmissionDate); - - // It shouldn't really matter what we set this to. 1 day in the future - // should be pretty safe. - this._moveScheduleForward24h(); - - // Fall through since we may have other actions. - } - - // Tend to any in progress work. - if (this._processInProgressSubmission()) { - return; - } - - // Requests to delete remote data take priority above everything else. - if (this.pendingDeleteRemoteData) { - if (nowT < nextSubmissionDate.getTime()) { - this._log.debug("Deletion request is scheduled for the future: " + - nextSubmissionDate); - return; - } - - return this._dispatchSubmissionRequest("onRequestRemoteDelete", true); - } - - if (!this.healthReportUploadEnabled) { - this._log.debug("Data upload is disabled. Doing nothing."); - return; - } - - if (!this.ensureUserNotified()) { - this._log.warn("The user has not been notified about the data submission " + - "policy. Not attempting upload."); - return; - } - - // Data submission is allowed to occur. Now comes the scheduling part. - - if (nowT < nextSubmissionDate.getTime()) { - this._log.debug("Next data submission is scheduled in the future: " + - nextSubmissionDate); - return; - } - - return this._dispatchSubmissionRequest("onRequestDataUpload", false); - }, - - /** - * Ensure that the data policy notification has been displayed. - * - * This must be called before data submission. If the policy has not been - * displayed, data submission must not occur. - * - * @return bool Whether the notification has been displayed. - */ - ensureUserNotified: function () { - if (this.userNotifiedOfCurrentPolicy || this.dataSubmissionPolicyBypassNotification) { - return true; - } - - // The user has not been notified yet, but is in the process of being notified. - if (this._userNotifyPromise) { - return false; - } - - let deferred = Promise.defer(); - deferred.promise.then((function onSuccess() { - this._recordDataPolicyNotification(this.now(), this.currentPolicyVersion); - this._userNotifyPromise = null; - }).bind(this), ((error) => { - this._log.warn("Data policy notification presentation failed", error); - this._userNotifyPromise = null; - }).bind(this)); - - this._log.info("Requesting display of data policy."); - let request = new NotifyPolicyRequest(this, deferred); - try { - this._listener.onNotifyDataPolicy(request); - } catch (ex) { - this._log.warn("Exception when calling onNotifyDataPolicy", ex); - } - - this._userNotifyPromise = deferred.promise; - - return false; - }, - - _recordDataPolicyNotification: function (date, version) { - this._log.debug("Recording data policy notification to version " + version + - " on date " + date); - this.dataSubmissionPolicyNotifiedDate = date; - this.dataSubmissionPolicyAcceptedVersion = version; - }, - - _migratePrefs: function () { - // Current prefs are mostly the same than the old ones, except for some deprecated ones. - this._prefs.reset([ - "dataSubmissionPolicyAccepted", - "dataSubmissionPolicyBypassAcceptance", - "dataSubmissionPolicyResponseType", - "dataSubmissionPolicyResponseTime" - ]); - }, - - _processInProgressSubmission: function _processInProgressSubmission() { - if (!this._inProgressSubmissionRequest) { - return false; - } - - let now = this.now().getTime(); - if (this._inProgressSubmissionRequest.expiresDate.getTime() > now) { - this._log.info("Waiting on in-progress submission request to finish."); - return true; - } - - this._log.warn("Old submission request has expired from no activity."); - this._inProgressSubmissionRequest.promise.reject(new Error("Request has expired.")); - this._inProgressSubmissionRequest = null; - this._handleSubmissionFailure(); - - return false; - }, - - _dispatchSubmissionRequest: function _dispatchSubmissionRequest(handler, isDelete) { - let now = this.now(); - - // We're past our scheduled next data submission date, so let's do it! - this.lastDataSubmissionRequestedDate = now; - let deferred = Promise.defer(); - let requestExpiresDate = - this._futureDate(this.SUBMISSION_REQUEST_EXPIRE_INTERVAL_MSEC); - this._inProgressSubmissionRequest = new DataSubmissionRequest(deferred, - requestExpiresDate, - isDelete); - - let onSuccess = function onSuccess(result) { - this._inProgressSubmissionRequest = null; - this._handleSubmissionResult(result); - }.bind(this); - - let onError = function onError(error) { - this._log.error("Error when handling data submission result", error); - this._inProgressSubmissionRequest = null; - this._handleSubmissionFailure(); - }.bind(this); - - let chained = deferred.promise.then(onSuccess, onError); - - this._log.info("Requesting data submission. Will expire at " + - requestExpiresDate); - try { - let promise = this._listener[handler](this._inProgressSubmissionRequest); - chained = chained.then(() => promise, null); - } catch (ex) { - this._log.warn("Exception when calling " + handler, ex); - this._inProgressSubmissionRequest = null; - this._handleSubmissionFailure(); - return; - } - - return chained; - }, - - _handleSubmissionResult: function _handleSubmissionResult(request) { - let state = request.state; - let reason = request.reason || "no reason"; - this._log.info("Got submission request result: " + state); - - if (state == request.SUBMISSION_SUCCESS) { - if (request.isDelete) { - this.pendingDeleteRemoteData = false; - this._log.info("Successful data delete reported."); - } else { - this._log.info("Successful data upload reported."); - } - - this.lastDataSubmissionSuccessfulDate = request.submissionDate; - - let nextSubmissionDate = - new Date(request.submissionDate.getTime() + MILLISECONDS_PER_DAY); - - // Schedule pending deletes immediately. This has potential to overload - // the server. However, the frequency of delete requests across all - // clients should be low, so this shouldn't pose a problem. - if (this.pendingDeleteRemoteData) { - nextSubmissionDate = this.now(); - } - - this.nextDataSubmissionDate = nextSubmissionDate; - this.currentDaySubmissionFailureCount = 0; - return; - } - - if (state == request.NO_DATA_AVAILABLE) { - if (request.isDelete) { - this._log.info("Remote data delete requested but no remote data was stored."); - this.pendingDeleteRemoteData = false; - return; - } - - this._log.info("No data was available to submit. May try later."); - this._handleSubmissionFailure(); - return; - } - - // We don't special case request.isDelete for these failures because it - // likely means there was a server error. - - if (state == request.SUBMISSION_FAILURE_SOFT) { - this._log.warn("Soft error submitting data: " + reason); - this.lastDataSubmissionFailureDate = this.now(); - this._handleSubmissionFailure(); - return; - } - - if (state == request.SUBMISSION_FAILURE_HARD) { - this._log.warn("Hard error submitting data: " + reason); - this.lastDataSubmissionFailureDate = this.now(); - this._moveScheduleForward24h(); - return; - } - - throw new Error("Unknown state on DataSubmissionRequest: " + request.state); - }, - - _handleSubmissionFailure: function _handleSubmissionFailure() { - if (this.currentDaySubmissionFailureCount >= this.FAILURE_BACKOFF_INTERVALS.length) { - this._log.warn("Reached the limit of daily submission attempts. " + - "Rescheduling for tomorrow."); - this._moveScheduleForward24h(); - return false; - } - - let offset = this.FAILURE_BACKOFF_INTERVALS[this.currentDaySubmissionFailureCount]; - this.nextDataSubmissionDate = this._futureDate(offset); - this.currentDaySubmissionFailureCount++; - return true; - }, - - _moveScheduleForward24h: function _moveScheduleForward24h() { - let d = this._futureDate(MILLISECONDS_PER_DAY); - this._log.info("Setting next scheduled data submission for " + d); - - this.nextDataSubmissionDate = d; - this.currentDaySubmissionFailureCount = 0; - }, - - _futureDate: function _futureDate(offset) { - return new Date(this.now().getTime() + offset); - }, -}); - diff --git a/services/datareporting/tests/xpcshell/head.js b/services/datareporting/tests/xpcshell/head.js deleted file mode 100644 index 3e63efaf29c..00000000000 --- a/services/datareporting/tests/xpcshell/head.js +++ /dev/null @@ -1,16 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// We need to initialize the profile or OS.File may not work. See bug 810543. -do_get_profile(); - -(function initTestingInfrastructure() { - let ns = {}; - Components.utils.import("resource://testing-common/services/common/logging.js", - ns); - - ns.initTestLogging(); -}).call(this); - diff --git a/services/datareporting/tests/xpcshell/test_policy.js b/services/datareporting/tests/xpcshell/test_policy.js deleted file mode 100644 index ed0613e4321..00000000000 --- a/services/datareporting/tests/xpcshell/test_policy.js +++ /dev/null @@ -1,689 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -var {utils: Cu} = Components; - -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/services/datareporting/policy.jsm"); -Cu.import("resource://testing-common/services/datareporting/mocks.jsm"); -Cu.import("resource://gre/modules/UpdateUtils.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); - -function getPolicy(name, - aCurrentPolicyVersion = 1, - aMinimumPolicyVersion = 1, - aBranchMinimumVersionOverride) { - let branch = "testing.datareporting." + name; - - // The version prefs should not be removed on reset, so set them in the - // default branch. - let defaultPolicyPrefs = new Preferences({ branch: branch + ".policy." - , defaultBranch: true }); - defaultPolicyPrefs.set("currentPolicyVersion", aCurrentPolicyVersion); - defaultPolicyPrefs.set("minimumPolicyVersion", aMinimumPolicyVersion); - let branchOverridePrefName = "minimumPolicyVersion.channel-" + UpdateUtils.getUpdateChannel(false); - if (aBranchMinimumVersionOverride !== undefined) - defaultPolicyPrefs.set(branchOverridePrefName, aBranchMinimumVersionOverride); - else - defaultPolicyPrefs.reset(branchOverridePrefName); - - let policyPrefs = new Preferences(branch + ".policy."); - let healthReportPrefs = new Preferences(branch + ".healthreport."); - - let listener = new MockPolicyListener(); - let policy = new DataReportingPolicy(policyPrefs, healthReportPrefs, listener); - - return [policy, policyPrefs, healthReportPrefs, listener]; -} - -/** - * Ensure that the notification has been displayed to the user therefore having - * policy.ensureUserNotified() === true, which will allow for a successful - * data upload and afterwards does a call to policy.checkStateAndTrigger() - * @param {Policy} policy - * @return {Promise} - */ -function ensureUserNotifiedAndTrigger(policy) { - return Task.spawn(function* ensureUserNotifiedAndTrigger () { - policy.ensureUserNotified(); - yield policy._listener.lastNotifyRequest.deferred.promise; - do_check_true(policy.userNotifiedOfCurrentPolicy); - policy.checkStateAndTrigger(); - }); -} - -function defineNow(policy, now) { - print("Adjusting fake system clock to " + now); - Object.defineProperty(policy, "now", { - value: function customNow() { - return now; - }, - writable: true, - }); -} - -function run_test() { - run_next_test(); -} - -add_test(function test_constructor() { - let policyPrefs = new Preferences("foo.bar.policy."); - let hrPrefs = new Preferences("foo.bar.healthreport."); - let listener = { - onRequestDataUpload: function() {}, - onRequestRemoteDelete: function() {}, - onNotifyDataPolicy: function() {}, - }; - - let policy = new DataReportingPolicy(policyPrefs, hrPrefs, listener); - do_check_true(Date.now() - policy.firstRunDate.getTime() < 1000); - - let tomorrow = Date.now() + 24 * 60 * 60 * 1000; - do_check_true(tomorrow - policy.nextDataSubmissionDate.getTime() < 1000); - - do_check_eq(policy.dataSubmissionPolicyAcceptedVersion, 0); - do_check_false(policy.userNotifiedOfCurrentPolicy); - - run_next_test(); -}); - -add_test(function test_prefs() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("prefs"); - - let now = new Date(); - let nowT = now.getTime(); - - policy.firstRunDate = now; - do_check_eq(policyPrefs.get("firstRunTime"), nowT); - do_check_eq(policy.firstRunDate.getTime(), nowT); - - policy.dataSubmissionPolicyNotifiedDate = now; - do_check_eq(policyPrefs.get("dataSubmissionPolicyNotifiedTime"), nowT); - do_check_neq(policy.dataSubmissionPolicyNotifiedDate, null); - do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), nowT); - - policy.dataSubmissionEnabled = false; - do_check_false(policyPrefs.get("dataSubmissionEnabled", true)); - do_check_false(policy.dataSubmissionEnabled); - - let new_version = DATAREPORTING_POLICY_VERSION + 1; - policy.dataSubmissionPolicyAcceptedVersion = new_version; - do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"), new_version); - - do_check_false(policy.dataSubmissionPolicyBypassNotification); - policy.dataSubmissionPolicyBypassNotification = true; - do_check_true(policy.dataSubmissionPolicyBypassNotification); - do_check_true(policyPrefs.get("dataSubmissionPolicyBypassNotification")); - - policy.lastDataSubmissionRequestedDate = now; - do_check_eq(hrPrefs.get("lastDataSubmissionRequestedTime"), nowT); - do_check_eq(policy.lastDataSubmissionRequestedDate.getTime(), nowT); - - policy.lastDataSubmissionSuccessfulDate = now; - do_check_eq(hrPrefs.get("lastDataSubmissionSuccessfulTime"), nowT); - do_check_eq(policy.lastDataSubmissionSuccessfulDate.getTime(), nowT); - - policy.lastDataSubmissionFailureDate = now; - do_check_eq(hrPrefs.get("lastDataSubmissionFailureTime"), nowT); - do_check_eq(policy.lastDataSubmissionFailureDate.getTime(), nowT); - - policy.nextDataSubmissionDate = now; - do_check_eq(hrPrefs.get("nextDataSubmissionTime"), nowT); - do_check_eq(policy.nextDataSubmissionDate.getTime(), nowT); - - policy.currentDaySubmissionFailureCount = 2; - do_check_eq(hrPrefs.get("currentDaySubmissionFailureCount", 0), 2); - do_check_eq(policy.currentDaySubmissionFailureCount, 2); - - policy.pendingDeleteRemoteData = true; - do_check_true(hrPrefs.get("pendingDeleteRemoteData")); - do_check_true(policy.pendingDeleteRemoteData); - - policy.healthReportUploadEnabled = false; - do_check_false(hrPrefs.get("uploadEnabled")); - do_check_false(policy.healthReportUploadEnabled); - - do_check_false(policy.healthReportUploadLocked); - hrPrefs.lock("uploadEnabled"); - do_check_true(policy.healthReportUploadLocked); - hrPrefs.unlock("uploadEnabled"); - do_check_false(policy.healthReportUploadLocked); - - run_next_test(); -}); - -add_task(function test_migratePrefs () { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("migratePrefs"); - let outdated_prefs = { - dataSubmissionPolicyAccepted: true, - dataSubmissionPolicyBypassAcceptance: true, - dataSubmissionPolicyResponseType: "something", - dataSubmissionPolicyResponseTime: Date.now() + "", - }; - - // Test removal of old prefs. - for (let name in outdated_prefs) { - policyPrefs.set(name, outdated_prefs[name]); - } - policy._migratePrefs(); - for (let name in outdated_prefs) { - do_check_false(policyPrefs.has(name)); - } -}); - -add_task(function test_userNotifiedOfCurrentPolicy () { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("initial_submission_notification"); - - do_check_false(policy.userNotifiedOfCurrentPolicy, - "The initial state should be unnotified."); - do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), 0); - - policy.dataSubmissionPolicyAcceptedVersion = DATAREPORTING_POLICY_VERSION; - do_check_false(policy.userNotifiedOfCurrentPolicy, - "The default state of the date should have a time of 0 and it should therefore fail"); - do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), 0, - "Updating the accepted version should not set a notified date."); - - policy._recordDataPolicyNotification(new Date(), DATAREPORTING_POLICY_VERSION); - do_check_true(policy.userNotifiedOfCurrentPolicy, - "Using the proper API causes user notification to report as true."); - - // It is assumed that later versions of the policy will incorporate previous - // ones, therefore this should also return true. - policy._recordDataPolicyNotification(new Date(), DATAREPORTING_POLICY_VERSION); - policy.dataSubmissionPolicyAcceptedVersion = DATAREPORTING_POLICY_VERSION + 1; - do_check_true(policy.userNotifiedOfCurrentPolicy, 'A future version of the policy should pass.'); - - policy._recordDataPolicyNotification(new Date(), DATAREPORTING_POLICY_VERSION); - policy.dataSubmissionPolicyAcceptedVersion = DATAREPORTING_POLICY_VERSION - 1; - do_check_false(policy.userNotifiedOfCurrentPolicy, 'A previous version of the policy should fail.'); -}); - -add_task(function* test_notification_displayed () { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_accept_displayed"); - - do_check_eq(listener.requestDataUploadCount, 0); - do_check_eq(listener.notifyUserCount, 0); - do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), 0); - - // Uploads will trigger user notifications as needed. - policy.checkStateAndTrigger(); - do_check_eq(listener.notifyUserCount, 1); - do_check_eq(listener.requestDataUploadCount, 0); - - yield ensureUserNotifiedAndTrigger(policy); - - do_check_eq(listener.notifyUserCount, 1); - do_check_true(policy.dataSubmissionPolicyNotifiedDate.getTime() > 0); - do_check_true(policy.userNotifiedOfCurrentPolicy); -}); - -add_task(function* test_submission_kill_switch() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_kill_switch"); - policy.nextDataSubmissionDate = new Date(Date.now() - 24 * 60 * 60 * 1000); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 0); - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - - defineNow(policy, - new Date(Date.now() + policy.SUBMISSION_REQUEST_EXPIRE_INTERVAL_MSEC + 100)); - policy.dataSubmissionEnabled = false; - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); -}); - -add_task(function* test_upload_kill_switch() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("upload_kill_switch"); - - yield ensureUserNotifiedAndTrigger(policy); - defineNow(policy, policy.nextDataSubmissionDate); - - // So that we don't trigger deletions, which cause uploads to be delayed. - hrPrefs.ignore("uploadEnabled", policy.uploadEnabledObserver); - - policy.healthReportUploadEnabled = false; - yield policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 0); - policy.healthReportUploadEnabled = true; - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); -}); - -add_task(function* test_data_submission_no_data() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_no_data"); - - let now = new Date(policy.nextDataSubmissionDate.getTime() + 1); - defineNow(policy, now); - do_check_eq(listener.requestDataUploadCount, 0); - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - listener.lastDataRequest.onNoDataAvailable(); - - // The next trigger should try again. - defineNow(policy, new Date(now.getTime() + 155 * 60 * 1000)); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 2); - }); - -add_task(function* test_data_submission_submit_failure_hard() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_submit_failure_hard"); - - let nextDataSubmissionDate = policy.nextDataSubmissionDate; - let now = new Date(policy.nextDataSubmissionDate.getTime() + 1); - defineNow(policy, now); - - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - yield listener.lastDataRequest.onSubmissionFailureHard(); - do_check_eq(listener.lastDataRequest.state, - listener.lastDataRequest.SUBMISSION_FAILURE_HARD); - - let expected = new Date(now.getTime() + 24 * 60 * 60 * 1000); - do_check_eq(policy.nextDataSubmissionDate.getTime(), expected.getTime()); - - defineNow(policy, new Date(now.getTime() + 10)); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); -}); - -add_task(function* test_data_submission_submit_try_again() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_failure_soft"); - - let nextDataSubmissionDate = policy.nextDataSubmissionDate; - let now = new Date(policy.nextDataSubmissionDate.getTime()); - defineNow(policy, now); - yield ensureUserNotifiedAndTrigger(policy); - yield listener.lastDataRequest.onSubmissionFailureSoft(); - do_check_eq(policy.nextDataSubmissionDate.getTime(), - nextDataSubmissionDate.getTime() + 15 * 60 * 1000); -}); - -add_task(function* test_submission_daily_scheduling() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_daily_scheduling"); - - let nextDataSubmissionDate = policy.nextDataSubmissionDate; - - // Skip ahead to next submission date. We should get a submission request. - let now = new Date(policy.nextDataSubmissionDate.getTime()); - defineNow(policy, now); - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - do_check_eq(policy.lastDataSubmissionRequestedDate.getTime(), now.getTime()); - - let finishedDate = new Date(now.getTime() + 250); - defineNow(policy, new Date(finishedDate.getTime() + 50)); - yield listener.lastDataRequest.onSubmissionSuccess(finishedDate); - do_check_eq(policy.lastDataSubmissionSuccessfulDate.getTime(), finishedDate.getTime()); - - // Next scheduled submission should be exactly 1 day after the reported - // submission success. - - let nextScheduled = new Date(finishedDate.getTime() + 24 * 60 * 60 * 1000); - do_check_eq(policy.nextDataSubmissionDate.getTime(), nextScheduled.getTime()); - - // Fast forward some arbitrary time. We shouldn't do any work yet. - defineNow(policy, new Date(now.getTime() + 40000)); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); - - defineNow(policy, nextScheduled); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 2); - yield listener.lastDataRequest.onSubmissionSuccess(new Date(nextScheduled.getTime() + 200)); - do_check_eq(policy.nextDataSubmissionDate.getTime(), - new Date(nextScheduled.getTime() + 24 * 60 * 60 * 1000 + 200).getTime()); -}); - -add_task(function* test_submission_far_future_scheduling() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_far_future_scheduling"); - - let now = new Date(Date.now() - 24 * 60 * 60 * 1000); - defineNow(policy, now); - yield ensureUserNotifiedAndTrigger(policy); - - let nextDate = policy._futureDate(3 * 24 * 60 * 60 * 1000 - 1); - policy.nextDataSubmissionDate = nextDate; - policy.checkStateAndTrigger(); - do_check_true(policy.dataSubmissionPolicyAcceptedVersion >= DATAREPORTING_POLICY_VERSION); - do_check_eq(listener.requestDataUploadCount, 0); - do_check_eq(policy.nextDataSubmissionDate.getTime(), nextDate.getTime()); - - policy.nextDataSubmissionDate = new Date(nextDate.getTime() + 1); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 0); - do_check_eq(policy.nextDataSubmissionDate.getTime(), - policy._futureDate(24 * 60 * 60 * 1000).getTime()); -}); - -add_task(function* test_submission_backoff() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_backoff"); - - do_check_eq(policy.FAILURE_BACKOFF_INTERVALS.length, 2); - - - let now = new Date(policy.nextDataSubmissionDate.getTime()); - defineNow(policy, now); - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - do_check_eq(policy.currentDaySubmissionFailureCount, 0); - - now = new Date(now.getTime() + 5000); - defineNow(policy, now); - - // On first soft failure we should back off by scheduled interval. - yield listener.lastDataRequest.onSubmissionFailureSoft(); - do_check_eq(policy.currentDaySubmissionFailureCount, 1); - do_check_eq(policy.nextDataSubmissionDate.getTime(), - new Date(now.getTime() + policy.FAILURE_BACKOFF_INTERVALS[0]).getTime()); - do_check_eq(policy.lastDataSubmissionFailureDate.getTime(), now.getTime()); - - // Should not request submission until scheduled. - now = new Date(policy.nextDataSubmissionDate.getTime() - 1); - defineNow(policy, now); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); - - // 2nd request for submission. - now = new Date(policy.nextDataSubmissionDate.getTime()); - defineNow(policy, now); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 2); - - now = new Date(now.getTime() + 5000); - defineNow(policy, now); - - // On second failure we should back off by more. - yield listener.lastDataRequest.onSubmissionFailureSoft(); - do_check_eq(policy.currentDaySubmissionFailureCount, 2); - do_check_eq(policy.nextDataSubmissionDate.getTime(), - new Date(now.getTime() + policy.FAILURE_BACKOFF_INTERVALS[1]).getTime()); - - now = new Date(policy.nextDataSubmissionDate.getTime()); - defineNow(policy, now); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 3); - - now = new Date(now.getTime() + 5000); - defineNow(policy, now); - - // On 3rd failure we should back off by a whole day. - yield listener.lastDataRequest.onSubmissionFailureSoft(); - do_check_eq(policy.currentDaySubmissionFailureCount, 0); - do_check_eq(policy.nextDataSubmissionDate.getTime(), - new Date(now.getTime() + 24 * 60 * 60 * 1000).getTime()); -}); - -// Ensure that only one submission request can be active at a time. -add_task(function* test_submission_expiring() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_expiring"); - - let nextDataSubmission = policy.nextDataSubmissionDate; - let now = new Date(policy.nextDataSubmissionDate.getTime()); - defineNow(policy, now); - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - defineNow(policy, new Date(now.getTime() + 500)); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); - - defineNow(policy, new Date(policy.now().getTime() + - policy.SUBMISSION_REQUEST_EXPIRE_INTERVAL_MSEC)); - - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 2); -}); - -add_task(function* test_delete_remote_data() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data"); - - do_check_false(policy.pendingDeleteRemoteData); - let nextSubmissionDate = policy.nextDataSubmissionDate; - - let now = new Date(); - defineNow(policy, now); - - policy.deleteRemoteData(); - do_check_true(policy.pendingDeleteRemoteData); - do_check_neq(nextSubmissionDate.getTime(), - policy.nextDataSubmissionDate.getTime()); - do_check_eq(now.getTime(), policy.nextDataSubmissionDate.getTime()); - - do_check_eq(listener.requestRemoteDeleteCount, 1); - do_check_true(listener.lastRemoteDeleteRequest.isDelete); - defineNow(policy, policy._futureDate(1000)); - - yield listener.lastRemoteDeleteRequest.onSubmissionSuccess(policy.now()); - do_check_false(policy.pendingDeleteRemoteData); -}); - -// Ensure that deletion requests take priority over regular data submission. -add_task(function* test_delete_remote_data_priority() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_priority"); - - let now = new Date(); - defineNow(policy, new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000)); - - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - policy._inProgressSubmissionRequest = null; - - policy.deleteRemoteData(); - policy.checkStateAndTrigger(); - - do_check_eq(listener.requestRemoteDeleteCount, 1); - do_check_eq(listener.requestDataUploadCount, 1); -}); - -add_test(function test_delete_remote_data_backoff() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_backoff"); - - let now = new Date(); - defineNow(policy, now); - policy.nextDataSubmissionDate = now; - policy.deleteRemoteData(); - - policy.checkStateAndTrigger(); - do_check_eq(listener.requestRemoteDeleteCount, 1); - defineNow(policy, policy._futureDate(1000)); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 0); - do_check_eq(listener.requestRemoteDeleteCount, 1); - - defineNow(policy, policy._futureDate(500)); - listener.lastRemoteDeleteRequest.onSubmissionFailureSoft(); - defineNow(policy, policy._futureDate(50)); - - policy.checkStateAndTrigger(); - do_check_eq(listener.requestRemoteDeleteCount, 1); - - defineNow(policy, policy._futureDate(policy.FAILURE_BACKOFF_INTERVALS[0] - 50)); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestRemoteDeleteCount, 2); - - run_next_test(); -}); - -// If we request delete while an upload is in progress, delete should be -// scheduled immediately after upload. -add_task(function* test_delete_remote_data_in_progress_upload() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_in_progress_upload"); - - defineNow(policy, policy.nextDataSubmissionDate); - - yield ensureUserNotifiedAndTrigger(policy); - do_check_eq(listener.requestDataUploadCount, 1); - defineNow(policy, policy._futureDate(50 * 1000)); - - // If we request a delete during a pending request, nothing should be done. - policy.deleteRemoteData(); - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); - do_check_eq(listener.requestRemoteDeleteCount, 0); - - // Now wait a little bit and finish the request. - defineNow(policy, policy._futureDate(10 * 1000)); - yield listener.lastDataRequest.onSubmissionSuccess(policy._futureDate(1000)); - defineNow(policy, policy._futureDate(5000)); - - policy.checkStateAndTrigger(); - do_check_eq(listener.requestDataUploadCount, 1); - do_check_eq(listener.requestRemoteDeleteCount, 1); -}); - -add_test(function test_polling() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("polling"); - let intended = 500; - let acceptable = 250; // Because nsITimer doesn't guarantee times. - - // Ensure checkStateAndTrigger is called at a regular interval. - let then = Date.now(); - print("Starting run: " + then); - Object.defineProperty(policy, "POLL_INTERVAL_MSEC", { - value: intended, - }); - let count = 0; - - Object.defineProperty(policy, "checkStateAndTrigger", { - value: function fakeCheckStateAndTrigger() { - let now = Date.now(); - let after = now - then; - count++; - - print("Polled at " + now + " after " + after + "ms, intended " + intended); - do_check_true(after >= acceptable); - DataReportingPolicy.prototype.checkStateAndTrigger.call(policy); - - if (count >= 2) { - policy.stopPolling(); - - do_check_eq(listener.requestDataUploadCount, 0); - - run_next_test(); - } - - // "Specified timer period will be at least the time between when - // processing for last firing the callback completes and when the next - // firing occurs." - // - // That means we should set 'then' at the *end* of our handler, not - // earlier. - then = Date.now(); - } - }); - policy.startPolling(); -}); - -add_task(function* test_record_health_report_upload_enabled() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("record_health_report_upload_enabled"); - - // Preconditions. - do_check_false(policy.pendingDeleteRemoteData); - do_check_true(policy.healthReportUploadEnabled); - do_check_eq(listener.requestRemoteDeleteCount, 0); - - // User intent to disable should immediately result in a pending - // delete request. - policy.recordHealthReportUploadEnabled(false, "testing 1 2 3"); - do_check_false(policy.healthReportUploadEnabled); - do_check_true(policy.pendingDeleteRemoteData); - do_check_eq(listener.requestRemoteDeleteCount, 1); - - // Fulfilling it should make it go away. - yield listener.lastRemoteDeleteRequest.onNoDataAvailable(); - do_check_false(policy.pendingDeleteRemoteData); - - // User intent to enable should get us back to default state. - policy.recordHealthReportUploadEnabled(true, "testing 1 2 3"); - do_check_false(policy.pendingDeleteRemoteData); - do_check_true(policy.healthReportUploadEnabled); -}); - -add_test(function test_pref_change_initiates_deletion() { - let [policy, policyPrefs, hrPrefs, listener] = getPolicy("record_health_report_upload_enabled"); - - // Preconditions. - do_check_false(policy.pendingDeleteRemoteData); - do_check_true(policy.healthReportUploadEnabled); - do_check_eq(listener.requestRemoteDeleteCount, 0); - - // User intent to disable should indirectly result in a pending - // delete request, because the policy is watching for the pref - // to change. - Object.defineProperty(policy, "deleteRemoteData", { - value: function deleteRemoteDataProxy() { - do_check_false(policy.healthReportUploadEnabled); - do_check_false(policy.pendingDeleteRemoteData); // Just called. - - run_next_test(); - }, - }); - - hrPrefs.set("uploadEnabled", false); -}); - -add_task(function* test_policy_version() { - let policy, policyPrefs, hrPrefs, listener, now, firstRunTime; - function createPolicy(shouldBeNotified = false, - currentPolicyVersion = 1, minimumPolicyVersion = 1, - branchMinimumVersionOverride) { - [policy, policyPrefs, hrPrefs, listener] = - getPolicy("policy_version_test", currentPolicyVersion, - minimumPolicyVersion, branchMinimumVersionOverride); - let firstRun = now === undefined; - if (firstRun) { - firstRunTime = policy.firstRunDate.getTime(); - do_check_true(firstRunTime > 0); - now = new Date(policy.firstRunDate.getTime()); - } - else { - // The first-run time should not be reset even after policy-version - // upgrades. - do_check_eq(policy.firstRunDate.getTime(), firstRunTime); - } - defineNow(policy, now); - do_check_eq(policy.userNotifiedOfCurrentPolicy, shouldBeNotified); - } - - function* triggerPolicyCheckAndEnsureNotified(notified = true) { - policy.checkStateAndTrigger(); - do_check_eq(listener.notifyUserCount, Number(notified)); - if (notified) { - policy.ensureUserNotified(); - yield listener.lastNotifyRequest.deferred.promise; - do_check_true(policy.userNotifiedOfCurrentPolicy); - do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"), - policyPrefs.get("currentPolicyVersion")); - } - } - - createPolicy(); - yield triggerPolicyCheckAndEnsureNotified(); - - // We shouldn't be notified again if the current version is still valid; - createPolicy(true); - yield triggerPolicyCheckAndEnsureNotified(false); - - // Just increasing the current version isn't enough. The minimum - // version must be changed. - let currentPolicyVersion = policyPrefs.get("currentPolicyVersion"); - let minimumPolicyVersion = policyPrefs.get("minimumPolicyVersion"); - createPolicy(false, ++currentPolicyVersion, minimumPolicyVersion); - yield triggerPolicyCheckAndEnsureNotified(true); - do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"), currentPolicyVersion); - - // Increase the minimum policy version and check if we're notified. - - createPolicy(true, currentPolicyVersion, ++minimumPolicyVersion); - do_check_true(policyPrefs.has("dataSubmissionPolicyAcceptedVersion")); - yield triggerPolicyCheckAndEnsureNotified(false); - - - // Test increasing the minimum version just on the current channel. - createPolicy(true, currentPolicyVersion, minimumPolicyVersion); - yield triggerPolicyCheckAndEnsureNotified(false); - createPolicy(false, ++currentPolicyVersion, minimumPolicyVersion, minimumPolicyVersion + 1); - yield triggerPolicyCheckAndEnsureNotified(true); -}); diff --git a/services/datareporting/tests/xpcshell/xpcshell.ini b/services/datareporting/tests/xpcshell/xpcshell.ini deleted file mode 100644 index eedf74293b1..00000000000 --- a/services/datareporting/tests/xpcshell/xpcshell.ini +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] -head = head.js -tail = -skip-if = toolkit == 'android' || toolkit == 'gonk' - -[test_policy.js] diff --git a/services/docs/datareporting.rst b/services/docs/datareporting.rst deleted file mode 100644 index 2b174fc7a7f..00000000000 --- a/services/docs/datareporting.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _data_reporting_service: - -====================== -Data Reporting Service -====================== - -``/services/datareporting`` contains files related to an XPCOM service -that collects and reports data within Gecko applications. - -The important files in this directory are: - -DataReportingService.js - An XPCOM service that coordinates collection and reporting of data. - -policy.jsm - A module containing the logic for coordinating and driving collection - and upload of data. - -sessions.jsm - Records Gecko application session history. This is loaded as part of - the XPCOM service because it needs to capture state from very early in - the application lifecycle. Bug 841561 tracks implementing this in C++. - -There is other code in the tree that collects and uploads data. The -original intent of this directory and XPCOM service was to serve as a -focal point for the coordination of all this activity so that it could -all be done consistently and properly. This vision may or may not be fully -realized. diff --git a/services/docs/index.rst b/services/docs/index.rst index b1f53cd4da2..a6e71ab83e8 100644 --- a/services/docs/index.rst +++ b/services/docs/index.rst @@ -14,4 +14,3 @@ the directory remains. :maxdepth: 1 metrics - datareporting diff --git a/services/moz.build b/services/moz.build index 74bfeab6f5a..f83bdcefa94 100644 --- a/services/moz.build +++ b/services/moz.build @@ -18,9 +18,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': if CONFIG['MOZ_SERVICES_HEALTHREPORT']: DIRS += ['healthreport'] - if CONFIG['MOZ_DATA_REPORTING']: - DIRS += ['datareporting'] - if CONFIG['MOZ_SERVICES_METRICS']: DIRS += ['metrics'] diff --git a/services/datareporting/datareporting-prefs.js b/toolkit/components/telemetry/datareporting-prefs.js similarity index 85% rename from services/datareporting/datareporting-prefs.js rename to toolkit/components/telemetry/datareporting-prefs.js index 62418ad7230..706284cd169 100644 --- a/services/datareporting/datareporting-prefs.js +++ b/toolkit/components/telemetry/datareporting-prefs.js @@ -3,8 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pref("datareporting.policy.dataSubmissionEnabled", true); -pref("datareporting.policy.dataSubmissionEnabled.v2", false); -pref("datareporting.policy.firstRunTime", "0"); pref("datareporting.policy.dataSubmissionPolicyNotifiedTime", "0"); pref("datareporting.policy.dataSubmissionPolicyAcceptedVersion", 0); pref("datareporting.policy.dataSubmissionPolicyBypassNotification", false); diff --git a/toolkit/modules/SessionRecorder.jsm b/toolkit/modules/SessionRecorder.jsm index 3a547283b1d..174be08e315 100644 --- a/toolkit/modules/SessionRecorder.jsm +++ b/toolkit/modules/SessionRecorder.jsm @@ -22,6 +22,9 @@ const STARTUP_RETRY_INTERVAL_MS = 5000; // Wait up to 5 minutes for startup measurements before giving up. const MAX_STARTUP_TRIES = 300000 / STARTUP_RETRY_INTERVAL_MS; +const LOGGER_NAME = "Toolkit.Telemetry"; +const LOGGER_PREFIX = "SessionRecorder::"; + /** * Records information about browser sessions. * @@ -64,7 +67,7 @@ this.SessionRecorder = function (branch) { throw new Error("branch argument must end with '.': " + branch); } - this._log = Log.repository.getLogger("Services.DataReporting.SessionRecorder"); + this._log = Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX); this._prefs = new Preferences(branch); this._lastActivityWasInactive = false;