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:
rdalal 2019-08-06 23:54:34 +00:00
Родитель 9f979c6057
Коммит 43acd674ea
28 изменённых файлов: 457 добавлений и 310 удалений

Просмотреть файл

@ -1237,7 +1237,9 @@ BrowserGlue.prototype = {
"resource:///modules/themes/dark/"
);
Normandy.init();
if (AppConstants.MOZ_NORMANDY) {
Normandy.init();
}
SaveToPocket.init();
Services.obs.notifyObservers(null, "browser-ui-startup-complete");

Просмотреть файл

@ -7,17 +7,41 @@ add_task(async function test_policy_disable_shield() {
const { RecipeRunner } = ChromeUtils.import(
"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({
set: [
["app.normandy.api_url", "https://localhost/selfsupport-dummy/"],
["datareporting.healthreport.uploadEnabled", true],
["app.shield.optoutstudies.enabled", true],
],
});
ok(RecipeRunner, "RecipeRunner exists");
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({
policies: {
@ -26,5 +50,19 @@ add_task(async function test_policy_disable_shield() {
});
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"
data-l10n-id="collection-health-report-link"/>
<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">
<checkbox id="addonRecommendationEnabled"
class="tail-with-learn-more"
@ -855,6 +844,19 @@
data-l10n-id="collection-health-report-disabled"/>
#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
<hbox align="center">
<checkbox id="automaticallySubmitCrashesBox"

Просмотреть файл

@ -604,7 +604,9 @@ var gPrivacyPane = {
"command",
gPrivacyPane.updateSubmitHealthReport
);
this.initOptOutStudyCheckbox();
if (AppConstants.MOZ_NORMANDY) {
this.initOptOutStudyCheckbox();
}
this.initAddonRecommendationsCheckbox();
}
this._initA11yState();
@ -2140,14 +2142,11 @@ var gPrivacyPane = {
* handles events coming from the UI for it.
*/
initOptOutStudyCheckbox(doc) {
const allowedByPolicy = Services.policies.isAllowed("Shield");
// The checkbox should be disabled if any of the below are true. This
// prevents the user from changing the value in the box.
//
// * the policy forbids shield
// * the Shield Study preference is locked
// * the FHR pref is false
// * Normandy is disabled
//
// The checkbox should match the value of the preference only if all of
// these are true. Otherwise, the checkbox should remain unchecked. This
@ -2155,16 +2154,27 @@ var gPrivacyPane = {
// so showing a checkbox would be confusing.
//
// * the policy allows Shield
// * the FHR pref is true
// * Normandy is enabled
dataCollectionCheckboxHandler({
checkbox: document.getElementById("optOutStudiesEnabled"),
matchPref: () =>
allowedByPolicy &&
Services.prefs.getBoolPref(PREF_NORMANDY_ENABLED, false),
isDisabled: () => !allowedByPolicy,
pref: PREF_OPT_OUT_STUDIES_ENABLED,
});
const allowedByPolicy = Services.policies.isAllowed("Shield");
const checkbox = document.getElementById("optOutStudiesEnabled");
if (
allowedByPolicy &&
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() {

Просмотреть файл

@ -9,6 +9,7 @@ imply_option('MOZ_SERVICES_HEALTHREPORT', True)
imply_option('MOZ_SERVICES_SYNC', True)
imply_option('MOZ_DEDICATED_PROFILES', True)
imply_option('MOZ_BLOCK_PROFILE_DOWNGRADE', True)
imply_option('MOZ_NORMANDY', True)
with only_when(target_is_linux & compile_environment):
option(env='MOZ_NO_PIE_COMPAT',

Просмотреть файл

@ -121,7 +121,7 @@ set_define('FENNEC_NIGHTLY', depends_if('FENNEC_NIGHTLY')(lambda _: True))
def fennec_nightly(nightly):
return bool(nightly)
imply_option('MOZ_NORMANDY', False)
imply_option('MOZ_SERVICES_HEALTHREPORT', True)
imply_option('MOZ_ANDROID_HISTORY', 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 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
if test -n "$MOZ_TELEMETRY_REPORTING" || test -n "$MOZ_SERVICES_HEALTHREPORT" || test -n "$MOZ_CRASHREPORTER" || test -n "$MOZ_NORMANDY"; then
MOZ_DATA_REPORTING=1
AC_DEFINE(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['pgo'] = substs.get('MOZ_PGO') == '1'
d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER'))
d['normandy'] = substs.get('MOZ_NORMANDY') == '1'
d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING'))
d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1'

Просмотреть файл

@ -14,6 +14,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
AddonStudies: "resource://normandy/lib/AddonStudies.jsm",
CleanupManager: "resource://normandy/lib/CleanupManager.jsm",
LogManager: "resource://normandy/lib/LogManager.jsm",
NormandyMigrations: "resource://normandy/NormandyMigrations.jsm",
PreferenceExperiments: "resource://normandy/lib/PreferenceExperiments.jsm",
PreferenceRollouts: "resource://normandy/lib/PreferenceRollouts.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 PREF_PREFIX = "app.normandy";
const LEGACY_PREF_PREFIX = "extensions.shield-recipe-client";
const STARTUP_EXPERIMENT_PREFS_BRANCH = `${PREF_PREFIX}.startupExperimentPrefs.`;
const STARTUP_ROLLOUT_PREFS_BRANCH = `${PREF_PREFIX}.startupRolloutPrefs.`;
const PREF_LOGGING_LEVEL = `${PREF_PREFIX}.logging.level`;
@ -44,7 +44,7 @@ var Normandy = {
init() {
// Initialization that needs to happen before the first paint on startup.
this.migrateShieldPrefs();
NormandyMigrations.applyAll();
this.rolloutPrefsChanged = this.applyStartupPrefs(
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
* 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(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { BaseAction } = ChromeUtils.import(
"resource://normandy/actions/BaseAction.jsm"
const { BaseStudyAction } = ChromeUtils.import(
"resource://normandy/actions/BaseStudyAction.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
@ -33,8 +33,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
var EXPORTED_SYMBOLS = ["BranchedAddonStudyAction"];
const OPT_OUT_STUDIES_ENABLED_PREF = "app.shield.optoutstudies.enabled";
class AddonStudyEnrollError extends Error {
/**
* @param {string} studyName
@ -115,7 +113,7 @@ class AddonStudyUpdateError extends Error {
}
}
class BranchedAddonStudyAction extends BaseAction {
class BranchedAddonStudyAction extends BaseStudyAction {
get schema() {
return ActionSchemas["branched-addon-study"];
}
@ -125,23 +123,6 @@ class BranchedAddonStudyAction extends BaseAction {
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
* client. It is responsible for:

Просмотреть файл

@ -4,11 +4,8 @@
"use strict";
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { BaseAction } = ChromeUtils.import(
"resource://normandy/actions/BaseAction.jsm"
const { BaseStudyAction } = ChromeUtils.import(
"resource://normandy/actions/BaseStudyAction.jsm"
);
ChromeUtils.defineModuleGetter(
this,
@ -30,13 +27,6 @@ ChromeUtils.defineModuleGetter(
"PreferenceExperiments",
"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"];
@ -45,7 +35,7 @@ var EXPORTED_SYMBOLS = ["PreferenceExperimentAction"];
* user to an experiment branch and modify a preference temporarily to
* measure how it affects Firefox via Telemetry.
*/
class PreferenceExperimentAction extends BaseAction {
class PreferenceExperimentAction extends BaseStudyAction {
get schema() {
return ActionSchemas["multi-preference-experiment"];
}
@ -55,15 +45,6 @@ class PreferenceExperimentAction extends BaseAction {
this.seenExperimentNames = [];
}
_preExecution() {
if (!shieldOptOutPref) {
this.log.info(
"User has opted out of preference experiments. Disabling this action."
);
this.disable();
}
}
async _run(recipe) {
const {
branches,

Просмотреть файл

@ -5,6 +5,7 @@
toolkit.jar:
% resource normandy %res/normandy/
res/normandy/Normandy.jsm (./Normandy.jsm)
res/normandy/NormandyMigrations.jsm (./NormandyMigrations.jsm)
res/normandy/lib/ (./lib/*)
res/normandy/skin/ (./skin/*)
res/normandy/actions/ (./actions/*.jsm)

Просмотреть файл

@ -39,8 +39,6 @@ const TIMER_NAME = "recipe-client-addon-run";
const REMOTE_SETTINGS_COLLECTION = "normandy-recipes";
const PREF_CHANGED_TOPIC = "nsPref:changed";
const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
const PREF_PREFIX = "app.normandy";
const RUN_INTERVAL_PREF = `${PREF_PREFIX}.run_interval_seconds`;
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
const TIMER_LAST_UPDATE_PREF = `app.update.lastUpdateTime.${TIMER_NAME}`;
const PREFS_TO_WATCH = [
RUN_INTERVAL_PREF,
TELEMETRY_ENABLED_PREF,
SHIELD_ENABLED_PREF,
API_URL_PREF,
];
const PREFS_TO_WATCH = [RUN_INTERVAL_PREF, SHIELD_ENABLED_PREF, API_URL_PREF];
XPCOMUtils.defineLazyGetter(this, "gRemoteSettingsClient", () => {
return RemoteSettings(REMOTE_SETTINGS_COLLECTION, {
@ -169,7 +162,6 @@ var RecipeRunner = {
break;
// explicit fall-through
case TELEMETRY_ENABLED_PREF:
case SHIELD_ENABLED_PREF:
case API_URL_PREF:
this.checkPrefs();
@ -187,15 +179,6 @@ var RecipeRunner = {
},
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)) {
log.debug(
`Disabling Shield because ${SHIELD_ENABLED_PREF} is set to false`
@ -204,12 +187,6 @@ var RecipeRunner = {
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);
if (!apiUrl) {
log.warn(`Disabling Shield because ${API_URL_PREF} is not set.`);

Просмотреть файл

@ -11,8 +11,6 @@ generated-files =
addons/normandydriver-a-2.0.xpi
head = head.js
[browser_about_preferences.js]
# Skip this test when FHR/Telemetry aren't available.
skip-if = !healthreport || !telemetry
[browser_about_studies.js]
[browser_actions_AddonStudyAction.js]
[browser_actions_BranchedAddonStudyAction.js]
@ -32,6 +30,7 @@ skip-if = (verify && (os == 'linux'))
[browser_Heartbeat.js]
[browser_LogManager.js]
[browser_Normandy.js]
[browser_NormandyMigrations.js]
[browser_PreferenceExperiments.js]
[browser_PreferenceRollouts.js]
[browser_RecipeRunner.js]

Просмотреть файл

@ -286,38 +286,3 @@ decorate_task(
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(
withPrefEnv({
set: [
["datareporting.healthreport.uploadEnabled", true], // telemetry enabled
["app.normandy.dev_mode", false],
["app.normandy.first_run", false],
["app.normandy.enabled", true],
@ -648,26 +647,6 @@ decorate_task(
);
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(
runStub.callCount,
0,

Просмотреть файл

@ -3,7 +3,6 @@
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
const OPT_OUT_PREF = "app.shield.optoutstudies.enabled";
const FHR_PREF = "datareporting.healthreport.uploadEnabled";
function withPrivacyPrefs(testFunc) {
return async (...args) =>
@ -46,48 +45,13 @@ decorate_task(
decorate_task(
withPrefEnv({
set: [[FHR_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]],
set: [[OPT_OUT_PREF, true]],
}),
withPrivacyPrefs,
async function testCheckboxes(browser) {
const optOutCheckbox = browser.contentDocument.getElementById(
"optOutStudiesEnabled"
);
const fhrCheckbox = browser.contentDocument.getElementById(
"submitHealthReportBox"
);
optOutCheckbox.click();
ok(
@ -99,40 +63,12 @@ decorate_task(
Services.prefs.getBoolPref(OPT_OUT_PREF),
"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(
withPrefEnv({
set: [[FHR_PREF, true], [OPT_OUT_PREF, true]],
set: [[OPT_OUT_PREF, true]],
}),
withPrivacyPrefs,
async function testPrefWatchers(browser) {
@ -150,34 +86,6 @@ decorate_task(
optOutCheckbox.checked,
"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
// if recipe is unchanged
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
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
// error is correctly reported.
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -109,6 +111,7 @@ decorate_task(
// Ensure that the database is clean and error correctly reported if hash check fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -149,6 +152,7 @@ decorate_task(
// Ensure that the database is clean and error correctly reported if there is a metadata mismatch
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
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
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -244,6 +249,7 @@ decorate_task(
// Test a successful enrollment
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -333,6 +339,7 @@ decorate_task(
// Test a successful update
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -412,6 +419,7 @@ decorate_task(
// Test update fails when addon ID does not match
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -473,6 +481,7 @@ decorate_task(
// Test update fails when original addon does not exist
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -536,6 +545,7 @@ decorate_task(
// Test update fails when download fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -598,6 +608,7 @@ decorate_task(
// Test update fails when hash check fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -661,6 +672,7 @@ decorate_task(
// Test update fails on downgrade when study version is greater than extension version
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -723,6 +735,7 @@ decorate_task(
// Test update fails when there is a version mismatch with metadata
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -799,6 +812,7 @@ decorate_task(
// Test that unenrolling fails if the study doesn't exist
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies(),
async function unenrollNonexistent(studies) {
@ -813,6 +827,7 @@ decorate_task(
// Test that unenrolling an inactive experiment fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([addonStudyFactory({ active: false })]),
withSendEventStub,
@ -829,6 +844,7 @@ decorate_task(
// test a successful unenrollment
const testStopId = "testStop@example.com";
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([
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
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([
addonStudyFactory({
@ -903,6 +920,7 @@ decorate_task(
// Test that the action respects the study opt-out
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -938,6 +956,7 @@ decorate_task(
// Test that the action does not enroll paused recipes
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -969,6 +988,7 @@ decorate_task(
// Test that the action updates paused recipes
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -1034,6 +1054,7 @@ decorate_task(
// Test that update method works for legacy studies with no hash
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -1117,6 +1138,7 @@ decorate_task(
// Test that enroll is not called if recipe is already enrolled
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([addonStudyFactory()]),
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
// if recipe is unchanged
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
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
// error is correctly reported.
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -147,6 +149,7 @@ decorate_task(
// Ensure that the database is clean and error correctly reported if hash check fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -184,6 +187,7 @@ decorate_task(
// Ensure that the database is clean and error correctly reported if there is a metadata mismatch
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
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
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -271,6 +276,7 @@ decorate_task(
// Test a successful update
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -347,6 +353,7 @@ decorate_task(
// Test update fails when addon ID does not match
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -400,6 +407,7 @@ decorate_task(
// Test update fails when original addon does not exist
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -455,6 +463,7 @@ decorate_task(
// Test update fails when download fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -509,6 +518,7 @@ decorate_task(
// Test update fails when hash check fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -564,6 +574,7 @@ decorate_task(
// Test update fails on downgrade when study version is greater than extension version
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -618,6 +629,7 @@ decorate_task(
// Test update fails when there is a version mismatch with metadata
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -686,6 +698,7 @@ decorate_task(
// Test that unenrolling fails if the study doesn't exist
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies(),
async function unenrollNonexistent(studies) {
@ -700,6 +713,7 @@ decorate_task(
// Test that unenrolling an inactive experiment fails
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([branchedAddonStudyFactory({ active: false })]),
withSendEventStub,
@ -716,6 +730,7 @@ decorate_task(
// test a successful unenrollment
const testStopId = "testStop@example.com";
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([
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
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([
branchedAddonStudyFactory({
@ -801,6 +817,7 @@ decorate_task(
// Test that the action respects the study opt-out
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -836,6 +853,7 @@ decorate_task(
// Test that the action does not enroll paused recipes
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -867,6 +885,7 @@ decorate_task(
// Test that the action updates paused recipes
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([
@ -924,6 +943,7 @@ decorate_task(
// Test that unenroll called if the study is no longer sent from the server
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
AddonStudies.withStudies([branchedAddonStudyFactory()]),
async function unenroll([study]) {
@ -942,6 +962,7 @@ decorate_task(
// 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.
const successEnrollBranchedTest = decorate(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,
@ -1070,6 +1091,7 @@ add_task(() => successEnrollBranchedTest("b"));
// If the enrolled branch no longer exists, unenroll
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
AddonStudies.withStudies([branchedAddonStudyFactory()]),
@ -1142,6 +1164,7 @@ decorate_task(
// Test that branches without an add-on can be enrolled and unenrolled succesfully.
decorate_task(
withStudiesEnabled,
ensureAddonCleanup,
withMockNormandyApi,
withSendEventStub,

Просмотреть файл

@ -63,6 +63,7 @@ function preferenceExperimentFactory(args) {
}
decorate_task(
withStudiesEnabled,
withStub(Uptake, "reportRecipe"),
async function run_without_errors(reportRecipe) {
const action = new PreferenceExperimentAction();
@ -76,6 +77,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(Uptake, "reportRecipe"),
withStub(Uptake, "reportAction"),
withPrefEnv({ set: [["app.shield.optoutstudies.enabled", false]] }),
@ -86,8 +88,9 @@ decorate_task(
const recipe = preferenceExperimentFactory();
await action.runRecipe(recipe);
Assert.deepEqual(action.log.info.args, [
["User has opted out of preference experiments. Disabling this action."],
Assert.ok(action.log.debug.args.length === 1);
Assert.deepEqual(action.log.debug.args[0], [
"User has opted-out of opt-out experiments, disabling action.",
]);
Assert.deepEqual(action.log.warn.args, [
[
@ -97,10 +100,9 @@ decorate_task(
]);
await action.finalize();
Assert.deepEqual(action.log.debug.args, [
[
"Skipping post-execution hook for PreferenceExperimentAction because it is disabled.",
],
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.",
]);
Assert.deepEqual(reportRecipe.args, [
[recipe, Uptake.RECIPE_ACTION_DISABLED],
@ -110,6 +112,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "start"),
PreferenceExperiments.withMockExperiments([]),
async function enroll_user_if_never_been_in_experiment(startStub) {
@ -172,6 +175,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "markLastSeen"),
PreferenceExperiments.withMockExperiments([{ name: "test", expired: false }]),
async function markSeen_if_experiment_active(markLastSeenStub) {
@ -188,6 +192,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "markLastSeen"),
PreferenceExperiments.withMockExperiments([{ name: "test", expired: true }]),
async function dont_markSeen_if_experiment_expired(markLastSeenStub) {
@ -204,6 +209,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "start"),
async function do_nothing_if_enrollment_paused(startStub) {
const action = new PreferenceExperimentAction();
@ -219,6 +225,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "stop"),
PreferenceExperiments.withMockExperiments([
{ name: "seen", expired: false, actionName: "PreferenceExperimentAction" },
@ -244,6 +251,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "stop"),
PreferenceExperiments.withMockExperiments([
{
@ -275,6 +283,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "start"),
withStub(Uptake, "reportRecipe"),
PreferenceExperiments.withMockExperiments([
@ -317,6 +326,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "start"),
PreferenceExperiments.withMockExperiments([]),
async function experimentType_with_isHighPopulation_false(startStub) {
@ -333,6 +343,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperiments, "start"),
PreferenceExperiments.withMockExperiments([]),
async function experimentType_with_isHighPopulation_true(startStub) {
@ -349,6 +360,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withStub(Sampling, "ratioSample"),
async function chooseBranch_uses_ratioSample(ratioSampleStub) {
ratioSampleStub.returns(Promise.resolve(1));
@ -388,6 +400,7 @@ decorate_task(
);
decorate_task(
withStudiesEnabled,
withMockPreferences,
PreferenceExperiments.withMockExperiments([]),
async function integration_test_enroll_and_unenroll(prefs) {

Просмотреть файл

@ -42,6 +42,7 @@ function preferenceExperimentFactory(args) {
}
decorate_task(
withStudiesEnabled,
withStub(PreferenceExperimentAction.prototype, "_run"),
PreferenceExperiments.withMockExperiments([]),
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
* to the preceding function as the argument; the result of this is passed to

Просмотреть файл

@ -187,6 +187,13 @@ this.AppConstants = Object.freeze({
false,
#endif
MOZ_NORMANDY:
#ifdef MOZ_NORMANDY
true,
#else
false,
#endif
MOZ_MAINTENANCE_SERVICE:
#ifdef MOZ_MAINTENANCE_SERVICE
true,

Просмотреть файл

@ -617,6 +617,11 @@ project_flag('MOZ_SERVICES_HEALTHREPORT',
set_for_old_configure=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',
help='Build Sync Services if required')

Просмотреть файл

@ -34,6 +34,7 @@ const kIfdefStateForLinting = {
MOZ_DATA_REPORTING: true,
MOZ_TELEMETRY_REPORTING: true,
MOZ_CRASHREPORTER: true,
MOZ_NORMANDY: true,
MOZ_MAINTENANCE_SERVICE: true,
HAVE_SHELL_SERVICE: true,
MENUBAR_CAN_AUTOHIDE: true,