Bug 828829 - Refactor Health Report policy out of services/healthreport; r=rnewman

--HG--
rename : services/healthreport/HealthReportService.js => services/datareporting/DataReportingService.js
rename : services/healthreport/modules-testing/mocks.jsm => services/datareporting/modules-testing/mocks.jsm
rename : services/healthreport/policy.jsm => services/datareporting/policy.jsm
rename : services/healthreport/tests/xpcshell/test_policy.js => services/datareporting/tests/xpcshell/test_policy.js
extra : rebase_source : cf766bc99ff843f2d31f82b1c4be71313fbc65a8
This commit is contained in:
Gregory Szorc 2013-01-11 13:45:22 -08:00
parent cc3187175f
commit a6c8da1aba
24 changed files with 392 additions and 255 deletions

View File

@ -469,9 +469,9 @@
@BINPATH@/components/AitcComponents.manifest
@BINPATH@/components/Aitc.js
#endif
#ifdef MOZ_SERVICES_HEALTHREPORT
@BINPATH@/components/HealthReportComponents.manifest
@BINPATH@/components/HealthReportService.js
#ifdef MOZ_DATA_REPORTING
@BINPATH@/components/DataReporting.manifest
@BINPATH@/components/DataReportingService.js
#endif
#ifdef MOZ_SERVICES_SYNC
@BINPATH@/components/SyncComponents.manifest

View File

@ -899,6 +899,7 @@ xpicleanup@BIN_SUFFIX@
components/GPSDGeolocationProvider.js
components/interfaces.manifest
components/jsconsole-clhandler.js
components/MetricsCollectionService.js
components/NetworkGeolocationProvider.js
components/NotificationsComponents.manifest
components/nsBadCertHandler.js

View File

@ -8719,6 +8719,15 @@ if test "$MOZ_TELEMETRY_REPORTING"; then
fi
fi
dnl If we have any service that uploads data (and requires data submission
dnl policy alert), set MOZ_DATA_REPORTING.
dnl We need SUBST for build system and DEFINE for xul preprocessor.
if test -n "$MOZ_TELEMETRY_REPORTING" || test -n "$MOZ_SERVICES_HEALTHREPORT" || test -n "MOZ_CRASHREPORTER"; then
MOZ_DATA_REPORTING=1
AC_DEFINE(MOZ_DATA_REPORTING)
AC_SUBST(MOZ_DATA_REPORTING)
fi
dnl win32 options
AC_SUBST(MOZ_MAPINFO)
AC_SUBST(MOZ_BROWSE_INFO)

View File

@ -43,6 +43,10 @@ GARBAGE += greprefs.js
# TODO bug 813259 external files should be defined near their location in the source tree.
grepref_files = $(topsrcdir)/netwerk/base/public/security-prefs.js $(srcdir)/init/all.js
ifdef MOZ_DATA_REPORTING
grepref_files += $(topsrcdir)/services/datareporting/datareporting-prefs.js
endif
ifdef MOZ_SERVICES_HEALTHREPORT
grepref_files += $(topsrcdir)/services/healthreport/healthreport-prefs.js
endif

View File

@ -9,9 +9,10 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
PARALLEL_DIRS += common
PARALLEL_DIRS += crypto
PARALLEL_DIRS += \
common \
crypto \
$(NULL)
ifdef MOZ_SERVICES_AITC
PARALLEL_DIRS += aitc
@ -21,6 +22,10 @@ ifdef MOZ_SERVICES_HEALTHREPORT
PARALLEL_DIRS += healthreport
endif
ifdef MOZ_DATA_REPORTING
PARALLEL_DIRS += datareporting
endif
ifdef MOZ_SERVICES_METRICS
PARALLEL_DIRS += metrics
endif

View File

@ -0,0 +1,16 @@
# 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}
# metro browser: {99bceaaa-e3c6-48c1-b981-ef9b46b67d60}
# 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}

View File

@ -6,11 +6,16 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/services/datareporting/policy.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://services-common/observers.js");
Cu.import("resource://services-common/preferences.js");
const BRANCH = "healthreport.";
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;
/**
@ -27,7 +32,7 @@ const DEFAULT_LOAD_DELAY_MSEC = 10 * 1000;
* let reporter = Cc["@mozilla.org/healthreport/service;1"]
* .getService(Ci.nsISupports)
* .wrappedJSObject
* .reporter;
* .healthReporter;
*
* if (reporter.haveRemoteData) {
* // ...
@ -45,36 +50,77 @@ const DEFAULT_LOAD_DELAY_MSEC = 10 * 1000;
* instance (it registers observers on initialization). See the notes on that
* type for more.
*/
this.HealthReportService = function HealthReportService() {
this.DataReportingService = function () {
this.wrappedJSObject = this;
this._prefs = new Preferences(BRANCH);
this._reporter = null;
this._os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
}
HealthReportService.prototype = {
classID: Components.ID("{e354c59b-b252-4040-b6dd-b71864e3e35c}"),
DataReportingService.prototype = Object.freeze({
classID: Components.ID("{41f6ae36-a79f-4613-9ac3-915e70f83789}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
observe: function observe(subject, topic, data) {
// If the background service is disabled, don't do anything.
if (!this._prefs.get("service.enabled", true)) {
//---------------------------------------------
// Start of policy listeners.
//---------------------------------------------
/**
* Called when policy requests data upload.
*/
onRequestDataUpload: function (request) {
if (!this.healthReporter) {
return;
}
let os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
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":
os.addObserver(this, "sessionstore-windows-restored", true);
this._os.addObserver(this, "profile-after-change", true);
break;
case "profile-after-change":
this._os.removeObserver(this, "profile-after-change");
this._os.addObserver(this, "sessionstore-windows-restored", true);
// We can't interact with prefs until after the profile is present.
let policyPrefs = new Preferences(POLICY_BRANCH);
this._prefs = new Preferences(HEALTHREPORT_BRANCH);
this.policy = new DataReportingPolicy(policyPrefs, this._prefs, this);
break;
case "sessionstore-windows-restored":
os.removeObserver(this, "sessionstore-windows-restored");
this._os.removeObserver(this, "sessionstore-windows-restored");
this._os.addObserver(this, "quit-application", false);
this.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 delayInterval = this._prefs.get("service.loadDelayMsec") ||
DEFAULT_LOAD_DELAY_MSEC;
@ -86,12 +132,17 @@ HealthReportService.prototype = {
notify: function notify() {
// Side effect: instantiates the reporter instance if not already
// accessed.
let reporter = this.reporter;
let reporter = this.healthReporter;
delete this.timer;
}.bind(this),
}, delayInterval, this.timer.TYPE_ONE_SHOT);
break;
case "quit-application":
this._os.removeObserver(this, "quit-application");
this.policy.stopPolling();
break;
}
},
@ -102,17 +153,29 @@ HealthReportService.prototype = {
*
* The obtained instance may not be fully initialized.
*/
get reporter() {
get healthReporter() {
if (!this._prefs.get("service.enabled", true)) {
return null;
}
if (this._reporter) {
return this._reporter;
if ("_healthReporter" in this) {
return this._healthReporter;
}
try {
this._loadHealthReporter();
} catch (ex) {
dump("Error loading health reporter: " + ex);
this._healthReporter = null;
}
return this._healthReporter;
},
_loadHealthReporter: function () {
let ns = {};
// Lazy import so application startup isn't adversely affected.
Cu.import("resource://gre/modules/Task.jsm", ns);
Cu.import("resource://gre/modules/services/healthreport/healthreporter.jsm", ns);
Cu.import("resource://services-common/log4moz.js", ns);
@ -120,15 +183,16 @@ HealthReportService.prototype = {
// 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 prefs = new Preferences(BRANCH + "logging.");
if (prefs.get("consoleEnabled", true)) {
let level = prefs.get("consoleLevel", "Warn");
let loggingPrefs = new Preferences(HEALTHREPORT_LOGGING_BRANCH);
if (loggingPrefs.get("consoleEnabled", true)) {
let level = loggingPrefs.get("consoleLevel", "Warn");
let appender = new ns.Log4Moz.ConsoleAppender();
appender.level = ns.Log4Moz.Level[level] || ns.Log4Moz.Level.Warn;
@ -139,13 +203,10 @@ HealthReportService.prototype = {
}
// The reporter initializes in the background.
this._reporter = new ns.HealthReporter(BRANCH);
return this._reporter;
this._healthReporter = new ns.HealthReporter(HEALTHREPORT_BRANCH,
this.policy);
},
};
});
Object.freeze(HealthReportService.prototype);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HealthReportService]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataReportingService]);

View File

@ -0,0 +1,26 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
TEST_DIRS += tests
MODULES_FILES := policy.jsm
MODULES_DEST = $(FINAL_TARGET)/modules/services/datareporting
INSTALL_TARGETS += MODULES
TESTING_JS_MODULES := $(addprefix modules-testing/,mocks.jsm)
TESTING_JS_MODULE_DIR := services/datareporting
EXTRA_COMPONENTS := \
DataReporting.manifest \
DataReportingService.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,12 @@
/* 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/. */
pref("datareporting.policy.dataSubmissionEnabled", true);
pref("datareporting.policy.dataSubmissionPolicyAccepted", false);
pref("datareporting.policy.dataSubmissionPolicyBypassAcceptance", false);
pref("datareporting.policy.dataSubmissionPolicyNotifiedTime", "0");
pref("datareporting.policy.dataSubmissionPolicyResponseType", "");
pref("datareporting.policy.dataSubmissionPolicyResponseTime", "0");
pref("datareporting.policy.firstRunTime", "0");

View File

@ -12,7 +12,7 @@ Cu.import("resource://services-common/log4moz.js");
this.MockPolicyListener = function MockPolicyListener() {
this._log = Log4Moz.repository.getLogger("HealthReport.Testing.MockPolicyListener");
this._log = Log4Moz.repository.getLogger("Services.DataReporting.Testing.MockPolicyListener");
this._log.level = Log4Moz.Level["Debug"];
this.requestDataUploadCount = 0;
@ -44,3 +44,4 @@ MockPolicyListener.prototype = {
this.lastNotifyRequest = request;
},
};

View File

@ -2,11 +2,22 @@
* 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. It was originally conceived to fulfill the
* needs of only Firefox Health Report. It is slowly being morphed into
* fulfilling the needs of all data reporting facilities in Gecko applications.
* As a result, some things feel a bit weird.
*
* DataReportingPolicy is both a driver for data reporting notification
* (a true policy) and the driver for FHR data submission. The latter should
* eventually be split into its own type and module.
*/
"use strict";
this.EXPORTED_SYMBOLS = [
"DataSubmissionRequest", // For test use only.
"HealthReportPolicy",
"DataReportingPolicy",
];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
@ -41,7 +52,7 @@ const OLDEST_ALLOWED_YEAR = 2012;
* signaling explicit user acceptance or rejection of the policy. They do this
* by calling `onUserAccept` or `onUserReject`, respectively. These functions
* are essentially proxies to
* HealthReportPolicy.{recordUserAcceptance,recordUserRejection}.
* DataReportingPolicy.{recordUserAcceptance,recordUserRejection}.
*
* If the user never explicitly accepts or rejects the policy, it will be
* implicitly accepted after a specified duration of time. The notice is
@ -53,7 +64,7 @@ const OLDEST_ALLOWED_YEAR = 2012;
* the exception of the on* functions.
*
* @param policy
* (HealthReportPolicy) The policy instance this request came from.
* (DataReportingPolicy) The policy instance this request came from.
* @param promise
* (deferred) The promise that will be fulfilled when display occurs.
*/
@ -235,15 +246,17 @@ Object.freeze(DataSubmissionRequest.prototype);
* can have different mechanisms by which they notify the user of data
* submission practices.
*
* @param prefs
* @param policyPrefs
* (Preferences) Handle on preferences branch on which state will be
* queried and stored.
* @param healthReportPrefs
* (Preferences) Handle on preferences branch hold Health Report state.
* @param listener
* (object) Object with callbacks that will be invoked at certain key
* events.
*/
this.HealthReportPolicy = function HealthReportPolicy(prefs, listener) {
this._log = Log4Moz.repository.getLogger("Services.HealthReport.Policy");
this.DataReportingPolicy = function (prefs, healthReportPrefs, listener) {
this._log = Log4Moz.repository.getLogger("Services.DataReporting.Policy");
this._log.level = Log4Moz.Level["Debug"];
for (let handler of this.REQUIRED_LISTENERS) {
@ -254,6 +267,7 @@ this.HealthReportPolicy = function HealthReportPolicy(prefs, listener) {
}
this._prefs = prefs;
this._healthReportPrefs = healthReportPrefs;
this._listener = listener;
// If we've never run before, record the current time.
@ -276,7 +290,7 @@ this.HealthReportPolicy = function HealthReportPolicy(prefs, listener) {
this._inProgressSubmissionRequest = null;
}
HealthReportPolicy.prototype = {
DataReportingPolicy.prototype = Object.freeze({
/**
* How long after first run we should notify about data submission.
*/
@ -444,22 +458,6 @@ HealthReportPolicy.prototype = {
this._prefs.set("dataSubmissionEnabled", !!value);
},
/**
* Whether upload of data is allowed.
*
* This is a kill switch for upload. It is meant to reflect a system or
* deployment policy decision. User intent should be reflected in the
* "dataSubmissionPolicy" prefs.
*/
get dataUploadEnabled() {
// Default is true because we are opt-out.
return this._prefs.get("dataUploadEnabled", true);
},
set dataUploadEnabled(value) {
this._prefs.set("dataUploadEnabled", !!value);
},
/**
* Whether the user has accepted that data submission can occur.
*
@ -474,13 +472,17 @@ HealthReportPolicy.prototype = {
this._prefs.set("dataSubmissionPolicyAccepted", !!value);
},
set dataSubmissionPolicyAcceptedVersion(value) {
this._prefs.set("dataSubmissionPolicyAcceptedVersion", value);
},
/**
* The state of user notification of the data policy.
*
* This must be HealthReportPolicy.STATE_NOTIFY_COMPLETE before data
* This must be DataReportingPolicy.STATE_NOTIFY_COMPLETE before data
* submission can occur.
*
* @return HealthReportPolicy.STATE_NOTIFY_* constant.
* @return DataReportingPolicy.STATE_NOTIFY_* constant.
*/
get notifyState() {
if (this.dataSubmissionPolicyResponseDate.getTime()) {
@ -505,13 +507,14 @@ HealthReportPolicy.prototype = {
* on scheduling or run-time behavior.
*/
get lastDataSubmissionRequestedDate() {
return CommonUtils.getDatePref(this._prefs,
return CommonUtils.getDatePref(this._healthReportPrefs,
"lastDataSubmissionRequestedTime", 0,
this._log, OLDEST_ALLOWED_YEAR);
},
set lastDataSubmissionRequestedDate(value) {
CommonUtils.setDatePref(this._prefs, "lastDataSubmissionRequestedTime",
CommonUtils.setDatePref(this._healthReportPrefs,
"lastDataSubmissionRequestedTime",
value, OLDEST_ALLOWED_YEAR);
},
@ -522,13 +525,14 @@ HealthReportPolicy.prototype = {
* actual scheduling.
*/
get lastDataSubmissionSuccessfulDate() {
return CommonUtils.getDatePref(this._prefs,
return CommonUtils.getDatePref(this._healthReportPrefs,
"lastDataSubmissionSuccessfulTime", 0,
this._log, OLDEST_ALLOWED_YEAR);
},
set lastDataSubmissionSuccessfulDate(value) {
CommonUtils.setDatePref(this._prefs, "lastDataSubmissionSuccessfulTime",
CommonUtils.setDatePref(this._healthReportPrefs,
"lastDataSubmissionSuccessfulTime",
value, OLDEST_ALLOWED_YEAR);
},
@ -539,13 +543,15 @@ HealthReportPolicy.prototype = {
* scheduling.
*/
get lastDataSubmissionFailureDate() {
return CommonUtils.getDatePref(this._prefs, "lastDataSubmissionFailureTime",
return CommonUtils.getDatePref(this._healthReportPrefs,
"lastDataSubmissionFailureTime",
0, this._log, OLDEST_ALLOWED_YEAR);
},
set lastDataSubmissionFailureDate(value) {
CommonUtils.setDatePref(this._prefs, "lastDataSubmissionFailureTime", value,
OLDEST_ALLOWED_YEAR);
CommonUtils.setDatePref(this._healthReportPrefs,
"lastDataSubmissionFailureTime",
value, OLDEST_ALLOWED_YEAR);
},
/**
@ -555,12 +561,14 @@ HealthReportPolicy.prototype = {
* mutate this value.
*/
get nextDataSubmissionDate() {
return CommonUtils.getDatePref(this._prefs, "nextDataSubmissionTime", 0,
return CommonUtils.getDatePref(this._healthReportPrefs,
"nextDataSubmissionTime", 0,
this._log, OLDEST_ALLOWED_YEAR);
},
set nextDataSubmissionDate(value) {
CommonUtils.setDatePref(this._prefs, "nextDataSubmissionTime", value,
CommonUtils.setDatePref(this._healthReportPrefs,
"nextDataSubmissionTime", value,
OLDEST_ALLOWED_YEAR);
},
@ -570,7 +578,7 @@ HealthReportPolicy.prototype = {
* This is used to drive backoff and scheduling.
*/
get currentDaySubmissionFailureCount() {
let v = this._prefs.get("currentDaySubmissionFailureCount", 0);
let v = this._healthReportPrefs.get("currentDaySubmissionFailureCount", 0);
if (!Number.isInteger(v)) {
v = 0;
@ -584,7 +592,7 @@ HealthReportPolicy.prototype = {
throw new Error("Value must be integer: " + value);
}
this._prefs.set("currentDaySubmissionFailureCount", value);
this._healthReportPrefs.set("currentDaySubmissionFailureCount", value);
},
/**
@ -595,11 +603,22 @@ HealthReportPolicy.prototype = {
* the remote deletion is fulfilled.
*/
get pendingDeleteRemoteData() {
return !!this._prefs.get("pendingDeleteRemoteData", false);
return !!this._healthReportPrefs.get("pendingDeleteRemoteData", false);
},
set pendingDeleteRemoteData(value) {
this._prefs.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);
},
set healthReportUploadEnabled(value) {
this._healthReportPrefs.set("uploadEnabled", !!value);
},
/**
@ -620,6 +639,7 @@ HealthReportPolicy.prototype = {
this.dataSubmissionPolicyResponseDate = this.now();
this.dataSubmissionPolicyResponseType = "accepted-" + reason;
this.dataSubmissionPolicyAccepted = true;
this.dataSubmissionPolicyAcceptedVersion = 1;
},
/**
@ -753,7 +773,7 @@ HealthReportPolicy.prototype = {
return this._dispatchSubmissionRequest("onRequestRemoteDelete", true);
}
if (!this.dataUploadEnabled) {
if (!this.healthReportUploadEnabled) {
this._log.debug("Data upload is disabled. Doing nothing.");
return;
}
@ -1003,7 +1023,5 @@ HealthReportPolicy.prototype = {
_futureDate: function _futureDate(offset) {
return new Date(this.now().getTime() + offset);
},
};
Object.freeze(HealthReportPolicy.prototype);
});

View File

@ -0,0 +1,16 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
XPCSHELL_TESTS = xpcshell
include $(topsrcdir)/config/rules.mk

View File

@ -6,15 +6,19 @@
const {utils: Cu} = Components;
Cu.import("resource://services-common/preferences.js");
Cu.import("resource://gre/modules/services/healthreport/policy.jsm");
Cu.import("resource://testing-common/services/healthreport/mocks.jsm");
Cu.import("resource://gre/modules/services/datareporting/policy.jsm");
Cu.import("resource://testing-common/services/datareporting/mocks.jsm");
function getPolicy(name) {
let prefs = new Preferences(name);
let listener = new MockPolicyListener();
let branch = "testing.datareporting." + name;
let policyPrefs = new Preferences(branch + ".policy.");
let healthReportPrefs = new Preferences(branch + ".healthreport.");
return [new HealthReportPolicy(prefs, listener), prefs, listener];
let listener = new MockPolicyListener();
let policy = new DataReportingPolicy(policyPrefs, healthReportPrefs, listener);
return [policy, policyPrefs, healthReportPrefs, listener];
}
function defineNow(policy, now) {
@ -32,14 +36,15 @@ function run_test() {
}
add_test(function test_constructor() {
let prefs = new Preferences("foo.bar");
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 HealthReportPolicy(prefs, listener);
let policy = new DataReportingPolicy(policyPrefs, hrPrefs, listener);
do_check_true(Date.now() - policy.firstRunDate.getTime() < 1000);
let tomorrow = Date.now() + 24 * 60 * 60 * 1000;
@ -51,68 +56,75 @@ add_test(function test_constructor() {
});
add_test(function test_prefs() {
let [policy, prefs, listener] = getPolicy("prefs");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("prefs");
let now = new Date();
let nowT = now.getTime();
policy.firstRunDate = now;
do_check_eq(prefs.get("firstRunTime"), nowT);
do_check_eq(policyPrefs.get("firstRunTime"), nowT);
do_check_eq(policy.firstRunDate.getTime(), nowT);
policy.dataSubmissionPolicyNotifiedDate= now;
do_check_eq(prefs.get("dataSubmissionPolicyNotifiedTime"), nowT);
do_check_eq(policyPrefs.get("dataSubmissionPolicyNotifiedTime"), nowT);
do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), nowT);
policy.dataSubmissionPolicyResponseDate = now;
do_check_eq(prefs.get("dataSubmissionPolicyResponseTime"), nowT);
do_check_eq(policyPrefs.get("dataSubmissionPolicyResponseTime"), nowT);
do_check_eq(policy.dataSubmissionPolicyResponseDate.getTime(), nowT);
policy.dataSubmissionPolicyResponseType = "type-1";
do_check_eq(prefs.get("dataSubmissionPolicyResponseType"), "type-1");
do_check_eq(policyPrefs.get("dataSubmissionPolicyResponseType"), "type-1");
do_check_eq(policy.dataSubmissionPolicyResponseType, "type-1");
policy.dataSubmissionEnabled = false;
do_check_false(prefs.get("dataSubmissionEnabled", true));
do_check_false(policyPrefs.get("dataSubmissionEnabled", true));
do_check_false(policy.dataSubmissionEnabled);
policy.dataSubmissionPolicyAccepted = false;
do_check_false(prefs.get("dataSubmissionPolicyAccepted", true));
do_check_false(policyPrefs.get("dataSubmissionPolicyAccepted", true));
do_check_false(policy.dataSubmissionPolicyAccepted);
policy.dataSubmissionPolicyAcceptedVersion = 2;
do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"), 2);
do_check_false(policy.dataSubmissionPolicyBypassAcceptance);
prefs.set("dataSubmissionPolicyBypassAcceptance", true);
policyPrefs.set("dataSubmissionPolicyBypassAcceptance", true);
do_check_true(policy.dataSubmissionPolicyBypassAcceptance);
policy.lastDataSubmissionRequestedDate = now;
do_check_eq(prefs.get("lastDataSubmissionRequestedTime"), nowT);
do_check_eq(hrPrefs.get("lastDataSubmissionRequestedTime"), nowT);
do_check_eq(policy.lastDataSubmissionRequestedDate.getTime(), nowT);
policy.lastDataSubmissionSuccessfulDate = now;
do_check_eq(prefs.get("lastDataSubmissionSuccessfulTime"), nowT);
do_check_eq(hrPrefs.get("lastDataSubmissionSuccessfulTime"), nowT);
do_check_eq(policy.lastDataSubmissionSuccessfulDate.getTime(), nowT);
policy.lastDataSubmissionFailureDate = now;
do_check_eq(prefs.get("lastDataSubmissionFailureTime"), nowT);
do_check_eq(hrPrefs.get("lastDataSubmissionFailureTime"), nowT);
do_check_eq(policy.lastDataSubmissionFailureDate.getTime(), nowT);
policy.nextDataSubmissionDate = now;
do_check_eq(prefs.get("nextDataSubmissionTime"), nowT);
do_check_eq(hrPrefs.get("nextDataSubmissionTime"), nowT);
do_check_eq(policy.nextDataSubmissionDate.getTime(), nowT);
policy.currentDaySubmissionFailureCount = 2;
do_check_eq(prefs.get("currentDaySubmissionFailureCount", 0), 2);
do_check_eq(hrPrefs.get("currentDaySubmissionFailureCount", 0), 2);
do_check_eq(policy.currentDaySubmissionFailureCount, 2);
policy.pendingDeleteRemoteData = true;
do_check_true(prefs.get("pendingDeleteRemoteData"));
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);
run_next_test();
});
add_test(function test_notify_state_prefs() {
let [policy, prefs, listener] = getPolicy("notify_state_prefs");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notify_state_prefs");
do_check_eq(policy.notifyState, policy.STATE_NOTIFY_UNNOTIFIED);
@ -127,7 +139,7 @@ add_test(function test_notify_state_prefs() {
});
add_test(function test_initial_submission_notification() {
let [policy, prefs, listener] = getPolicy("initial_submission_notification");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("initial_submission_notification");
do_check_eq(listener.notifyUserCount, 0);
@ -159,9 +171,9 @@ add_test(function test_initial_submission_notification() {
});
add_test(function test_bypass_acceptance() {
let [policy, prefs, listener] = getPolicy("bypass_acceptance");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("bypass_acceptance");
prefs.set("dataSubmissionPolicyBypassAcceptance", true);
policyPrefs.set("dataSubmissionPolicyBypassAcceptance", true);
do_check_false(policy.dataSubmissionPolicyAccepted);
do_check_true(policy.dataSubmissionPolicyBypassAcceptance);
defineNow(policy, new Date(policy.nextDataSubmissionDate.getTime()));
@ -172,7 +184,7 @@ add_test(function test_bypass_acceptance() {
});
add_test(function test_notification_implicit_acceptance() {
let [policy, prefs, listener] = getPolicy("notification_implicit_acceptance");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_implicit_acceptance");
let now = new Date(policy.nextDataSubmissionDate.getTime() -
policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
@ -202,7 +214,7 @@ add_test(function test_notification_implicit_acceptance() {
add_test(function test_notification_rejected() {
// User notification failed. We should not record it as being presented.
let [policy, prefs, listener] = getPolicy("notification_failed");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_failed");
let now = new Date(policy.nextDataSubmissionDate.getTime() -
policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
@ -218,7 +230,7 @@ add_test(function test_notification_rejected() {
});
add_test(function test_notification_accepted() {
let [policy, prefs, listener] = getPolicy("notification_accepted");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_accepted");
let now = new Date(policy.nextDataSubmissionDate.getTime() -
policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
@ -238,7 +250,7 @@ add_test(function test_notification_accepted() {
});
add_test(function test_notification_rejected() {
let [policy, prefs, listener] = getPolicy("notification_rejected");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_rejected");
let now = new Date(policy.nextDataSubmissionDate.getTime() -
policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
@ -261,11 +273,12 @@ add_test(function test_notification_rejected() {
});
add_test(function test_submission_kill_switch() {
let [policy, prefs, listener] = getPolicy("submission_kill_switch");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_kill_switch");
policy.firstRunDate = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
policy.nextDataSubmissionDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
policy.recordUserAcceptance("accept-old-ack");
do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"), 1);
policy.checkStateAndTrigger();
do_check_eq(listener.requestDataUploadCount, 1);
@ -279,16 +292,16 @@ add_test(function test_submission_kill_switch() {
});
add_test(function test_upload_kill_switch() {
let [policy, prefs, listener] = getPolicy("upload_kill_switch");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("upload_kill_switch");
defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
policy.recordUserAcceptance();
defineNow(policy, policy.nextDataSubmissionDate);
policy.dataUploadEnabled = false;
policy.healthReportUploadEnabled = false;
policy.checkStateAndTrigger();
do_check_eq(listener.requestDataUploadCount, 0);
policy.dataUploadEnabled = true;
policy.healthReportUploadEnabled = true;
policy.checkStateAndTrigger();
do_check_eq(listener.requestDataUploadCount, 1);
@ -296,7 +309,7 @@ add_test(function test_upload_kill_switch() {
});
add_test(function test_data_submission_no_data() {
let [policy, prefs, listener] = getPolicy("data_submission_no_data");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_no_data");
policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
policy.dataSubmissionPolicyAccepted = true;
@ -316,7 +329,7 @@ add_test(function test_data_submission_no_data() {
});
add_test(function test_data_submission_submit_failure_hard() {
let [policy, prefs, listener] = getPolicy("data_submission_submit_failure_hard");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_submit_failure_hard");
policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
policy.dataSubmissionPolicyAccepted = true;
@ -341,7 +354,7 @@ add_test(function test_data_submission_submit_failure_hard() {
});
add_test(function test_data_submission_submit_try_again() {
let [policy, prefs, listener] = getPolicy("data_submission_failure_soft");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_failure_soft");
policy.recordUserAcceptance();
let nextDataSubmissionDate = policy.nextDataSubmissionDate;
@ -356,7 +369,7 @@ add_test(function test_data_submission_submit_try_again() {
});
add_test(function test_submission_daily_scheduling() {
let [policy, prefs, listener] = getPolicy("submission_daily_scheduling");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_daily_scheduling");
policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
policy.dataSubmissionPolicyAccepted = true;
@ -396,7 +409,7 @@ add_test(function test_submission_daily_scheduling() {
});
add_test(function test_submission_far_future_scheduling() {
let [policy, prefs, listener] = getPolicy("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);
@ -420,7 +433,7 @@ add_test(function test_submission_far_future_scheduling() {
});
add_test(function test_submission_backoff() {
let [policy, prefs, listener] = getPolicy("submission_backoff");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_backoff");
do_check_eq(policy.FAILURE_BACKOFF_INTERVALS.length, 2);
@ -483,7 +496,7 @@ add_test(function test_submission_backoff() {
// Ensure that only one submission request can be active at a time.
add_test(function test_submission_expiring() {
let [policy, prefs, listener] = getPolicy("submission_expiring");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_expiring");
policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
policy.dataSubmissionPolicyAccepted = true;
@ -506,7 +519,7 @@ add_test(function test_submission_expiring() {
});
add_test(function test_delete_remote_data() {
let [policy, prefs, listener] = getPolicy("delete_remote_data");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data");
do_check_false(policy.pendingDeleteRemoteData);
let nextSubmissionDate = policy.nextDataSubmissionDate;
@ -532,7 +545,7 @@ add_test(function test_delete_remote_data() {
// Ensure that deletion requests take priority over regular data submission.
add_test(function test_delete_remote_data_priority() {
let [policy, prefs, listener] = getPolicy("delete_remote_data_priority");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_priority");
let now = new Date();
defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
@ -553,7 +566,7 @@ add_test(function test_delete_remote_data_priority() {
});
add_test(function test_delete_remote_data_backoff() {
let [policy, prefs, listener] = getPolicy("delete_remote_data_backoff");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_backoff");
let now = new Date();
defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
@ -586,7 +599,7 @@ add_test(function test_delete_remote_data_backoff() {
// If we request delete while an upload is in progress, delete should be
// scheduled immediately after upload.
add_test(function test_delete_remote_data_in_progress_upload() {
let [policy, prefs, listener] = getPolicy("delete_remote_data_in_progress_upload");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_in_progress_upload");
let now = new Date();
defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
@ -616,7 +629,7 @@ add_test(function test_delete_remote_data_in_progress_upload() {
});
add_test(function test_polling() {
let [policy, prefs, listener] = getPolicy("polling");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("polling");
// Ensure checkStateAndTrigger is called at a regular interval.
let now = new Date();
@ -632,7 +645,7 @@ add_test(function test_polling() {
do_check_true(now2.getTime() - now.getTime() >= 500);
now = now2;
HealthReportPolicy.prototype.checkStateAndTrigger.call(policy);
DataReportingPolicy.prototype.checkStateAndTrigger.call(policy);
if (count >= 2) {
policy.stopPolling();
@ -652,7 +665,7 @@ add_test(function test_polling() {
// This is probably covered by other tests. But, it's best to have explicit
// coverage from a higher-level.
add_test(function test_polling_implicit_acceptance() {
let [policy, prefs, listener] = getPolicy("polling_implicit_acceptance");
let [policy, policyPrefs, hrPrefs, listener] = getPolicy("polling_implicit_acceptance");
// Redefine intervals with shorter, test-friendly values.
Object.defineProperty(policy, "POLL_INTERVAL_MSEC", {
@ -670,7 +683,7 @@ add_test(function test_polling_implicit_acceptance() {
print("checkStateAndTrigger count: " + count);
// Account for some slack.
HealthReportPolicy.prototype.checkStateAndTrigger.call(policy);
DataReportingPolicy.prototype.checkStateAndTrigger.call(policy);
// What should happen on different invocations:
//

View File

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_policy.js]

View File

@ -1,14 +1,4 @@
# 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}
# metro browser: {99bceaaa-e3c6-48c1-b981-ef9b46b67d60}
component {e354c59b-b252-4040-b6dd-b71864e3e35c} HealthReportService.js
contract @mozilla.org/healthreport/service;1 {e354c59b-b252-4040-b6dd-b71864e3e35c}
category app-startup HealthReportService service,@mozilla.org/healthreport/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}
# Register Firefox Health Report providers.
category healthreport-js-provider AddonsProvider resource://gre/modules/services/healthreport/providers.jsm
category healthreport-js-provider AppInfoProvider resource://gre/modules/services/healthreport/providers.jsm
category healthreport-js-provider CrashesProvider resource://gre/modules/services/healthreport/providers.jsm

View File

@ -11,13 +11,11 @@ include $(DEPTH)/config/autoconf.mk
modules := \
healthreporter.jsm \
policy.jsm \
profile.jsm \
providers.jsm \
$(NULL)
testing_modules := \
mocks.jsm \
utils.jsm \
$(NULL)
@ -32,7 +30,6 @@ TESTING_JS_MODULE_DIR := services/healthreport
EXTRA_COMPONENTS := \
HealthReportComponents.manifest \
HealthReportService.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -2,23 +2,22 @@
* 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/. */
pref("healthreport.documentServerURI", "https://data.mozilla.com/");
pref("healthreport.documentServerNamespace", "metrics");
pref("healthreport.logging.consoleEnabled", true);
pref("healthreport.logging.consoleLevel", "Warn");
pref("healthreport.policy.currentDaySubmissionFailureCount", 0);
pref("healthreport.policy.dataSubmissionEnabled", true);
pref("healthreport.policy.dataSubmissionPolicyAccepted", false);
pref("healthreport.policy.dataSubmissionPolicyBypassAcceptance", false);
pref("healthreport.policy.dataSubmissionPolicyNotifiedTime", "0");
pref("healthreport.policy.dataSubmissionPolicyResponseType", "");
pref("healthreport.policy.dataSubmissionPolicyResponseTime", "0");
pref("healthreport.policy.firstRunTime", "0");
pref("healthreport.policy.lastDataSubmissionFailureTime", "0");
pref("healthreport.policy.lastDataSubmissionRequestedTime", "0");
pref("healthreport.policy.lastDataSubmissionSuccessfulTime", "0");
pref("healthreport.policy.nextDataSubmissionTime", "0");
pref("healthreport.service.enabled", true);
pref("healthreport.service.loadDelayMsec", 10000);
pref("healthreport.service.providerCategories", "healthreport-js-provider");
pref("healthreport.infoURL", "http://www.mozilla.org/legal/privacy/firefox.html#health-report");
pref("datareporting.healthreport.currentDaySubmissionFailureCount", 0);
pref("datareporting.healthreport.documentServerURI", "https://data.mozilla.com/");
pref("datareporting.healthreport.documentServerNamespace", "metrics");
pref("datareporting.healthreport.infoURL", "http://www.mozilla.org/legal/privacy/firefox.html#health-report");
pref("datareporting.healthreport.logging.consoleEnabled", true);
pref("datareporting.healthreport.logging.consoleLevel", "Warn");
pref("datareporting.healthreport.lastDataSubmissionFailureTime", "0");
pref("datareporting.healthreport.lastDataSubmissionRequestedTime", "0");
pref("datareporting.healthreport.lastDataSubmissionSuccessfulTime", "0");
pref("datareporting.healthreport.nextDataSubmissionTime", "0");
pref("datareporting.healthreport.pendingDeleteRemoteData", false);
// Health Report is enabled by default on all channels.
pref("datareporting.healthreport.uploadEnabled", true);
pref("datareporting.healthreport.service.enabled", true);
pref("datareporting.healthreport.service.loadDelayMsec", 10000);
pref("datareporting.healthreport.service.providerCategories", "healthreport-js-provider");

View File

@ -11,7 +11,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://services-common/async.js");
Cu.import("resource://services-common/bagheeraclient.js");
Cu.import("resource://services-common/log4moz.js");
Cu.import("resource://services-common/observers.js");
Cu.import("resource://services-common/preferences.js");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://gre/modules/commonjs/promise/core.js");
@ -20,7 +19,6 @@ Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/services/healthreport/policy.jsm");
// Oldest year to allow in date preferences. This module was implemented in
@ -81,12 +79,19 @@ const DEFAULT_DATABASE_NAME = "healthreport.sqlite";
* @param branch
* (string) The preferences branch to use for state storage. The value
* must end with a period (.).
*
* @param policy
* (HealthReportPolicy) Policy driving execution of HealthReporter.
*/
function HealthReporter(branch) {
function HealthReporter(branch, policy) {
if (!branch.endsWith(".")) {
throw new Error("Branch must end with a period (.): " + branch);
}
if (!policy) {
throw new Error("Must provide policy to HealthReporter constructor.");
}
this._log = Log4Moz.repository.getLogger("Services.HealthReport.HealthReporter");
this._log.info("Initializing health reporter instance against " + branch);
@ -100,10 +105,9 @@ function HealthReporter(branch) {
throw new Error("No server namespace defined. Did you forget a pref?");
}
this._dbName = this._prefs.get("dbName") || DEFAULT_DATABASE_NAME;
this._policy = policy;
let policyBranch = new Preferences(branch + "policy.");
this._policy = new HealthReportPolicy(policyBranch, this);
this._dbName = this._prefs.get("dbName") || DEFAULT_DATABASE_NAME;
this._storage = null;
this._storageInProgress = false;
@ -210,6 +214,14 @@ HealthReporter.prototype = Object.freeze({
this._prefs.set("lastSubmitID", value || "");
},
/**
* Whether this instance will upload data to a server.
*/
get willUploadData() {
return this._policy.dataSubmissionPolicyAccepted &&
this._policy.healthReportUploadEnabled;
},
/**
* Whether remote data is currently stored.
*
@ -289,7 +301,6 @@ HealthReporter.prototype = Object.freeze({
return;
}
this._policy.startPolling();
this._log.info("HealthReporter started.");
this._initialized = true;
Services.obs.addObserver(this, "idle-daily", false);
@ -327,9 +338,6 @@ HealthReporter.prototype = Object.freeze({
this._initialized = false;
this._shutdownRequested = true;
// Safe to call multiple times.
this._policy.stopPolling();
if (this._collectorInProgress) {
this._log.warn("Collector is in progress of initializing. Waiting to finish.");
return;
@ -552,45 +560,14 @@ HealthReporter.prototype = Object.freeze({
},
/**
* Record the user's rejection of the data submission policy.
* Called to initiate a data upload.
*
* This should be what everything uses to disable data submission.
*
* @param reason
* (string) Why data submission is being disabled.
* The passed argument is a `DataSubmissionRequest` from policy.jsm.
*/
recordPolicyRejection: function (reason) {
this._policy.recordUserRejection(reason);
},
/**
* Record the user's acceptance of the data submission policy.
*
* This should be what everything uses to enable data submission.
*
* @param reason
* (string) Why data submission is being enabled.
*/
recordPolicyAcceptance: function (reason) {
this._policy.recordUserAcceptance(reason);
},
/**
* Whether the data submission policy has been accepted.
*
* If this is true, health data will be submitted unless one of the kill
* switches is active.
*/
get dataSubmissionPolicyAccepted() {
return this._policy.dataSubmissionPolicyAccepted;
},
/**
* Whether this health reporter will upload data to a server.
*/
get willUploadData() {
return this._policy.dataSubmissionPolicyAccepted &&
this._policy.dataUploadEnabled;
requestDataUpload: function (request) {
this.collectMeasurements()
.then(this._uploadData.bind(this, request),
this._onSubmitDataRequestFailure.bind(this));
},
/**
@ -768,7 +745,7 @@ HealthReporter.prototype = Object.freeze({
}.bind(this));
},
_deleteRemoteData: function (request) {
deleteRemoteData: function (request) {
if (!this.lastSubmitID) {
this._log.info("Received request to delete remote data but no data stored.");
request.onNoDataAvailable();
@ -859,28 +836,5 @@ HealthReporter.prototype = Object.freeze({
return new Date();
},
//-----------------------------
// HealthReportPolicy listeners
//-----------------------------
onRequestDataUpload: function (request) {
this.collectMeasurements()
.then(this._uploadData.bind(this, request),
this._onSubmitDataRequestFailure.bind(this));
},
onNotifyDataPolicy: function (request) {
// This isn't very loosely coupled. We may want to have this call
// registered listeners instead.
Observers.notify("healthreport:notify-data-policy:request", request);
},
onRequestRemoteDelete: function (request) {
this._deleteRemoteData(request);
},
//------------------------------------
// End of HealthReportPolicy listeners
//------------------------------------
});

View File

@ -216,8 +216,8 @@ this.createFakeCrash = function (submitted=false, date=new Date()) {
*
* The purpose of this type is to aid testing of startup and shutdown.
*/
this.InspectedHealthReporter = function (branch) {
HealthReporter.call(this, branch);
this.InspectedHealthReporter = function (branch, policy) {
HealthReporter.call(this, branch, policy);
this.onStorageCreated = null;
this.onCollectorInitialized = null;

View File

@ -9,7 +9,7 @@ Cu.import("resource://services-common/observers.js");
Cu.import("resource://services-common/preferences.js");
Cu.import("resource://gre/modules/commonjs/promise/core.js");
Cu.import("resource://gre/modules/services/healthreport/healthreporter.jsm");
Cu.import("resource://gre/modules/services/healthreport/policy.jsm");
Cu.import("resource://gre/modules/services/datareporting/policy.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://testing-common/services-common/bagheeraserver.js");
@ -36,12 +36,29 @@ function defineNow(policy, now) {
function getJustReporter(name, uri=SERVER_URI, inspected=false) {
let branch = "healthreport.testing. " + name + ".";
let prefs = new Preferences(branch);
let prefs = new Preferences(branch + "healthreport.");
prefs.set("documentServerURI", uri);
prefs.set("dbName", name);
let reporter;
let policyPrefs = new Preferences(branch + "policy.");
let policy = new DataReportingPolicy(policyPrefs, prefs, {
onRequestDataUpload: function (request) {
reporter.requestDataUpload(request);
},
onNotifyDataPolicy: function (request) { },
onRequestRemoteDelete: function (request) {
reporter.deleteRemoteData(request);
},
});
let type = inspected ? InspectedHealthReporter : HealthReporter;
return new type(branch);
reporter = new type(branch + "healthreport.", policy);
return reporter;
}
function getReporter(name, uri, inspected) {
@ -251,7 +268,7 @@ add_task(function test_data_submission_transport_failure() {
let deferred = Promise.defer();
let request = new DataSubmissionRequest(deferred, new Date(Date.now + 30000));
reporter.onRequestDataUpload(request);
reporter.requestDataUpload(request);
yield deferred.promise;
do_check_eq(request.state, request.SUBMISSION_FAILURE_SOFT);
@ -268,7 +285,7 @@ add_task(function test_data_submission_success() {
let deferred = Promise.defer();
let request = new DataSubmissionRequest(deferred, new Date());
reporter.onRequestDataUpload(request);
reporter.requestDataUpload(request);
yield deferred.promise;
do_check_eq(request.state, request.SUBMISSION_SUCCESS);
do_check_true(reporter.lastPingDate.getTime() > 0);
@ -336,22 +353,23 @@ add_task(function test_request_remote_data_deletion() {
add_task(function test_policy_accept_reject() {
let [reporter, server] = yield getReporterAndServer("policy_accept_reject");
do_check_false(reporter.dataSubmissionPolicyAccepted);
let policy = reporter._policy;
do_check_false(policy.dataSubmissionPolicyAccepted);
do_check_false(reporter.willUploadData);
reporter.recordPolicyAcceptance();
do_check_true(reporter.dataSubmissionPolicyAccepted);
policy.recordUserAcceptance();
do_check_true(policy.dataSubmissionPolicyAccepted);
do_check_true(reporter.willUploadData);
reporter.recordPolicyRejection();
do_check_false(reporter.dataSubmissionPolicyAccepted);
policy.recordUserRejection();
do_check_false(policy.dataSubmissionPolicyAccepted);
do_check_false(reporter.willUploadData);
reporter._shutdown();
yield shutdownServer(server);
});
add_task(function test_upload_save_payload() {
let [reporter, server] = yield getReporterAndServer("upload_save_payload");

View File

@ -5,24 +5,14 @@
const modules = [
"healthreporter.jsm",
"policy.jsm",
"profile.jsm",
"providers.jsm",
];
const test_modules = [
"mocks.jsm",
];
function run_test() {
for (let m of modules) {
let resource = "resource://gre/modules/services/healthreport/" + m;
Components.utils.import(resource, {});
}
for (let m of test_modules) {
let resource = "resource://testing-common/services/healthreport/" + m;
Components.utils.import(resource, {});
}
}

View File

@ -4,7 +4,6 @@ tail =
[test_load_modules.js]
[test_profile.js]
[test_policy.js]
[test_healthreporter.js]
[test_provider_addons.js]
[test_provider_appinfo.js]

View File

@ -9,6 +9,7 @@ add_makefiles "
services/crypto/Makefile
services/crypto/component/Makefile
services/healthreport/Makefile
services/datareporting/Makefile
services/metrics/Makefile
services/sync/Makefile
services/sync/locales/Makefile
@ -20,6 +21,7 @@ if [ "$ENABLE_TESTS" ]; then
services/common/tests/Makefile
services/crypto/tests/Makefile
services/healthreport/tests/Makefile
services/datareporting/tests/Makefile
services/metrics/tests/Makefile
services/sync/tests/Makefile
"

View File

@ -88,6 +88,7 @@ skip-if = os == "android"
[include:services/common/tests/unit/xpcshell.ini]
[include:services/crypto/tests/unit/xpcshell.ini]
[include:services/crypto/components/tests/unit/xpcshell.ini]
[include:services/datareporting/tests/xpcshell/xpcshell.ini]
[include:services/healthreport/tests/xpcshell/xpcshell.ini]
[include:services/metrics/tests/xpcshell/xpcshell.ini]
[include:services/sync/tests/unit/xpcshell.ini]