зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1569330 - Disable telemetry check in Normandy recipe runner r=mythmon,nalexander
Differential Revision: https://phabricator.services.mozilla.com/D39576 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
9f979c6057
Коммит
43acd674ea
|
@ -1237,7 +1237,9 @@ BrowserGlue.prototype = {
|
||||||
"resource:///modules/themes/dark/"
|
"resource:///modules/themes/dark/"
|
||||||
);
|
);
|
||||||
|
|
||||||
Normandy.init();
|
if (AppConstants.MOZ_NORMANDY) {
|
||||||
|
Normandy.init();
|
||||||
|
}
|
||||||
|
|
||||||
SaveToPocket.init();
|
SaveToPocket.init();
|
||||||
Services.obs.notifyObservers(null, "browser-ui-startup-complete");
|
Services.obs.notifyObservers(null, "browser-ui-startup-complete");
|
||||||
|
|
|
@ -7,17 +7,41 @@ add_task(async function test_policy_disable_shield() {
|
||||||
const { RecipeRunner } = ChromeUtils.import(
|
const { RecipeRunner } = ChromeUtils.import(
|
||||||
"resource://normandy/lib/RecipeRunner.jsm"
|
"resource://normandy/lib/RecipeRunner.jsm"
|
||||||
);
|
);
|
||||||
|
const { BaseAction } = ChromeUtils.import(
|
||||||
|
"resource://normandy/actions/BaseAction.jsm"
|
||||||
|
);
|
||||||
|
const { BaseStudyAction } = ChromeUtils.import(
|
||||||
|
"resource://normandy/actions/BaseStudyAction.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
const baseAction = new BaseAction();
|
||||||
|
const baseStudyAction = new BaseStudyAction();
|
||||||
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
await SpecialPowers.pushPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["app.normandy.api_url", "https://localhost/selfsupport-dummy/"],
|
["app.normandy.api_url", "https://localhost/selfsupport-dummy/"],
|
||||||
["datareporting.healthreport.uploadEnabled", true],
|
["app.shield.optoutstudies.enabled", true],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
ok(RecipeRunner, "RecipeRunner exists");
|
ok(RecipeRunner, "RecipeRunner exists");
|
||||||
|
|
||||||
RecipeRunner.checkPrefs();
|
RecipeRunner.checkPrefs();
|
||||||
is(RecipeRunner.enabled, true, "RecipeRunner is enabled");
|
ok(RecipeRunner.enabled, "RecipeRunner is enabled");
|
||||||
|
|
||||||
|
baseAction._preExecution();
|
||||||
|
is(
|
||||||
|
baseAction.state,
|
||||||
|
BaseAction.STATE_PREPARING,
|
||||||
|
"Base action is not disabled"
|
||||||
|
);
|
||||||
|
|
||||||
|
baseStudyAction._preExecution();
|
||||||
|
is(
|
||||||
|
baseStudyAction.state,
|
||||||
|
BaseAction.STATE_PREPARING,
|
||||||
|
"Base study action is not disabled"
|
||||||
|
);
|
||||||
|
|
||||||
await setupPolicyEngineWithJson({
|
await setupPolicyEngineWithJson({
|
||||||
policies: {
|
policies: {
|
||||||
|
@ -26,5 +50,19 @@ add_task(async function test_policy_disable_shield() {
|
||||||
});
|
});
|
||||||
|
|
||||||
RecipeRunner.checkPrefs();
|
RecipeRunner.checkPrefs();
|
||||||
is(RecipeRunner.enabled, false, "RecipeRunner is disabled");
|
ok(RecipeRunner.enabled, "RecipeRunner is still enabled");
|
||||||
|
|
||||||
|
baseAction._preExecution();
|
||||||
|
is(
|
||||||
|
baseAction.state,
|
||||||
|
BaseAction.STATE_PREPARING,
|
||||||
|
"Base action is not disabled"
|
||||||
|
);
|
||||||
|
|
||||||
|
baseStudyAction._preExecution();
|
||||||
|
is(
|
||||||
|
baseStudyAction.state,
|
||||||
|
BaseAction.STATE_DISABLED,
|
||||||
|
"Base study action is disabled"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -828,17 +828,6 @@
|
||||||
class="learnMore" is="text-link"
|
class="learnMore" is="text-link"
|
||||||
data-l10n-id="collection-health-report-link"/>
|
data-l10n-id="collection-health-report-link"/>
|
||||||
<vbox class="indent">
|
<vbox class="indent">
|
||||||
<hbox align="center">
|
|
||||||
<checkbox id="optOutStudiesEnabled"
|
|
||||||
class="tail-with-learn-more"
|
|
||||||
data-l10n-id="collection-studies"/>
|
|
||||||
<label id="viewShieldStudies"
|
|
||||||
href="about:studies"
|
|
||||||
useoriginprincipal="true"
|
|
||||||
class="learnMore" is="text-link"
|
|
||||||
data-l10n-id="collection-studies-link"/>
|
|
||||||
</hbox>
|
|
||||||
|
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
<checkbox id="addonRecommendationEnabled"
|
<checkbox id="addonRecommendationEnabled"
|
||||||
class="tail-with-learn-more"
|
class="tail-with-learn-more"
|
||||||
|
@ -855,6 +844,19 @@
|
||||||
data-l10n-id="collection-health-report-disabled"/>
|
data-l10n-id="collection-health-report-disabled"/>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MOZ_NORMANDY
|
||||||
|
<hbox align="center">
|
||||||
|
<checkbox id="optOutStudiesEnabled"
|
||||||
|
class="tail-with-learn-more"
|
||||||
|
data-l10n-id="collection-studies"/>
|
||||||
|
<label id="viewShieldStudies"
|
||||||
|
href="about:studies"
|
||||||
|
useoriginprincipal="true"
|
||||||
|
class="learnMore" is="text-link"
|
||||||
|
data-l10n-id="collection-studies-link"/>
|
||||||
|
</hbox>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_CRASHREPORTER
|
#ifdef MOZ_CRASHREPORTER
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
<checkbox id="automaticallySubmitCrashesBox"
|
<checkbox id="automaticallySubmitCrashesBox"
|
||||||
|
|
|
@ -604,7 +604,9 @@ var gPrivacyPane = {
|
||||||
"command",
|
"command",
|
||||||
gPrivacyPane.updateSubmitHealthReport
|
gPrivacyPane.updateSubmitHealthReport
|
||||||
);
|
);
|
||||||
this.initOptOutStudyCheckbox();
|
if (AppConstants.MOZ_NORMANDY) {
|
||||||
|
this.initOptOutStudyCheckbox();
|
||||||
|
}
|
||||||
this.initAddonRecommendationsCheckbox();
|
this.initAddonRecommendationsCheckbox();
|
||||||
}
|
}
|
||||||
this._initA11yState();
|
this._initA11yState();
|
||||||
|
@ -2140,14 +2142,11 @@ var gPrivacyPane = {
|
||||||
* handles events coming from the UI for it.
|
* handles events coming from the UI for it.
|
||||||
*/
|
*/
|
||||||
initOptOutStudyCheckbox(doc) {
|
initOptOutStudyCheckbox(doc) {
|
||||||
const allowedByPolicy = Services.policies.isAllowed("Shield");
|
|
||||||
|
|
||||||
// The checkbox should be disabled if any of the below are true. This
|
// The checkbox should be disabled if any of the below are true. This
|
||||||
// prevents the user from changing the value in the box.
|
// prevents the user from changing the value in the box.
|
||||||
//
|
//
|
||||||
// * the policy forbids shield
|
// * the policy forbids shield
|
||||||
// * the Shield Study preference is locked
|
// * Normandy is disabled
|
||||||
// * the FHR pref is false
|
|
||||||
//
|
//
|
||||||
// The checkbox should match the value of the preference only if all of
|
// The checkbox should match the value of the preference only if all of
|
||||||
// these are true. Otherwise, the checkbox should remain unchecked. This
|
// these are true. Otherwise, the checkbox should remain unchecked. This
|
||||||
|
@ -2155,16 +2154,27 @@ var gPrivacyPane = {
|
||||||
// so showing a checkbox would be confusing.
|
// so showing a checkbox would be confusing.
|
||||||
//
|
//
|
||||||
// * the policy allows Shield
|
// * the policy allows Shield
|
||||||
// * the FHR pref is true
|
|
||||||
// * Normandy is enabled
|
// * Normandy is enabled
|
||||||
dataCollectionCheckboxHandler({
|
|
||||||
checkbox: document.getElementById("optOutStudiesEnabled"),
|
const allowedByPolicy = Services.policies.isAllowed("Shield");
|
||||||
matchPref: () =>
|
const checkbox = document.getElementById("optOutStudiesEnabled");
|
||||||
allowedByPolicy &&
|
|
||||||
Services.prefs.getBoolPref(PREF_NORMANDY_ENABLED, false),
|
if (
|
||||||
isDisabled: () => !allowedByPolicy,
|
allowedByPolicy &&
|
||||||
pref: PREF_OPT_OUT_STUDIES_ENABLED,
|
Services.prefs.getBoolPref(PREF_NORMANDY_ENABLED, false)
|
||||||
});
|
) {
|
||||||
|
if (Services.prefs.getBoolPref(PREF_OPT_OUT_STUDIES_ENABLED, false)) {
|
||||||
|
checkbox.setAttribute("checked", "true");
|
||||||
|
} else {
|
||||||
|
checkbox.removeAttribute("checked");
|
||||||
|
}
|
||||||
|
checkbox.setAttribute("preference", PREF_OPT_OUT_STUDIES_ENABLED);
|
||||||
|
checkbox.removeAttribute("disabled");
|
||||||
|
} else {
|
||||||
|
checkbox.removeAttribute("preference");
|
||||||
|
checkbox.removeAttribute("checked");
|
||||||
|
checkbox.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
initAddonRecommendationsCheckbox() {
|
initAddonRecommendationsCheckbox() {
|
||||||
|
|
|
@ -9,6 +9,7 @@ imply_option('MOZ_SERVICES_HEALTHREPORT', True)
|
||||||
imply_option('MOZ_SERVICES_SYNC', True)
|
imply_option('MOZ_SERVICES_SYNC', True)
|
||||||
imply_option('MOZ_DEDICATED_PROFILES', True)
|
imply_option('MOZ_DEDICATED_PROFILES', True)
|
||||||
imply_option('MOZ_BLOCK_PROFILE_DOWNGRADE', True)
|
imply_option('MOZ_BLOCK_PROFILE_DOWNGRADE', True)
|
||||||
|
imply_option('MOZ_NORMANDY', True)
|
||||||
|
|
||||||
with only_when(target_is_linux & compile_environment):
|
with only_when(target_is_linux & compile_environment):
|
||||||
option(env='MOZ_NO_PIE_COMPAT',
|
option(env='MOZ_NO_PIE_COMPAT',
|
||||||
|
|
|
@ -121,7 +121,7 @@ set_define('FENNEC_NIGHTLY', depends_if('FENNEC_NIGHTLY')(lambda _: True))
|
||||||
def fennec_nightly(nightly):
|
def fennec_nightly(nightly):
|
||||||
return bool(nightly)
|
return bool(nightly)
|
||||||
|
|
||||||
|
imply_option('MOZ_NORMANDY', False)
|
||||||
imply_option('MOZ_SERVICES_HEALTHREPORT', True)
|
imply_option('MOZ_SERVICES_HEALTHREPORT', True)
|
||||||
imply_option('MOZ_ANDROID_HISTORY', True)
|
imply_option('MOZ_ANDROID_HISTORY', True)
|
||||||
imply_option('--enable-small-chunk-size', True)
|
imply_option('--enable-small-chunk-size', True)
|
||||||
|
|
|
@ -3085,7 +3085,7 @@ AC_SUBST(MOZ_INCLUDE_SOURCE_INFO)
|
||||||
dnl If we have any service that uploads data (and requires data submission
|
dnl If we have any service that uploads data (and requires data submission
|
||||||
dnl policy alert), set MOZ_DATA_REPORTING.
|
dnl policy alert), set MOZ_DATA_REPORTING.
|
||||||
dnl We need SUBST for build system and DEFINE for xul preprocessor.
|
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
|
if test -n "$MOZ_TELEMETRY_REPORTING" || test -n "$MOZ_SERVICES_HEALTHREPORT" || test -n "$MOZ_CRASHREPORTER" || test -n "$MOZ_NORMANDY"; then
|
||||||
MOZ_DATA_REPORTING=1
|
MOZ_DATA_REPORTING=1
|
||||||
AC_DEFINE(MOZ_DATA_REPORTING)
|
AC_DEFINE(MOZ_DATA_REPORTING)
|
||||||
AC_SUBST(MOZ_DATA_REPORTING)
|
AC_SUBST(MOZ_DATA_REPORTING)
|
||||||
|
|
|
@ -78,6 +78,7 @@ def build_dict(config, env=os.environ):
|
||||||
d['devedition'] = substs.get('MOZ_DEV_EDITION') == '1'
|
d['devedition'] = substs.get('MOZ_DEV_EDITION') == '1'
|
||||||
d['pgo'] = substs.get('MOZ_PGO') == '1'
|
d['pgo'] = substs.get('MOZ_PGO') == '1'
|
||||||
d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER'))
|
d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER'))
|
||||||
|
d['normandy'] = substs.get('MOZ_NORMANDY') == '1'
|
||||||
d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING'))
|
d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING'))
|
||||||
d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
|
d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
|
||||||
d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1'
|
d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1'
|
||||||
|
|
|
@ -14,6 +14,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
AddonStudies: "resource://normandy/lib/AddonStudies.jsm",
|
AddonStudies: "resource://normandy/lib/AddonStudies.jsm",
|
||||||
CleanupManager: "resource://normandy/lib/CleanupManager.jsm",
|
CleanupManager: "resource://normandy/lib/CleanupManager.jsm",
|
||||||
LogManager: "resource://normandy/lib/LogManager.jsm",
|
LogManager: "resource://normandy/lib/LogManager.jsm",
|
||||||
|
NormandyMigrations: "resource://normandy/NormandyMigrations.jsm",
|
||||||
PreferenceExperiments: "resource://normandy/lib/PreferenceExperiments.jsm",
|
PreferenceExperiments: "resource://normandy/lib/PreferenceExperiments.jsm",
|
||||||
PreferenceRollouts: "resource://normandy/lib/PreferenceRollouts.jsm",
|
PreferenceRollouts: "resource://normandy/lib/PreferenceRollouts.jsm",
|
||||||
RecipeRunner: "resource://normandy/lib/RecipeRunner.jsm",
|
RecipeRunner: "resource://normandy/lib/RecipeRunner.jsm",
|
||||||
|
@ -28,7 +29,6 @@ const BOOTSTRAP_LOGGER_NAME = "app.normandy.bootstrap";
|
||||||
const SHIELD_INIT_NOTIFICATION = "shield-init-complete";
|
const SHIELD_INIT_NOTIFICATION = "shield-init-complete";
|
||||||
|
|
||||||
const PREF_PREFIX = "app.normandy";
|
const PREF_PREFIX = "app.normandy";
|
||||||
const LEGACY_PREF_PREFIX = "extensions.shield-recipe-client";
|
|
||||||
const STARTUP_EXPERIMENT_PREFS_BRANCH = `${PREF_PREFIX}.startupExperimentPrefs.`;
|
const STARTUP_EXPERIMENT_PREFS_BRANCH = `${PREF_PREFIX}.startupExperimentPrefs.`;
|
||||||
const STARTUP_ROLLOUT_PREFS_BRANCH = `${PREF_PREFIX}.startupRolloutPrefs.`;
|
const STARTUP_ROLLOUT_PREFS_BRANCH = `${PREF_PREFIX}.startupRolloutPrefs.`;
|
||||||
const PREF_LOGGING_LEVEL = `${PREF_PREFIX}.logging.level`;
|
const PREF_LOGGING_LEVEL = `${PREF_PREFIX}.logging.level`;
|
||||||
|
@ -44,7 +44,7 @@ var Normandy = {
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Initialization that needs to happen before the first paint on startup.
|
// Initialization that needs to happen before the first paint on startup.
|
||||||
this.migrateShieldPrefs();
|
NormandyMigrations.applyAll();
|
||||||
this.rolloutPrefsChanged = this.applyStartupPrefs(
|
this.rolloutPrefsChanged = this.applyStartupPrefs(
|
||||||
STARTUP_ROLLOUT_PREFS_BRANCH
|
STARTUP_ROLLOUT_PREFS_BRANCH
|
||||||
);
|
);
|
||||||
|
@ -129,57 +129,6 @@ var Normandy = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
migrateShieldPrefs() {
|
|
||||||
const legacyBranch = Services.prefs.getBranch(LEGACY_PREF_PREFIX + ".");
|
|
||||||
const newBranch = Services.prefs.getBranch(PREF_PREFIX + ".");
|
|
||||||
|
|
||||||
for (const prefName of legacyBranch.getChildList("")) {
|
|
||||||
const legacyPrefType = legacyBranch.getPrefType(prefName);
|
|
||||||
const newPrefType = newBranch.getPrefType(prefName);
|
|
||||||
|
|
||||||
// If new preference exists and is not the same as the legacy pref, skip it
|
|
||||||
if (
|
|
||||||
newPrefType !== Services.prefs.PREF_INVALID &&
|
|
||||||
newPrefType !== legacyPrefType
|
|
||||||
) {
|
|
||||||
log.error(
|
|
||||||
`Error migrating normandy pref ${prefName}; pref type does not match.`
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now move the value over. If it matches the default, this will be a no-op
|
|
||||||
switch (legacyPrefType) {
|
|
||||||
case Services.prefs.PREF_STRING:
|
|
||||||
newBranch.setCharPref(prefName, legacyBranch.getCharPref(prefName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Services.prefs.PREF_INT:
|
|
||||||
newBranch.setIntPref(prefName, legacyBranch.getIntPref(prefName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Services.prefs.PREF_BOOL:
|
|
||||||
newBranch.setBoolPref(prefName, legacyBranch.getBoolPref(prefName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Services.prefs.PREF_INVALID:
|
|
||||||
// This should never happen.
|
|
||||||
log.error(
|
|
||||||
`Error migrating pref ${prefName}; pref type is invalid (${legacyPrefType}).`
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// This should never happen either.
|
|
||||||
log.error(
|
|
||||||
`Error getting startup pref ${prefName}; unknown value type ${legacyPrefType}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
legacyBranch.clearUserPref(prefName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy a preference subtree from one branch to another, being careful about
|
* Copy a preference subtree from one branch to another, being careful about
|
||||||
* types, and return the values the target branch originally had. Prefs will
|
* types, and return the values the target branch originally had. Prefs will
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/* 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 { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||||
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = ["NormandyMigrations"];
|
||||||
|
|
||||||
|
const BOOTSTRAP_LOGGER_NAME = "app.normandy.bootstrap";
|
||||||
|
|
||||||
|
const PREF_PREFIX = "app.normandy";
|
||||||
|
const LEGACY_PREF_PREFIX = "extensions.shield-recipe-client";
|
||||||
|
const PREF_LOGGING_LEVEL = `${PREF_PREFIX}.logging.level`;
|
||||||
|
const PREF_MIGRATIONS_APPLIED = `${PREF_PREFIX}.migrationsApplied`;
|
||||||
|
const PREF_OPTOUTSTUDIES_ENABLED = "app.shield.optoutstudies.enabled";
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
const log = Log.repository.getLogger(BOOTSTRAP_LOGGER_NAME);
|
||||||
|
log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
|
||||||
|
log.level = Services.prefs.getIntPref(PREF_LOGGING_LEVEL, Log.Level.Warn);
|
||||||
|
|
||||||
|
const NormandyMigrations = {
|
||||||
|
applyAll() {
|
||||||
|
let migrationsApplied = Services.prefs.getIntPref(
|
||||||
|
PREF_MIGRATIONS_APPLIED,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = migrationsApplied; i < this.migrations.length; i++) {
|
||||||
|
this.applyOne(i);
|
||||||
|
migrationsApplied++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.prefs.setIntPref(PREF_MIGRATIONS_APPLIED, migrationsApplied);
|
||||||
|
},
|
||||||
|
|
||||||
|
applyOne(id) {
|
||||||
|
this.migrations[id]();
|
||||||
|
},
|
||||||
|
|
||||||
|
migrations: [
|
||||||
|
// Migration 0
|
||||||
|
migrateShieldPrefs,
|
||||||
|
|
||||||
|
// Migration 1
|
||||||
|
migrateStudiesEnabledWithoutHealthReporting,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
function migrateShieldPrefs() {
|
||||||
|
const legacyBranch = Services.prefs.getBranch(LEGACY_PREF_PREFIX + ".");
|
||||||
|
const newBranch = Services.prefs.getBranch(PREF_PREFIX + ".");
|
||||||
|
|
||||||
|
for (const prefName of legacyBranch.getChildList("")) {
|
||||||
|
const legacyPrefType = legacyBranch.getPrefType(prefName);
|
||||||
|
const newPrefType = newBranch.getPrefType(prefName);
|
||||||
|
|
||||||
|
// If new preference exists and is not the same as the legacy pref, skip it
|
||||||
|
if (
|
||||||
|
newPrefType !== Services.prefs.PREF_INVALID &&
|
||||||
|
newPrefType !== legacyPrefType
|
||||||
|
) {
|
||||||
|
log.error(
|
||||||
|
`Error migrating normandy pref ${prefName}; pref type does not match.`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now move the value over. If it matches the default, this will be a no-op
|
||||||
|
switch (legacyPrefType) {
|
||||||
|
case Services.prefs.PREF_STRING:
|
||||||
|
newBranch.setCharPref(prefName, legacyBranch.getCharPref(prefName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Services.prefs.PREF_INT:
|
||||||
|
newBranch.setIntPref(prefName, legacyBranch.getIntPref(prefName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Services.prefs.PREF_BOOL:
|
||||||
|
newBranch.setBoolPref(prefName, legacyBranch.getBoolPref(prefName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Services.prefs.PREF_INVALID:
|
||||||
|
// This should never happen.
|
||||||
|
log.error(
|
||||||
|
`Error migrating pref ${prefName}; pref type is invalid (${legacyPrefType}).`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// This should never happen either.
|
||||||
|
log.error(
|
||||||
|
`Error getting startup pref ${prefName}; unknown value type ${legacyPrefType}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
legacyBranch.clearUserPref(prefName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration to handle moving the studies opt-out pref from under the health
|
||||||
|
* report upload pref to an independent pref.
|
||||||
|
*
|
||||||
|
* If the pref was set to true and the health report upload pref was set
|
||||||
|
* to true then the pref should stay true. Otherwise set it to false.
|
||||||
|
*/
|
||||||
|
function migrateStudiesEnabledWithoutHealthReporting() {
|
||||||
|
const optOutStudiesEnabled = Services.prefs.getBoolPref(
|
||||||
|
PREF_OPTOUTSTUDIES_ENABLED,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
const healthReportUploadEnabled = Services.prefs.getBoolPref(
|
||||||
|
"datareporting.healthreport.uploadEnabled",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
Services.prefs.setBoolPref(
|
||||||
|
PREF_OPTOUTSTUDIES_ENABLED,
|
||||||
|
optOutStudiesEnabled && healthReportUploadEnabled
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* 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 { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
const { BaseAction } = ChromeUtils.import(
|
||||||
|
"resource://normandy/actions/BaseAction.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = ["BaseStudyAction"];
|
||||||
|
|
||||||
|
const OPT_OUT_STUDIES_ENABLED_PREF = "app.shield.optoutstudies.enabled";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for local study actions.
|
||||||
|
*
|
||||||
|
* This should be subclassed. Subclasses must implement _run() for
|
||||||
|
* per-recipe behavior, and may implement _finalize for actions to be
|
||||||
|
* taken once after recipes are run.
|
||||||
|
*
|
||||||
|
* For actions that need to be taken once before recipes are run
|
||||||
|
* _preExecution may be overriden but the overridden method must
|
||||||
|
* call the parent method to ensure the appropriate checks occur.
|
||||||
|
*
|
||||||
|
* Other methods should be overridden with care, to maintain the life
|
||||||
|
* cycle events and error reporting implemented by this class.
|
||||||
|
*/
|
||||||
|
class BaseStudyAction extends BaseAction {
|
||||||
|
_preExecution() {
|
||||||
|
if (!Services.policies.isAllowed("Shield")) {
|
||||||
|
this.log.debug("Disabling Shield because it's blocked by policy.");
|
||||||
|
this.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Services.prefs.getBoolPref(OPT_OUT_STUDIES_ENABLED_PREF, true)) {
|
||||||
|
this.log.debug(
|
||||||
|
"User has opted-out of opt-out experiments, disabling action."
|
||||||
|
);
|
||||||
|
this.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,8 @@
|
||||||
const { XPCOMUtils } = ChromeUtils.import(
|
const { XPCOMUtils } = ChromeUtils.import(
|
||||||
"resource://gre/modules/XPCOMUtils.jsm"
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
);
|
);
|
||||||
const { BaseAction } = ChromeUtils.import(
|
const { BaseStudyAction } = ChromeUtils.import(
|
||||||
"resource://normandy/actions/BaseAction.jsm"
|
"resource://normandy/actions/BaseStudyAction.jsm"
|
||||||
);
|
);
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
|
@ -33,8 +33,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["BranchedAddonStudyAction"];
|
var EXPORTED_SYMBOLS = ["BranchedAddonStudyAction"];
|
||||||
|
|
||||||
const OPT_OUT_STUDIES_ENABLED_PREF = "app.shield.optoutstudies.enabled";
|
|
||||||
|
|
||||||
class AddonStudyEnrollError extends Error {
|
class AddonStudyEnrollError extends Error {
|
||||||
/**
|
/**
|
||||||
* @param {string} studyName
|
* @param {string} studyName
|
||||||
|
@ -115,7 +113,7 @@ class AddonStudyUpdateError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BranchedAddonStudyAction extends BaseAction {
|
class BranchedAddonStudyAction extends BaseStudyAction {
|
||||||
get schema() {
|
get schema() {
|
||||||
return ActionSchemas["branched-addon-study"];
|
return ActionSchemas["branched-addon-study"];
|
||||||
}
|
}
|
||||||
|
@ -125,23 +123,6 @@ class BranchedAddonStudyAction extends BaseAction {
|
||||||
this.seenRecipeIds = new Set();
|
this.seenRecipeIds = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This hook is executed once before any recipes have been processed, it is
|
|
||||||
* responsible for:
|
|
||||||
*
|
|
||||||
* - Checking if the user has opted out of studies, and if so, it disables the action.
|
|
||||||
* - Setting up tracking of seen recipes, for use in _finalize.
|
|
||||||
*/
|
|
||||||
_preExecution() {
|
|
||||||
// Check opt-out preference
|
|
||||||
if (!Services.prefs.getBoolPref(OPT_OUT_STUDIES_ENABLED_PREF, true)) {
|
|
||||||
this.log.info(
|
|
||||||
"User has opted-out of opt-out experiments, disabling action."
|
|
||||||
);
|
|
||||||
this.disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This hook is executed once for each recipe that currently applies to this
|
* This hook is executed once for each recipe that currently applies to this
|
||||||
* client. It is responsible for:
|
* client. It is responsible for:
|
||||||
|
|
|
@ -4,11 +4,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { XPCOMUtils } = ChromeUtils.import(
|
const { BaseStudyAction } = ChromeUtils.import(
|
||||||
"resource://gre/modules/XPCOMUtils.jsm"
|
"resource://normandy/actions/BaseStudyAction.jsm"
|
||||||
);
|
|
||||||
const { BaseAction } = ChromeUtils.import(
|
|
||||||
"resource://normandy/actions/BaseAction.jsm"
|
|
||||||
);
|
);
|
||||||
ChromeUtils.defineModuleGetter(
|
ChromeUtils.defineModuleGetter(
|
||||||
this,
|
this,
|
||||||
|
@ -30,13 +27,6 @@ ChromeUtils.defineModuleGetter(
|
||||||
"PreferenceExperiments",
|
"PreferenceExperiments",
|
||||||
"resource://normandy/lib/PreferenceExperiments.jsm"
|
"resource://normandy/lib/PreferenceExperiments.jsm"
|
||||||
);
|
);
|
||||||
const SHIELD_OPT_OUT_PREF = "app.shield.optoutstudies.enabled";
|
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
|
||||||
this,
|
|
||||||
"shieldOptOutPref",
|
|
||||||
SHIELD_OPT_OUT_PREF,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["PreferenceExperimentAction"];
|
var EXPORTED_SYMBOLS = ["PreferenceExperimentAction"];
|
||||||
|
|
||||||
|
@ -45,7 +35,7 @@ var EXPORTED_SYMBOLS = ["PreferenceExperimentAction"];
|
||||||
* user to an experiment branch and modify a preference temporarily to
|
* user to an experiment branch and modify a preference temporarily to
|
||||||
* measure how it affects Firefox via Telemetry.
|
* measure how it affects Firefox via Telemetry.
|
||||||
*/
|
*/
|
||||||
class PreferenceExperimentAction extends BaseAction {
|
class PreferenceExperimentAction extends BaseStudyAction {
|
||||||
get schema() {
|
get schema() {
|
||||||
return ActionSchemas["multi-preference-experiment"];
|
return ActionSchemas["multi-preference-experiment"];
|
||||||
}
|
}
|
||||||
|
@ -55,15 +45,6 @@ class PreferenceExperimentAction extends BaseAction {
|
||||||
this.seenExperimentNames = [];
|
this.seenExperimentNames = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
_preExecution() {
|
|
||||||
if (!shieldOptOutPref) {
|
|
||||||
this.log.info(
|
|
||||||
"User has opted out of preference experiments. Disabling this action."
|
|
||||||
);
|
|
||||||
this.disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async _run(recipe) {
|
async _run(recipe) {
|
||||||
const {
|
const {
|
||||||
branches,
|
branches,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
toolkit.jar:
|
toolkit.jar:
|
||||||
% resource normandy %res/normandy/
|
% resource normandy %res/normandy/
|
||||||
res/normandy/Normandy.jsm (./Normandy.jsm)
|
res/normandy/Normandy.jsm (./Normandy.jsm)
|
||||||
|
res/normandy/NormandyMigrations.jsm (./NormandyMigrations.jsm)
|
||||||
res/normandy/lib/ (./lib/*)
|
res/normandy/lib/ (./lib/*)
|
||||||
res/normandy/skin/ (./skin/*)
|
res/normandy/skin/ (./skin/*)
|
||||||
res/normandy/actions/ (./actions/*.jsm)
|
res/normandy/actions/ (./actions/*.jsm)
|
||||||
|
|
|
@ -39,8 +39,6 @@ const TIMER_NAME = "recipe-client-addon-run";
|
||||||
const REMOTE_SETTINGS_COLLECTION = "normandy-recipes";
|
const REMOTE_SETTINGS_COLLECTION = "normandy-recipes";
|
||||||
const PREF_CHANGED_TOPIC = "nsPref:changed";
|
const PREF_CHANGED_TOPIC = "nsPref:changed";
|
||||||
|
|
||||||
const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
|
|
||||||
|
|
||||||
const PREF_PREFIX = "app.normandy";
|
const PREF_PREFIX = "app.normandy";
|
||||||
const RUN_INTERVAL_PREF = `${PREF_PREFIX}.run_interval_seconds`;
|
const RUN_INTERVAL_PREF = `${PREF_PREFIX}.run_interval_seconds`;
|
||||||
const FIRST_RUN_PREF = `${PREF_PREFIX}.first_run`;
|
const FIRST_RUN_PREF = `${PREF_PREFIX}.first_run`;
|
||||||
|
@ -53,12 +51,7 @@ const LAZY_CLASSIFY_PREF = `${PREF_PREFIX}.experiments.lazy_classify`;
|
||||||
// see https://searchfox.org/mozilla-central/rev/11cfa0462/toolkit/components/timermanager/UpdateTimerManager.jsm#8
|
// see https://searchfox.org/mozilla-central/rev/11cfa0462/toolkit/components/timermanager/UpdateTimerManager.jsm#8
|
||||||
const TIMER_LAST_UPDATE_PREF = `app.update.lastUpdateTime.${TIMER_NAME}`;
|
const TIMER_LAST_UPDATE_PREF = `app.update.lastUpdateTime.${TIMER_NAME}`;
|
||||||
|
|
||||||
const PREFS_TO_WATCH = [
|
const PREFS_TO_WATCH = [RUN_INTERVAL_PREF, SHIELD_ENABLED_PREF, API_URL_PREF];
|
||||||
RUN_INTERVAL_PREF,
|
|
||||||
TELEMETRY_ENABLED_PREF,
|
|
||||||
SHIELD_ENABLED_PREF,
|
|
||||||
API_URL_PREF,
|
|
||||||
];
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "gRemoteSettingsClient", () => {
|
XPCOMUtils.defineLazyGetter(this, "gRemoteSettingsClient", () => {
|
||||||
return RemoteSettings(REMOTE_SETTINGS_COLLECTION, {
|
return RemoteSettings(REMOTE_SETTINGS_COLLECTION, {
|
||||||
|
@ -169,7 +162,6 @@ var RecipeRunner = {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// explicit fall-through
|
// explicit fall-through
|
||||||
case TELEMETRY_ENABLED_PREF:
|
|
||||||
case SHIELD_ENABLED_PREF:
|
case SHIELD_ENABLED_PREF:
|
||||||
case API_URL_PREF:
|
case API_URL_PREF:
|
||||||
this.checkPrefs();
|
this.checkPrefs();
|
||||||
|
@ -187,15 +179,6 @@ var RecipeRunner = {
|
||||||
},
|
},
|
||||||
|
|
||||||
checkPrefs() {
|
checkPrefs() {
|
||||||
// Only run if Unified Telemetry is enabled.
|
|
||||||
if (!Services.prefs.getBoolPref(TELEMETRY_ENABLED_PREF)) {
|
|
||||||
log.debug(
|
|
||||||
"Disabling RecipeRunner because Unified Telemetry is disabled."
|
|
||||||
);
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Services.prefs.getBoolPref(SHIELD_ENABLED_PREF)) {
|
if (!Services.prefs.getBoolPref(SHIELD_ENABLED_PREF)) {
|
||||||
log.debug(
|
log.debug(
|
||||||
`Disabling Shield because ${SHIELD_ENABLED_PREF} is set to false`
|
`Disabling Shield because ${SHIELD_ENABLED_PREF} is set to false`
|
||||||
|
@ -204,12 +187,6 @@ var RecipeRunner = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Services.policies.isAllowed("Shield")) {
|
|
||||||
log.debug("Disabling Shield because it's blocked by policy.");
|
|
||||||
this.disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiUrl = Services.prefs.getCharPref(API_URL_PREF);
|
const apiUrl = Services.prefs.getCharPref(API_URL_PREF);
|
||||||
if (!apiUrl) {
|
if (!apiUrl) {
|
||||||
log.warn(`Disabling Shield because ${API_URL_PREF} is not set.`);
|
log.warn(`Disabling Shield because ${API_URL_PREF} is not set.`);
|
||||||
|
|
|
@ -11,8 +11,6 @@ generated-files =
|
||||||
addons/normandydriver-a-2.0.xpi
|
addons/normandydriver-a-2.0.xpi
|
||||||
head = head.js
|
head = head.js
|
||||||
[browser_about_preferences.js]
|
[browser_about_preferences.js]
|
||||||
# Skip this test when FHR/Telemetry aren't available.
|
|
||||||
skip-if = !healthreport || !telemetry
|
|
||||||
[browser_about_studies.js]
|
[browser_about_studies.js]
|
||||||
[browser_actions_AddonStudyAction.js]
|
[browser_actions_AddonStudyAction.js]
|
||||||
[browser_actions_BranchedAddonStudyAction.js]
|
[browser_actions_BranchedAddonStudyAction.js]
|
||||||
|
@ -32,6 +30,7 @@ skip-if = (verify && (os == 'linux'))
|
||||||
[browser_Heartbeat.js]
|
[browser_Heartbeat.js]
|
||||||
[browser_LogManager.js]
|
[browser_LogManager.js]
|
||||||
[browser_Normandy.js]
|
[browser_Normandy.js]
|
||||||
|
[browser_NormandyMigrations.js]
|
||||||
[browser_PreferenceExperiments.js]
|
[browser_PreferenceExperiments.js]
|
||||||
[browser_PreferenceRollouts.js]
|
[browser_PreferenceRollouts.js]
|
||||||
[browser_RecipeRunner.js]
|
[browser_RecipeRunner.js]
|
||||||
|
|
|
@ -286,38 +286,3 @@ decorate_task(
|
||||||
ok(PreferenceRollouts.init.called, "startup calls PreferenceRollouts.init");
|
ok(PreferenceRollouts.init.called, "startup calls PreferenceRollouts.init");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(withMockPreferences, async function testPrefMigration(
|
|
||||||
mockPreferences
|
|
||||||
) {
|
|
||||||
const legacyPref = "extensions.shield-recipe-client.test";
|
|
||||||
const migratedPref = "app.normandy.test";
|
|
||||||
mockPreferences.set(legacyPref, 1);
|
|
||||||
|
|
||||||
ok(
|
|
||||||
Services.prefs.prefHasUserValue(legacyPref),
|
|
||||||
"Legacy pref should have a user value before running migration"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!Services.prefs.prefHasUserValue(migratedPref),
|
|
||||||
"Migrated pref should not have a user value before running migration"
|
|
||||||
);
|
|
||||||
|
|
||||||
Normandy.migrateShieldPrefs();
|
|
||||||
|
|
||||||
ok(
|
|
||||||
!Services.prefs.prefHasUserValue(legacyPref),
|
|
||||||
"Legacy pref should not have a user value after running migration"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
Services.prefs.prefHasUserValue(migratedPref),
|
|
||||||
"Migrated pref should have a user value after running migration"
|
|
||||||
);
|
|
||||||
is(
|
|
||||||
Services.prefs.getIntPref(migratedPref),
|
|
||||||
1,
|
|
||||||
"Value should have been migrated"
|
|
||||||
);
|
|
||||||
|
|
||||||
Services.prefs.clearUserPref(migratedPref);
|
|
||||||
});
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
ChromeUtils.import("resource://normandy/NormandyMigrations.jsm", this);
|
||||||
|
|
||||||
|
decorate_task(withMockPreferences, async function testApplyMigrations(
|
||||||
|
mockPreferences
|
||||||
|
) {
|
||||||
|
const migrationsAppliedPref = "app.normandy.migrationsApplied";
|
||||||
|
mockPreferences.set(migrationsAppliedPref, 0);
|
||||||
|
|
||||||
|
NormandyMigrations.applyAll();
|
||||||
|
|
||||||
|
is(
|
||||||
|
Services.prefs.getIntPref(migrationsAppliedPref),
|
||||||
|
NormandyMigrations.migrations.length,
|
||||||
|
"All migrations should have been applied"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
decorate_task(withMockPreferences, async function testPrefMigration(
|
||||||
|
mockPreferences
|
||||||
|
) {
|
||||||
|
const legacyPref = "extensions.shield-recipe-client.test";
|
||||||
|
const migratedPref = "app.normandy.test";
|
||||||
|
mockPreferences.set(legacyPref, 1);
|
||||||
|
|
||||||
|
ok(
|
||||||
|
Services.prefs.prefHasUserValue(legacyPref),
|
||||||
|
"Legacy pref should have a user value before running migration"
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
!Services.prefs.prefHasUserValue(migratedPref),
|
||||||
|
"Migrated pref should not have a user value before running migration"
|
||||||
|
);
|
||||||
|
|
||||||
|
NormandyMigrations.applyOne(0);
|
||||||
|
|
||||||
|
ok(
|
||||||
|
!Services.prefs.prefHasUserValue(legacyPref),
|
||||||
|
"Legacy pref should not have a user value after running migration"
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
Services.prefs.prefHasUserValue(migratedPref),
|
||||||
|
"Migrated pref should have a user value after running migration"
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
Services.prefs.getIntPref(migratedPref),
|
||||||
|
1,
|
||||||
|
"Value should have been migrated"
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref(migratedPref);
|
||||||
|
});
|
||||||
|
|
||||||
|
decorate_task(withMockPreferences, async function testMigration0(
|
||||||
|
mockPreferences
|
||||||
|
) {
|
||||||
|
const studiesEnabledPref = "app.shield.optoutstudies.enabled";
|
||||||
|
const healthReportUploadEnabledPref =
|
||||||
|
"datareporting.healthreport.uploadEnabled";
|
||||||
|
|
||||||
|
// Both enabled
|
||||||
|
mockPreferences.set(studiesEnabledPref, true);
|
||||||
|
mockPreferences.set(healthReportUploadEnabledPref, true);
|
||||||
|
NormandyMigrations.applyOne(1);
|
||||||
|
ok(
|
||||||
|
Services.prefs.getBoolPref(studiesEnabledPref),
|
||||||
|
"Studies should be enabled."
|
||||||
|
);
|
||||||
|
|
||||||
|
mockPreferences.cleanup();
|
||||||
|
|
||||||
|
// Telemetry disabled, studies enabled
|
||||||
|
mockPreferences.set(studiesEnabledPref, true);
|
||||||
|
mockPreferences.set(healthReportUploadEnabledPref, false);
|
||||||
|
NormandyMigrations.applyOne(1);
|
||||||
|
ok(
|
||||||
|
!Services.prefs.getBoolPref(studiesEnabledPref),
|
||||||
|
"Studies should be disabled."
|
||||||
|
);
|
||||||
|
|
||||||
|
mockPreferences.cleanup();
|
||||||
|
|
||||||
|
// Telemetry enabled, studies disabled
|
||||||
|
mockPreferences.set(studiesEnabledPref, false);
|
||||||
|
mockPreferences.set(healthReportUploadEnabledPref, true);
|
||||||
|
NormandyMigrations.applyOne(1);
|
||||||
|
ok(
|
||||||
|
!Services.prefs.getBoolPref(studiesEnabledPref),
|
||||||
|
"Studies should be disabled."
|
||||||
|
);
|
||||||
|
|
||||||
|
mockPreferences.cleanup();
|
||||||
|
|
||||||
|
// Both disabled
|
||||||
|
mockPreferences.set(studiesEnabledPref, false);
|
||||||
|
mockPreferences.set(healthReportUploadEnabledPref, false);
|
||||||
|
NormandyMigrations.applyOne(1);
|
||||||
|
ok(
|
||||||
|
!Services.prefs.getBoolPref(studiesEnabledPref),
|
||||||
|
"Studies should be disabled."
|
||||||
|
);
|
||||||
|
});
|
|
@ -590,7 +590,6 @@ decorate_task(
|
||||||
decorate_task(
|
decorate_task(
|
||||||
withPrefEnv({
|
withPrefEnv({
|
||||||
set: [
|
set: [
|
||||||
["datareporting.healthreport.uploadEnabled", true], // telemetry enabled
|
|
||||||
["app.normandy.dev_mode", false],
|
["app.normandy.dev_mode", false],
|
||||||
["app.normandy.first_run", false],
|
["app.normandy.first_run", false],
|
||||||
["app.normandy.enabled", true],
|
["app.normandy.enabled", true],
|
||||||
|
@ -648,26 +647,6 @@ decorate_task(
|
||||||
);
|
);
|
||||||
is(disableStub.callCount, 2, "Disable should not be called again");
|
is(disableStub.callCount, 2, "Disable should not be called again");
|
||||||
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["datareporting.healthreport.uploadEnabled", false]],
|
|
||||||
});
|
|
||||||
is(enableStub.callCount, 3, "Enable should not be called again");
|
|
||||||
is(
|
|
||||||
disableStub.callCount,
|
|
||||||
3,
|
|
||||||
"RecipeRunner should disable when telemetry is disabled"
|
|
||||||
);
|
|
||||||
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [["datareporting.healthreport.uploadEnabled", true]],
|
|
||||||
});
|
|
||||||
is(
|
|
||||||
enableStub.callCount,
|
|
||||||
4,
|
|
||||||
"RecipeRunner should re-enable when telemetry is enabled"
|
|
||||||
);
|
|
||||||
is(disableStub.callCount, 3, "Disable should not be called again");
|
|
||||||
|
|
||||||
is(
|
is(
|
||||||
runStub.callCount,
|
runStub.callCount,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
|
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
|
||||||
|
|
||||||
const OPT_OUT_PREF = "app.shield.optoutstudies.enabled";
|
const OPT_OUT_PREF = "app.shield.optoutstudies.enabled";
|
||||||
const FHR_PREF = "datareporting.healthreport.uploadEnabled";
|
|
||||||
|
|
||||||
function withPrivacyPrefs(testFunc) {
|
function withPrivacyPrefs(testFunc) {
|
||||||
return async (...args) =>
|
return async (...args) =>
|
||||||
|
@ -46,48 +45,13 @@ decorate_task(
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
withPrefEnv({
|
withPrefEnv({
|
||||||
set: [[FHR_PREF, true]],
|
set: [[OPT_OUT_PREF, true]],
|
||||||
}),
|
|
||||||
withPrivacyPrefs,
|
|
||||||
async function testEnabledOnLoad(browser) {
|
|
||||||
const checkbox = browser.contentDocument.getElementById(
|
|
||||||
"optOutStudiesEnabled"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!checkbox.disabled,
|
|
||||||
"Opt-out checkbox is enabled on load when the FHR pref is true"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
decorate_task(
|
|
||||||
withPrefEnv({
|
|
||||||
set: [[FHR_PREF, false]],
|
|
||||||
}),
|
|
||||||
withPrivacyPrefs,
|
|
||||||
async function testDisabledOnLoad(browser) {
|
|
||||||
const checkbox = browser.contentDocument.getElementById(
|
|
||||||
"optOutStudiesEnabled"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
checkbox.disabled,
|
|
||||||
"Opt-out checkbox is disabled on load when the FHR pref is false"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
decorate_task(
|
|
||||||
withPrefEnv({
|
|
||||||
set: [[FHR_PREF, true], [OPT_OUT_PREF, true]],
|
|
||||||
}),
|
}),
|
||||||
withPrivacyPrefs,
|
withPrivacyPrefs,
|
||||||
async function testCheckboxes(browser) {
|
async function testCheckboxes(browser) {
|
||||||
const optOutCheckbox = browser.contentDocument.getElementById(
|
const optOutCheckbox = browser.contentDocument.getElementById(
|
||||||
"optOutStudiesEnabled"
|
"optOutStudiesEnabled"
|
||||||
);
|
);
|
||||||
const fhrCheckbox = browser.contentDocument.getElementById(
|
|
||||||
"submitHealthReportBox"
|
|
||||||
);
|
|
||||||
|
|
||||||
optOutCheckbox.click();
|
optOutCheckbox.click();
|
||||||
ok(
|
ok(
|
||||||
|
@ -99,40 +63,12 @@ decorate_task(
|
||||||
Services.prefs.getBoolPref(OPT_OUT_PREF),
|
Services.prefs.getBoolPref(OPT_OUT_PREF),
|
||||||
"Checking the opt-out checkbox sets the pref to true."
|
"Checking the opt-out checkbox sets the pref to true."
|
||||||
);
|
);
|
||||||
|
|
||||||
fhrCheckbox.click();
|
|
||||||
ok(
|
|
||||||
!Services.prefs.getBoolPref(OPT_OUT_PREF),
|
|
||||||
"Unchecking the FHR checkbox sets the opt-out pref to false."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
optOutCheckbox.disabled,
|
|
||||||
"Unchecking the FHR checkbox disables the opt-out checkbox."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!optOutCheckbox.checked,
|
|
||||||
"Unchecking the FHR checkbox unchecks the opt-out checkbox."
|
|
||||||
);
|
|
||||||
|
|
||||||
fhrCheckbox.click();
|
|
||||||
ok(
|
|
||||||
Services.prefs.getBoolPref(OPT_OUT_PREF),
|
|
||||||
"Checking the FHR checkbox sets the opt-out pref to true."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!optOutCheckbox.disabled,
|
|
||||||
"Checking the FHR checkbox enables the opt-out checkbox."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
optOutCheckbox.checked,
|
|
||||||
"Checking the FHR checkbox checks the opt-out checkbox."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
withPrefEnv({
|
withPrefEnv({
|
||||||
set: [[FHR_PREF, true], [OPT_OUT_PREF, true]],
|
set: [[OPT_OUT_PREF, true]],
|
||||||
}),
|
}),
|
||||||
withPrivacyPrefs,
|
withPrivacyPrefs,
|
||||||
async function testPrefWatchers(browser) {
|
async function testPrefWatchers(browser) {
|
||||||
|
@ -150,34 +86,6 @@ decorate_task(
|
||||||
optOutCheckbox.checked,
|
optOutCheckbox.checked,
|
||||||
"Enabling the opt-out pref checks the opt-out checkbox."
|
"Enabling the opt-out pref checks the opt-out checkbox."
|
||||||
);
|
);
|
||||||
|
|
||||||
Services.prefs.setBoolPref(FHR_PREF, false);
|
|
||||||
ok(
|
|
||||||
!Services.prefs.getBoolPref(OPT_OUT_PREF),
|
|
||||||
"Disabling the FHR pref sets the opt-out pref to false."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
optOutCheckbox.disabled,
|
|
||||||
"Disabling the FHR pref disables the opt-out checkbox."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!optOutCheckbox.checked,
|
|
||||||
"Disabling the FHR pref unchecks the opt-out checkbox."
|
|
||||||
);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref(FHR_PREF, true);
|
|
||||||
ok(
|
|
||||||
Services.prefs.getBoolPref(OPT_OUT_PREF),
|
|
||||||
"Enabling the FHR pref sets the opt-out pref to true."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!optOutCheckbox.disabled,
|
|
||||||
"Enabling the FHR pref enables the opt-out checkbox."
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
optOutCheckbox.checked,
|
|
||||||
"Enabling the FHR pref checks the opt-out checkbox."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ function addonStudyRecipeFactory(overrides = {}) {
|
||||||
// Test that enroll is not called if recipe is already enrolled and update does nothing
|
// Test that enroll is not called if recipe is already enrolled and update does nothing
|
||||||
// if recipe is unchanged
|
// if recipe is unchanged
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([addonStudyFactory()]),
|
AddonStudies.withStudies([addonStudyFactory()]),
|
||||||
|
@ -72,6 +73,7 @@ decorate_task(
|
||||||
// Test that if the add-on fails to install, the database is cleaned up and the
|
// Test that if the add-on fails to install, the database is cleaned up and the
|
||||||
// error is correctly reported.
|
// error is correctly reported.
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -109,6 +111,7 @@ decorate_task(
|
||||||
|
|
||||||
// Ensure that the database is clean and error correctly reported if hash check fails
|
// Ensure that the database is clean and error correctly reported if hash check fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -149,6 +152,7 @@ decorate_task(
|
||||||
|
|
||||||
// Ensure that the database is clean and error correctly reported if there is a metadata mismatch
|
// Ensure that the database is clean and error correctly reported if there is a metadata mismatch
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -190,6 +194,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that in the case of a study add-on conflicting with a non-study add-on, the study does not enroll
|
// Test that in the case of a study add-on conflicting with a non-study add-on, the study does not enroll
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -244,6 +249,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test a successful enrollment
|
// Test a successful enrollment
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -333,6 +339,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test a successful update
|
// Test a successful update
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -412,6 +419,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when addon ID does not match
|
// Test update fails when addon ID does not match
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -473,6 +481,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when original addon does not exist
|
// Test update fails when original addon does not exist
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -536,6 +545,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when download fails
|
// Test update fails when download fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -598,6 +608,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when hash check fails
|
// Test update fails when hash check fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -661,6 +672,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails on downgrade when study version is greater than extension version
|
// Test update fails on downgrade when study version is greater than extension version
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -723,6 +735,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when there is a version mismatch with metadata
|
// Test update fails when there is a version mismatch with metadata
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -799,6 +812,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that unenrolling fails if the study doesn't exist
|
// Test that unenrolling fails if the study doesn't exist
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies(),
|
AddonStudies.withStudies(),
|
||||||
async function unenrollNonexistent(studies) {
|
async function unenrollNonexistent(studies) {
|
||||||
|
@ -813,6 +827,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that unenrolling an inactive experiment fails
|
// Test that unenrolling an inactive experiment fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([addonStudyFactory({ active: false })]),
|
AddonStudies.withStudies([addonStudyFactory({ active: false })]),
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -829,6 +844,7 @@ decorate_task(
|
||||||
// test a successful unenrollment
|
// test a successful unenrollment
|
||||||
const testStopId = "testStop@example.com";
|
const testStopId = "testStop@example.com";
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
addonStudyFactory({
|
addonStudyFactory({
|
||||||
|
@ -870,6 +886,7 @@ decorate_task(
|
||||||
|
|
||||||
// If the add-on for a study isn't installed, a warning should be logged, but the action is still successful
|
// If the add-on for a study isn't installed, a warning should be logged, but the action is still successful
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
addonStudyFactory({
|
addonStudyFactory({
|
||||||
|
@ -903,6 +920,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that the action respects the study opt-out
|
// Test that the action respects the study opt-out
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -938,6 +956,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that the action does not enroll paused recipes
|
// Test that the action does not enroll paused recipes
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -969,6 +988,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that the action updates paused recipes
|
// Test that the action updates paused recipes
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -1034,6 +1054,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that update method works for legacy studies with no hash
|
// Test that update method works for legacy studies with no hash
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -1117,6 +1138,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that enroll is not called if recipe is already enrolled
|
// Test that enroll is not called if recipe is already enrolled
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([addonStudyFactory()]),
|
AddonStudies.withStudies([addonStudyFactory()]),
|
||||||
async function enrollTwiceFail([study]) {
|
async function enrollTwiceFail([study]) {
|
||||||
|
|
|
@ -74,6 +74,7 @@ function recipeFromStudy(study, overrides = {}) {
|
||||||
// Test that enroll is not called if recipe is already enrolled and update does nothing
|
// Test that enroll is not called if recipe is already enrolled and update does nothing
|
||||||
// if recipe is unchanged
|
// if recipe is unchanged
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([branchedAddonStudyFactory()]),
|
AddonStudies.withStudies([branchedAddonStudyFactory()]),
|
||||||
|
@ -107,6 +108,7 @@ decorate_task(
|
||||||
// Test that if the add-on fails to install, the database is cleaned up and the
|
// Test that if the add-on fails to install, the database is cleaned up and the
|
||||||
// error is correctly reported.
|
// error is correctly reported.
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -147,6 +149,7 @@ decorate_task(
|
||||||
|
|
||||||
// Ensure that the database is clean and error correctly reported if hash check fails
|
// Ensure that the database is clean and error correctly reported if hash check fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -184,6 +187,7 @@ decorate_task(
|
||||||
|
|
||||||
// Ensure that the database is clean and error correctly reported if there is a metadata mismatch
|
// Ensure that the database is clean and error correctly reported if there is a metadata mismatch
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -221,6 +225,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that in the case of a study add-on conflicting with a non-study add-on, the study does not enroll
|
// Test that in the case of a study add-on conflicting with a non-study add-on, the study does not enroll
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -271,6 +276,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test a successful update
|
// Test a successful update
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -347,6 +353,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when addon ID does not match
|
// Test update fails when addon ID does not match
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -400,6 +407,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when original addon does not exist
|
// Test update fails when original addon does not exist
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -455,6 +463,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when download fails
|
// Test update fails when download fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -509,6 +518,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when hash check fails
|
// Test update fails when hash check fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -564,6 +574,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails on downgrade when study version is greater than extension version
|
// Test update fails on downgrade when study version is greater than extension version
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -618,6 +629,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test update fails when there is a version mismatch with metadata
|
// Test update fails when there is a version mismatch with metadata
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -686,6 +698,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that unenrolling fails if the study doesn't exist
|
// Test that unenrolling fails if the study doesn't exist
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies(),
|
AddonStudies.withStudies(),
|
||||||
async function unenrollNonexistent(studies) {
|
async function unenrollNonexistent(studies) {
|
||||||
|
@ -700,6 +713,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that unenrolling an inactive experiment fails
|
// Test that unenrolling an inactive experiment fails
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([branchedAddonStudyFactory({ active: false })]),
|
AddonStudies.withStudies([branchedAddonStudyFactory({ active: false })]),
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -716,6 +730,7 @@ decorate_task(
|
||||||
// test a successful unenrollment
|
// test a successful unenrollment
|
||||||
const testStopId = "testStop@example.com";
|
const testStopId = "testStop@example.com";
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
branchedAddonStudyFactory({
|
branchedAddonStudyFactory({
|
||||||
|
@ -769,6 +784,7 @@ decorate_task(
|
||||||
|
|
||||||
// If the add-on for a study isn't installed, a warning should be logged, but the action is still successful
|
// If the add-on for a study isn't installed, a warning should be logged, but the action is still successful
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
branchedAddonStudyFactory({
|
branchedAddonStudyFactory({
|
||||||
|
@ -801,6 +817,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that the action respects the study opt-out
|
// Test that the action respects the study opt-out
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -836,6 +853,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that the action does not enroll paused recipes
|
// Test that the action does not enroll paused recipes
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -867,6 +885,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that the action updates paused recipes
|
// Test that the action updates paused recipes
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([
|
AddonStudies.withStudies([
|
||||||
|
@ -924,6 +943,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that unenroll called if the study is no longer sent from the server
|
// Test that unenroll called if the study is no longer sent from the server
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
AddonStudies.withStudies([branchedAddonStudyFactory()]),
|
AddonStudies.withStudies([branchedAddonStudyFactory()]),
|
||||||
async function unenroll([study]) {
|
async function unenroll([study]) {
|
||||||
|
@ -942,6 +962,7 @@ decorate_task(
|
||||||
// A test function that will be parameterized over the argument "branch" below.
|
// A test function that will be parameterized over the argument "branch" below.
|
||||||
// Mocks the branch selector, and then tests that the user correctly gets enrolled in that branch.
|
// Mocks the branch selector, and then tests that the user correctly gets enrolled in that branch.
|
||||||
const successEnrollBranchedTest = decorate(
|
const successEnrollBranchedTest = decorate(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
@ -1070,6 +1091,7 @@ add_task(() => successEnrollBranchedTest("b"));
|
||||||
|
|
||||||
// If the enrolled branch no longer exists, unenroll
|
// If the enrolled branch no longer exists, unenroll
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
AddonStudies.withStudies([branchedAddonStudyFactory()]),
|
AddonStudies.withStudies([branchedAddonStudyFactory()]),
|
||||||
|
@ -1142,6 +1164,7 @@ decorate_task(
|
||||||
|
|
||||||
// Test that branches without an add-on can be enrolled and unenrolled succesfully.
|
// Test that branches without an add-on can be enrolled and unenrolled succesfully.
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
ensureAddonCleanup,
|
ensureAddonCleanup,
|
||||||
withMockNormandyApi,
|
withMockNormandyApi,
|
||||||
withSendEventStub,
|
withSendEventStub,
|
||||||
|
|
|
@ -63,6 +63,7 @@ function preferenceExperimentFactory(args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(Uptake, "reportRecipe"),
|
withStub(Uptake, "reportRecipe"),
|
||||||
async function run_without_errors(reportRecipe) {
|
async function run_without_errors(reportRecipe) {
|
||||||
const action = new PreferenceExperimentAction();
|
const action = new PreferenceExperimentAction();
|
||||||
|
@ -76,6 +77,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(Uptake, "reportRecipe"),
|
withStub(Uptake, "reportRecipe"),
|
||||||
withStub(Uptake, "reportAction"),
|
withStub(Uptake, "reportAction"),
|
||||||
withPrefEnv({ set: [["app.shield.optoutstudies.enabled", false]] }),
|
withPrefEnv({ set: [["app.shield.optoutstudies.enabled", false]] }),
|
||||||
|
@ -86,8 +88,9 @@ decorate_task(
|
||||||
const recipe = preferenceExperimentFactory();
|
const recipe = preferenceExperimentFactory();
|
||||||
await action.runRecipe(recipe);
|
await action.runRecipe(recipe);
|
||||||
|
|
||||||
Assert.deepEqual(action.log.info.args, [
|
Assert.ok(action.log.debug.args.length === 1);
|
||||||
["User has opted out of preference experiments. Disabling this action."],
|
Assert.deepEqual(action.log.debug.args[0], [
|
||||||
|
"User has opted-out of opt-out experiments, disabling action.",
|
||||||
]);
|
]);
|
||||||
Assert.deepEqual(action.log.warn.args, [
|
Assert.deepEqual(action.log.warn.args, [
|
||||||
[
|
[
|
||||||
|
@ -97,10 +100,9 @@ decorate_task(
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await action.finalize();
|
await action.finalize();
|
||||||
Assert.deepEqual(action.log.debug.args, [
|
Assert.ok(action.log.debug.args.length === 2);
|
||||||
[
|
Assert.deepEqual(action.log.debug.args[1], [
|
||||||
"Skipping post-execution hook for PreferenceExperimentAction because it is disabled.",
|
"Skipping post-execution hook for PreferenceExperimentAction because it is disabled.",
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
Assert.deepEqual(reportRecipe.args, [
|
Assert.deepEqual(reportRecipe.args, [
|
||||||
[recipe, Uptake.RECIPE_ACTION_DISABLED],
|
[recipe, Uptake.RECIPE_ACTION_DISABLED],
|
||||||
|
@ -110,6 +112,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "start"),
|
withStub(PreferenceExperiments, "start"),
|
||||||
PreferenceExperiments.withMockExperiments([]),
|
PreferenceExperiments.withMockExperiments([]),
|
||||||
async function enroll_user_if_never_been_in_experiment(startStub) {
|
async function enroll_user_if_never_been_in_experiment(startStub) {
|
||||||
|
@ -172,6 +175,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "markLastSeen"),
|
withStub(PreferenceExperiments, "markLastSeen"),
|
||||||
PreferenceExperiments.withMockExperiments([{ name: "test", expired: false }]),
|
PreferenceExperiments.withMockExperiments([{ name: "test", expired: false }]),
|
||||||
async function markSeen_if_experiment_active(markLastSeenStub) {
|
async function markSeen_if_experiment_active(markLastSeenStub) {
|
||||||
|
@ -188,6 +192,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "markLastSeen"),
|
withStub(PreferenceExperiments, "markLastSeen"),
|
||||||
PreferenceExperiments.withMockExperiments([{ name: "test", expired: true }]),
|
PreferenceExperiments.withMockExperiments([{ name: "test", expired: true }]),
|
||||||
async function dont_markSeen_if_experiment_expired(markLastSeenStub) {
|
async function dont_markSeen_if_experiment_expired(markLastSeenStub) {
|
||||||
|
@ -204,6 +209,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "start"),
|
withStub(PreferenceExperiments, "start"),
|
||||||
async function do_nothing_if_enrollment_paused(startStub) {
|
async function do_nothing_if_enrollment_paused(startStub) {
|
||||||
const action = new PreferenceExperimentAction();
|
const action = new PreferenceExperimentAction();
|
||||||
|
@ -219,6 +225,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "stop"),
|
withStub(PreferenceExperiments, "stop"),
|
||||||
PreferenceExperiments.withMockExperiments([
|
PreferenceExperiments.withMockExperiments([
|
||||||
{ name: "seen", expired: false, actionName: "PreferenceExperimentAction" },
|
{ name: "seen", expired: false, actionName: "PreferenceExperimentAction" },
|
||||||
|
@ -244,6 +251,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "stop"),
|
withStub(PreferenceExperiments, "stop"),
|
||||||
PreferenceExperiments.withMockExperiments([
|
PreferenceExperiments.withMockExperiments([
|
||||||
{
|
{
|
||||||
|
@ -275,6 +283,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "start"),
|
withStub(PreferenceExperiments, "start"),
|
||||||
withStub(Uptake, "reportRecipe"),
|
withStub(Uptake, "reportRecipe"),
|
||||||
PreferenceExperiments.withMockExperiments([
|
PreferenceExperiments.withMockExperiments([
|
||||||
|
@ -317,6 +326,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "start"),
|
withStub(PreferenceExperiments, "start"),
|
||||||
PreferenceExperiments.withMockExperiments([]),
|
PreferenceExperiments.withMockExperiments([]),
|
||||||
async function experimentType_with_isHighPopulation_false(startStub) {
|
async function experimentType_with_isHighPopulation_false(startStub) {
|
||||||
|
@ -333,6 +343,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperiments, "start"),
|
withStub(PreferenceExperiments, "start"),
|
||||||
PreferenceExperiments.withMockExperiments([]),
|
PreferenceExperiments.withMockExperiments([]),
|
||||||
async function experimentType_with_isHighPopulation_true(startStub) {
|
async function experimentType_with_isHighPopulation_true(startStub) {
|
||||||
|
@ -349,6 +360,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(Sampling, "ratioSample"),
|
withStub(Sampling, "ratioSample"),
|
||||||
async function chooseBranch_uses_ratioSample(ratioSampleStub) {
|
async function chooseBranch_uses_ratioSample(ratioSampleStub) {
|
||||||
ratioSampleStub.returns(Promise.resolve(1));
|
ratioSampleStub.returns(Promise.resolve(1));
|
||||||
|
@ -388,6 +400,7 @@ decorate_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withMockPreferences,
|
withMockPreferences,
|
||||||
PreferenceExperiments.withMockExperiments([]),
|
PreferenceExperiments.withMockExperiments([]),
|
||||||
async function integration_test_enroll_and_unenroll(prefs) {
|
async function integration_test_enroll_and_unenroll(prefs) {
|
||||||
|
|
|
@ -42,6 +42,7 @@ function preferenceExperimentFactory(args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
decorate_task(
|
decorate_task(
|
||||||
|
withStudiesEnabled,
|
||||||
withStub(PreferenceExperimentAction.prototype, "_run"),
|
withStub(PreferenceExperimentAction.prototype, "_run"),
|
||||||
PreferenceExperiments.withMockExperiments([]),
|
PreferenceExperiments.withMockExperiments([]),
|
||||||
async function enroll_user_if_never_been_in_experiment(runStub) {
|
async function enroll_user_if_never_been_in_experiment(runStub) {
|
||||||
|
|
|
@ -240,6 +240,19 @@ this.withPrefEnv = function(inPrefs) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.withStudiesEnabled = function(testFunc) {
|
||||||
|
return async function inner(...args) {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["app.shield.optoutstudies.enabled", true]],
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await testFunc(...args);
|
||||||
|
} finally {
|
||||||
|
await SpecialPowers.popPrefEnv();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine a list of functions right to left. The rightmost function is passed
|
* Combine a list of functions right to left. The rightmost function is passed
|
||||||
* to the preceding function as the argument; the result of this is passed to
|
* to the preceding function as the argument; the result of this is passed to
|
||||||
|
|
|
@ -187,6 +187,13 @@ this.AppConstants = Object.freeze({
|
||||||
false,
|
false,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
MOZ_NORMANDY:
|
||||||
|
#ifdef MOZ_NORMANDY
|
||||||
|
true,
|
||||||
|
#else
|
||||||
|
false,
|
||||||
|
#endif
|
||||||
|
|
||||||
MOZ_MAINTENANCE_SERVICE:
|
MOZ_MAINTENANCE_SERVICE:
|
||||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -617,6 +617,11 @@ project_flag('MOZ_SERVICES_HEALTHREPORT',
|
||||||
set_for_old_configure=True,
|
set_for_old_configure=True,
|
||||||
set_as_define=True)
|
set_as_define=True)
|
||||||
|
|
||||||
|
project_flag('MOZ_NORMANDY',
|
||||||
|
help='Enable Normandy recipe runner',
|
||||||
|
set_for_old_configure=True,
|
||||||
|
set_as_define=True)
|
||||||
|
|
||||||
project_flag('MOZ_SERVICES_SYNC',
|
project_flag('MOZ_SERVICES_SYNC',
|
||||||
help='Build Sync Services if required')
|
help='Build Sync Services if required')
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ const kIfdefStateForLinting = {
|
||||||
MOZ_DATA_REPORTING: true,
|
MOZ_DATA_REPORTING: true,
|
||||||
MOZ_TELEMETRY_REPORTING: true,
|
MOZ_TELEMETRY_REPORTING: true,
|
||||||
MOZ_CRASHREPORTER: true,
|
MOZ_CRASHREPORTER: true,
|
||||||
|
MOZ_NORMANDY: true,
|
||||||
MOZ_MAINTENANCE_SERVICE: true,
|
MOZ_MAINTENANCE_SERVICE: true,
|
||||||
HAVE_SHELL_SERVICE: true,
|
HAVE_SHELL_SERVICE: true,
|
||||||
MENUBAR_CAN_AUTOHIDE: true,
|
MENUBAR_CAN_AUTOHIDE: true,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче