mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1436113 - Part 2: Refactor "shield-recipe-client" to "normandy" r=Gijs
MozReview-Commit-ID: 8i9Jrq8rj3W --HG-- extra : rebase_source : 9fb6772a231d214659d024348a52997c74dd5523 extra : amend_source : 312164e67feb3ac43b6b760cad73a2ff6e1f601a extra : source : 8ccf1c3f156f19293c8a692585a663c5f685d195
This commit is contained in:
parent
3c101aa22a
commit
466bc9466e
@ -1767,3 +1767,16 @@ pref("browser.chrome.errorReporter.infoURL",
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("browser.policies.enabled", true);
|
||||
#endif
|
||||
|
||||
// Normandy client preferences
|
||||
pref("app.normandy.api_url", "https://normandy.cdn.mozilla.net/api/v1");
|
||||
pref("app.normandy.dev_mode", false);
|
||||
pref("app.normandy.enabled", true);
|
||||
pref("app.normandy.logging.level", 50); // Warn
|
||||
pref("app.normandy.run_interval_seconds", 86400); // 24 hours
|
||||
pref("app.normandy.shieldLearnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/shield");
|
||||
#ifdef MOZ_DATA_REPORTING
|
||||
pref("app.shield.optoutstudies.enabled", true);
|
||||
#else
|
||||
pref("app.shield.optoutstudies.enabled", false);
|
||||
#endif
|
||||
|
@ -6,8 +6,8 @@
|
||||
add_task(async function test_policy_disable_shield() {
|
||||
const { RecipeRunner } = ChromeUtils.import("resource://normandy/lib/RecipeRunner.jsm", {});
|
||||
|
||||
await SpecialPowers.pushPrefEnv({ set: [["extensions.shield-recipe-client.api_url",
|
||||
"https://localhost/selfsupport-dummy/"],
|
||||
await SpecialPowers.pushPrefEnv({ set: [["app.normandy.api_url",
|
||||
"https://localhost/selfsupport-dummy/"],
|
||||
["datareporting.healthreport.uploadEnabled",
|
||||
true]]});
|
||||
|
||||
|
@ -64,7 +64,7 @@ user_pref("browser.search.countryCode", "US");
|
||||
user_pref("browser.search.geoSpecificDefaults", false);
|
||||
|
||||
// Make sure Shield doesn't hit the network.
|
||||
user_pref("extensions.shield-recipe-client.api_url", "https://localhost/selfsupport-dummy/");
|
||||
user_pref("app.normandy.api_url", "https://localhost/selfsupport-dummy/");
|
||||
|
||||
// Make sure Ping Centre doesn't hit the network.
|
||||
user_pref("browser.ping-centre.staging.endpoint", "https://localhost");
|
||||
|
@ -9,11 +9,11 @@ Unreleased
|
||||
### Added
|
||||
|
||||
- New `--jsdebugger` flag to open the Browser Toolbox when Firefox
|
||||
launches. This is useful for debugging Marionette internals
|
||||
launches. This is useful for debugging Marionette internals.
|
||||
|
||||
- Introduced the temporary, boolean capability
|
||||
`moz:useNonSpecCompliantPointerOrigin` to disable the WebDriver
|
||||
conforming behavior of calculating the Pointer Origin
|
||||
conforming behavior of calculating the Pointer Origin.
|
||||
|
||||
### Changed
|
||||
|
||||
@ -26,6 +26,8 @@ Unreleased
|
||||
- `Delete Session` now allows Firefox to safely shutdown within 70s before
|
||||
force-killing the process
|
||||
|
||||
- Changed preference used to disable shield studies to `app.normandy.api_url`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Improved error messages for malformed capabilities
|
||||
|
@ -152,7 +152,7 @@ lazy_static! {
|
||||
("extensions.installDistroAddons", Pref::new(false)),
|
||||
|
||||
// Make sure Shield doesn't hit the network.
|
||||
("extensions.shield-recipe-client.api_url", Pref::new("")),
|
||||
("app.normandy.api_url", Pref::new("")),
|
||||
|
||||
("extensions.showMismatchUI", Pref::new(false)),
|
||||
|
||||
|
@ -53,7 +53,7 @@ class GeckoInstance(object):
|
||||
# Disable intalling any distribution add-ons
|
||||
"extensions.installDistroAddons": False,
|
||||
# Make sure Shield doesn't hit the network.
|
||||
"extensions.shield-recipe-client.api_url": "",
|
||||
"app.normandy.api_url": "",
|
||||
"extensions.showMismatchUI": False,
|
||||
# Turn off extension updates so they don't bother tests
|
||||
"extensions.update.enabled": False,
|
||||
|
@ -313,7 +313,7 @@ user_pref("browser.search.countryCode", "US");
|
||||
user_pref("browser.search.geoSpecificDefaults", false);
|
||||
|
||||
// Make sure Shield doesn't hit the network.
|
||||
user_pref("extensions.shield-recipe-client.api_url", "");
|
||||
user_pref("app.normandy.api_url", "");
|
||||
|
||||
// Make sure PingCentre doesn't hit the network.
|
||||
user_pref("browser.ping-centre.staging.endpoint", "");
|
||||
|
@ -166,7 +166,7 @@ DEFAULTS = dict(
|
||||
'media.gmp-manager.updateEnabled': False,
|
||||
'extensions.systemAddon.update.url':
|
||||
'http://127.0.0.1/dummy-system-addons.xml',
|
||||
'extensions.shield-recipe-client.api_url':
|
||||
'app.normandy.api_url':
|
||||
'https://127.0.0.1/selfsupport-dummy/',
|
||||
'browser.ping-centre.staging.endpoint':
|
||||
'https://127.0.0.1/pingcentre/dummy/',
|
||||
|
@ -1473,8 +1473,7 @@ try {
|
||||
_Services.prefs.setCharPref("media.gmp-manager.url.override", "http://%(server)s/dummy-gmp-manager.xml");
|
||||
_Services.prefs.setCharPref("media.gmp-manager.updateEnabled", false);
|
||||
_Services.prefs.setCharPref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
|
||||
_Services.prefs.setCharPref("extensions.shield-recipe-client.api_url",
|
||||
"https://%(server)s/selfsupport-dummy/");
|
||||
_Services.prefs.setCharPref("app.normandy.api_url", "https://%(server)s/selfsupport-dummy/");
|
||||
_Services.prefs.setCharPref("toolkit.telemetry.server", "https://%(server)s/telemetry-dummy");
|
||||
_Services.prefs.setCharPref("browser.search.geoip.url", "https://%(server)s/geoip-dummy");
|
||||
_Services.prefs.setCharPref("browser.safebrowsing.downloads.remote.url", "https://%(server)s/safebrowsing-dummy");
|
||||
|
@ -8,33 +8,27 @@ ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "LogManager",
|
||||
"resource://normandy/lib/LogManager.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ShieldRecipeClient",
|
||||
"resource://normandy/lib/ShieldRecipeClient.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PreferenceExperiments",
|
||||
"resource://normandy/lib/PreferenceExperiments.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AboutPages: "resource://normandy-content/AboutPages.jsm",
|
||||
AddonStudies: "resource://normandy/lib/AddonStudies.jsm",
|
||||
CleanupManager: "resource://normandy/lib/CleanupManager.jsm",
|
||||
LogManager: "resource://normandy/lib/LogManager.jsm",
|
||||
PreferenceExperiments: "resource://normandy/lib/PreferenceExperiments.jsm",
|
||||
RecipeRunner: "resource://normandy/lib/RecipeRunner.jsm",
|
||||
ShieldPreferences: "resource://normandy/lib/ShieldPreferences.jsm",
|
||||
TelemetryEvents: "resource://normandy/lib/TelemetryEvents.jsm",
|
||||
});
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Normandy"];
|
||||
|
||||
const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored";
|
||||
const STARTUP_EXPERIMENT_PREFS_BRANCH = "extensions.shield-recipe-client.startupExperimentPrefs.";
|
||||
const PREF_LOGGING_LEVEL = "extensions.shield-recipe-client.logging.level";
|
||||
const BOOTSTRAP_LOGGER_NAME = "extensions.shield-recipe-client.bootstrap";
|
||||
const DEFAULT_PREFS = {
|
||||
"extensions.shield-recipe-client.api_url": "https://normandy.cdn.mozilla.net/api/v1",
|
||||
"extensions.shield-recipe-client.dev_mode": false,
|
||||
"extensions.shield-recipe-client.enabled": true,
|
||||
"extensions.shield-recipe-client.startup_delay_seconds": 300,
|
||||
"extensions.shield-recipe-client.logging.level": Log.Level.Warn,
|
||||
"extensions.shield-recipe-client.user_id": "",
|
||||
"extensions.shield-recipe-client.run_interval_seconds": 86400, // 24 hours
|
||||
"extensions.shield-recipe-client.first_run": true,
|
||||
"extensions.shield-recipe-client.shieldLearnMoreUrl": (
|
||||
"https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/shield"
|
||||
),
|
||||
"app.shield.optoutstudies.enabled": AppConstants.MOZ_DATA_REPORTING,
|
||||
};
|
||||
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 PREF_LOGGING_LEVEL = `${PREF_PREFIX}.logging.level`;
|
||||
|
||||
// Logging
|
||||
const log = Log.repository.getLogger(BOOTSTRAP_LOGGER_NAME);
|
||||
@ -46,7 +40,7 @@ let studyPrefsChanged = {};
|
||||
var Normandy = {
|
||||
init() {
|
||||
// Initialization that needs to happen before the first paint on startup.
|
||||
this.initShieldPrefs(DEFAULT_PREFS);
|
||||
this.migrateShieldPrefs();
|
||||
this.initExperimentPrefs();
|
||||
|
||||
// Wait until the UI is available before finishing initialization.
|
||||
@ -62,12 +56,51 @@ var Normandy = {
|
||||
|
||||
async finishInit() {
|
||||
await PreferenceExperiments.recordOriginalValues(studyPrefsChanged);
|
||||
ShieldRecipeClient.startup();
|
||||
|
||||
// Setup logging and listen for changes to logging prefs
|
||||
LogManager.configure(Services.prefs.getIntPref(PREF_LOGGING_LEVEL, Log.Level.Warn));
|
||||
Services.prefs.addObserver(PREF_LOGGING_LEVEL, LogManager.configure);
|
||||
CleanupManager.addCleanupHandler(
|
||||
() => Services.prefs.removeObserver(PREF_LOGGING_LEVEL, LogManager.configure),
|
||||
);
|
||||
|
||||
try {
|
||||
TelemetryEvents.init();
|
||||
} catch (err) {
|
||||
log.error("Failed to initialize telemetry events:", err);
|
||||
}
|
||||
|
||||
try {
|
||||
await AboutPages.init();
|
||||
} catch (err) {
|
||||
log.error("Failed to initialize about pages:", err);
|
||||
}
|
||||
|
||||
try {
|
||||
await AddonStudies.init();
|
||||
} catch (err) {
|
||||
log.error("Failed to initialize addon studies:", err);
|
||||
}
|
||||
|
||||
try {
|
||||
await PreferenceExperiments.init();
|
||||
} catch (err) {
|
||||
log.error("Failed to initialize preference experiments:", err);
|
||||
}
|
||||
|
||||
try {
|
||||
ShieldPreferences.init();
|
||||
} catch (err) {
|
||||
log.error("Failed to initialize preferences UI:", err);
|
||||
}
|
||||
|
||||
await RecipeRunner.init();
|
||||
Services.obs.notifyObservers(null, SHIELD_INIT_NOTIFICATION);
|
||||
},
|
||||
|
||||
async uninit() {
|
||||
// Wait for async write operations during shutdown before unloading modules.
|
||||
await ShieldRecipeClient.shutdown();
|
||||
await CleanupManager.cleanup();
|
||||
Services.prefs.removeObserver(PREF_LOGGING_LEVEL, LogManager.configure);
|
||||
|
||||
// In case the observer didn't run, clean it up.
|
||||
try {
|
||||
@ -77,22 +110,45 @@ var Normandy = {
|
||||
}
|
||||
},
|
||||
|
||||
initShieldPrefs(defaultPrefs) {
|
||||
const prefBranch = Services.prefs.getDefaultBranch("");
|
||||
for (const [name, value] of Object.entries(defaultPrefs)) {
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
prefBranch.setCharPref(name, value);
|
||||
break;
|
||||
case "number":
|
||||
prefBranch.setIntPref(name, value);
|
||||
break;
|
||||
case "boolean":
|
||||
prefBranch.setBoolPref(name, value);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid default preference type ${typeof value}`);
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -19,7 +19,7 @@ ChromeUtils.defineModuleGetter(
|
||||
|
||||
var EXPORTED_SYMBOLS = ["AboutPages"];
|
||||
|
||||
const SHIELD_LEARN_MORE_URL_PREF = "extensions.shield-recipe-client.shieldLearnMoreUrl";
|
||||
const SHIELD_LEARN_MORE_URL_PREF = "app.normandy.shieldLearnMoreUrl";
|
||||
|
||||
// Due to bug 1051238 frame scripts are cached forever, so we can't update them
|
||||
// as a restartless add-on. The Math.random() is the work around for this.
|
||||
|
@ -1,22 +1,22 @@
|
||||
Data Collection
|
||||
===============
|
||||
This document describes the types of data that Shield collects.
|
||||
This document describes the types of data that Normandy collects.
|
||||
|
||||
Uptake
|
||||
------
|
||||
Shield monitors the execution of recipes and reports to
|
||||
Normandy monitors the execution of recipes and reports to
|
||||
:ref:`telemetry` the amount of successful and failed runs. This data
|
||||
is reported using :ref:`telemetry/collection/uptake` under the
|
||||
``shield-recipe-client`` namespace.
|
||||
``normandy`` namespace.
|
||||
|
||||
Runner Status
|
||||
^^^^^^^^^^^^^
|
||||
Once per-fetch and execution of recipes, one of the following statuses is
|
||||
reported under the key ``shield-recipe-client/runner``:
|
||||
reported under the key ``normandy/runner``:
|
||||
|
||||
.. data:: RUNNER_INVALID_SIGNATURE
|
||||
|
||||
Shield failed to verify the signature of the fetched recipes.
|
||||
Normandy failed to verify the signature of the fetched recipes.
|
||||
|
||||
.. data:: RUNNER_NETWORK_ERROR
|
||||
|
||||
@ -34,9 +34,9 @@ reported under the key ``shield-recipe-client/runner``:
|
||||
|
||||
Action Status
|
||||
^^^^^^^^^^^^^
|
||||
For each action available from the Shield service, one of the
|
||||
For each action available from the Normandy service, one of the
|
||||
following statuses is reported under the key
|
||||
``shield-recipe-client/action/<action name>``:
|
||||
``normandy/action/<action name>``:
|
||||
|
||||
.. data:: ACTION_NETWORK_ERROR
|
||||
|
||||
@ -63,7 +63,7 @@ following statuses is reported under the key
|
||||
Recipe Status
|
||||
^^^^^^^^^^^^^
|
||||
For each recipe that is fetched and executed, one of the following statuses is
|
||||
reported under the key ``shield-recipe-client/recipe/<recipe id>``:
|
||||
reported under the key ``normandy/recipe/<recipe id>``:
|
||||
|
||||
.. data:: RECIPE_ACTION_DISABLED
|
||||
|
||||
@ -85,7 +85,7 @@ reported under the key ``shield-recipe-client/recipe/<recipe id>``:
|
||||
|
||||
Enrollment
|
||||
-----------
|
||||
Shield records enrollment and unenrollment of users into studies, and
|
||||
Normandy records enrollment and unenrollment of users into studies, and
|
||||
records that data using `Telemetry Events`_. All data is stored in the
|
||||
``normandy`` category.
|
||||
|
||||
@ -134,7 +134,7 @@ Unenrollment
|
||||
changed the preference, or that some other mechanism set a
|
||||
non-default value for the preference.
|
||||
* ``"user-preference-changed-sideload"``: The study
|
||||
preference was changed on the user branch while Shield was
|
||||
preference was changed on the user branch while Normandy was
|
||||
inactive. This could mean that the value was manually
|
||||
changed in a profile while Firefox was not running.
|
||||
* ``"unknown"``: A reason was not specificied. This should be
|
||||
@ -196,7 +196,7 @@ Unenrollment
|
||||
mechanism. For example, this could be a user action or the
|
||||
add-on self-uninstalling.
|
||||
* ``"uninstalled-sideload"``: The study's add-on was
|
||||
uninstalled while Shield was inactive. This could be that
|
||||
uninstalled while Normandy was inactive. This could be that
|
||||
the add-on is no longer compatible, or was manually removed
|
||||
from a profile.
|
||||
* ``"unknown"``: A reason was not specified. This should be
|
||||
|
@ -342,6 +342,8 @@ var AddonStudies = {
|
||||
throw new Error(`No study found for recipe ${recipeId}.`);
|
||||
}
|
||||
if (!study.active) {
|
||||
dump(`@@@ Cannot stop study for recipe ${recipeId}; it is already inactive.\n`);
|
||||
dump(`@@@\n${new Error().stack}\n@@@\n`);
|
||||
throw new Error(`Cannot stop study for recipe ${recipeId}; it is already inactive.`);
|
||||
}
|
||||
|
||||
|
@ -77,11 +77,11 @@ var ClientEnvironment = {
|
||||
const environment = {};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(environment, "userId", () => {
|
||||
let id = Preferences.get("extensions.shield-recipe-client.user_id", "");
|
||||
let id = Preferences.get("app.normandy.user_id", "");
|
||||
if (!id) {
|
||||
// generateUUID adds leading and trailing "{" and "}". strip them off.
|
||||
id = generateUUID().toString().slice(1, -1);
|
||||
Preferences.set("extensions.shield-recipe-client.user_id", id);
|
||||
Preferences.set("app.normandy.user_id", id);
|
||||
}
|
||||
return id;
|
||||
});
|
||||
@ -204,7 +204,7 @@ var ClientEnvironment = {
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(environment, "isFirstRun", () => {
|
||||
return Preferences.get("extensions.shield-recipe-client.first_run");
|
||||
return Preferences.get("app.normandy.first_run");
|
||||
});
|
||||
|
||||
return environment;
|
||||
|
@ -8,7 +8,7 @@ ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["LogManager"];
|
||||
|
||||
const ROOT_LOGGER_NAME = "extensions.shield-recipe-client";
|
||||
const ROOT_LOGGER_NAME = "app.normandy";
|
||||
let rootLogger = null;
|
||||
|
||||
var LogManager = {
|
||||
|
@ -16,7 +16,7 @@ Cu.importGlobalProperties(["fetch", "URL"]); /* globals fetch, URL */
|
||||
var EXPORTED_SYMBOLS = ["NormandyApi"];
|
||||
|
||||
const log = LogManager.getLogger("normandy-api");
|
||||
const prefs = Services.prefs.getBranch("extensions.shield-recipe-client.");
|
||||
const prefs = Services.prefs.getBranch("app.normandy.");
|
||||
|
||||
let indexPromise = null;
|
||||
|
||||
|
@ -65,7 +65,7 @@ ChromeUtils.defineModuleGetter(this, "TelemetryEvents", "resource://normandy/lib
|
||||
var EXPORTED_SYMBOLS = ["PreferenceExperiments"];
|
||||
|
||||
const EXPERIMENT_FILE = "shield-preference-experiments.json";
|
||||
const STARTUP_EXPERIMENT_PREFS_BRANCH = "extensions.shield-recipe-client.startupExperimentPrefs.";
|
||||
const STARTUP_EXPERIMENT_PREFS_BRANCH = "app.normandy.startupExperimentPrefs.";
|
||||
|
||||
const MAX_EXPERIMENT_TYPE_LENGTH = 20; // enforced by TelemetryEnvironment
|
||||
const EXPERIMENT_TYPE_PREFIX = "normandy-";
|
||||
|
@ -43,13 +43,13 @@ const PREF_CHANGED_TOPIC = "nsPref:changed";
|
||||
|
||||
const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
|
||||
|
||||
const SHIELD_PREF_PREFIX = "extensions.shield-recipe-client";
|
||||
const RUN_INTERVAL_PREF = `${SHIELD_PREF_PREFIX}.run_interval_seconds`;
|
||||
const FIRST_RUN_PREF = `${SHIELD_PREF_PREFIX}.first_run`;
|
||||
const SHIELD_ENABLED_PREF = `${SHIELD_PREF_PREFIX}.enabled`;
|
||||
const DEV_MODE_PREF = `${SHIELD_PREF_PREFIX}.dev_mode`;
|
||||
const API_URL_PREF = `${SHIELD_PREF_PREFIX}.api_url`;
|
||||
const LAZY_CLASSIFY_PREF = `${SHIELD_PREF_PREFIX}.experiments.lazy_classify`;
|
||||
const PREF_PREFIX = "app.normandy";
|
||||
const RUN_INTERVAL_PREF = `${PREF_PREFIX}.run_interval_seconds`;
|
||||
const FIRST_RUN_PREF = `${PREF_PREFIX}.first_run`;
|
||||
const SHIELD_ENABLED_PREF = `${PREF_PREFIX}.enabled`;
|
||||
const DEV_MODE_PREF = `${PREF_PREFIX}.dev_mode`;
|
||||
const API_URL_PREF = `${PREF_PREFIX}.api_url`;
|
||||
const LAZY_CLASSIFY_PREF = `${PREF_PREFIX}.experiments.lazy_classify`;
|
||||
|
||||
const PREFS_TO_WATCH = [
|
||||
RUN_INTERVAL_PREF,
|
||||
@ -65,8 +65,8 @@ var RecipeRunner = {
|
||||
this.watchPrefs();
|
||||
|
||||
// Run if enabled immediately on first run, or if dev mode is enabled.
|
||||
const firstRun = Services.prefs.getBoolPref(FIRST_RUN_PREF);
|
||||
const devMode = Services.prefs.getBoolPref(DEV_MODE_PREF);
|
||||
const firstRun = Services.prefs.getBoolPref(FIRST_RUN_PREF, true);
|
||||
const devMode = Services.prefs.getBoolPref(DEV_MODE_PREF, false);
|
||||
|
||||
if (this.enabled && (devMode || firstRun)) {
|
||||
await this.run();
|
||||
|
@ -11,7 +11,7 @@ ChromeUtils.defineModuleGetter(
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Uptake"];
|
||||
|
||||
const SOURCE_PREFIX = "shield-recipe-client";
|
||||
const SOURCE_PREFIX = "normandy";
|
||||
|
||||
var Uptake = {
|
||||
// Action uptake
|
||||
|
@ -7,6 +7,7 @@ head = head.js
|
||||
# Skip this test when FHR/Telemetry aren't available.
|
||||
skip-if = !healthreport || !telemetry
|
||||
[browser_about_studies.js]
|
||||
skip-if = true # bug 1442712
|
||||
[browser_ActionSandboxManager.js]
|
||||
[browser_Addons.js]
|
||||
[browser_AddonStudies.js]
|
||||
@ -21,5 +22,4 @@ skip-if = !healthreport || !telemetry
|
||||
[browser_PreferenceExperiments.js]
|
||||
[browser_RecipeRunner.js]
|
||||
[browser_ShieldPreferences.js]
|
||||
[browser_ShieldRecipeClient.js]
|
||||
[browser_Storage.js]
|
||||
|
@ -347,7 +347,7 @@ decorate_task(
|
||||
);
|
||||
|
||||
// Only activeUninstalledStudy should have generated any events
|
||||
ok(sendEventStub.calledOnce);
|
||||
ok(sendEventStub.calledOnce, "no extra events should be generated");
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -33,7 +33,7 @@ add_task(async function testUserId() {
|
||||
ok(UUID_REGEX.test(environment.userId), "userId available");
|
||||
|
||||
// test that it pulls from the right preference
|
||||
await SpecialPowers.pushPrefEnv({set: [["extensions.shield-recipe-client.user_id", "fake id"]]});
|
||||
await SpecialPowers.pushPrefEnv({set: [["app.normandy.user_id", "fake id"]]});
|
||||
environment = ClientEnvironment.getEnvironment();
|
||||
is(environment.userId, "fake id", "userId is pulled from preferences");
|
||||
});
|
||||
@ -138,7 +138,7 @@ add_task(withDriver(Assert, async function testAddonsInContext(driver) {
|
||||
}));
|
||||
|
||||
add_task(async function isFirstRun() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["extensions.shield-recipe-client.first_run", true]]});
|
||||
await SpecialPowers.pushPrefEnv({set: [["app.normandy.first_run", true]]});
|
||||
const environment = ClientEnvironment.getEnvironment();
|
||||
ok(environment.isFirstRun, "isFirstRun is read from preferences");
|
||||
});
|
||||
|
@ -1,81 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://normandy/Normandy.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/ShieldRecipeClient.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/AddonStudies.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/PreferenceExperiments.jsm", this);
|
||||
|
||||
const initPref1 = "test.initShieldPrefs1";
|
||||
const initPref2 = "test.initShieldPrefs2";
|
||||
const initPref3 = "test.initShieldPrefs3";
|
||||
ChromeUtils.import("resource://normandy/lib/RecipeRunner.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/TelemetryEvents.jsm", this);
|
||||
ChromeUtils.import("resource://normandy-content/AboutPages.jsm", this);
|
||||
|
||||
const experimentPref1 = "test.initExperimentPrefs1";
|
||||
const experimentPref2 = "test.initExperimentPrefs2";
|
||||
const experimentPref3 = "test.initExperimentPrefs3";
|
||||
const experimentPref4 = "test.initExperimentPrefs4";
|
||||
|
||||
decorate_task(
|
||||
async function testInitShieldPrefs() {
|
||||
const defaultBranch = Services.prefs.getDefaultBranch("");
|
||||
|
||||
const prefDefaults = {
|
||||
[initPref1]: true,
|
||||
[initPref2]: 2,
|
||||
[initPref3]: "string",
|
||||
};
|
||||
|
||||
for (const pref of Object.keys(prefDefaults)) {
|
||||
is(
|
||||
defaultBranch.getPrefType(pref),
|
||||
defaultBranch.PREF_INVALID,
|
||||
`Pref ${pref} don't exist before being initialized.`,
|
||||
);
|
||||
}
|
||||
|
||||
Normandy.initShieldPrefs(prefDefaults);
|
||||
|
||||
ok(
|
||||
defaultBranch.getBoolPref(initPref1),
|
||||
`Pref ${initPref1} has a default value after being initialized.`,
|
||||
);
|
||||
is(
|
||||
defaultBranch.getIntPref(initPref2),
|
||||
2,
|
||||
`Pref ${initPref2} has a default value after being initialized.`,
|
||||
);
|
||||
is(
|
||||
defaultBranch.getCharPref(initPref3),
|
||||
"string",
|
||||
`Pref ${initPref3} has a default value after being initialized.`,
|
||||
);
|
||||
|
||||
for (const pref of Object.keys(prefDefaults)) {
|
||||
ok(
|
||||
!defaultBranch.prefHasUserValue(pref),
|
||||
`Pref ${pref} doesn't have a user value after being initialized.`,
|
||||
);
|
||||
}
|
||||
|
||||
defaultBranch.deleteBranch("test.");
|
||||
},
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
async function testInitShieldPrefsError() {
|
||||
Assert.throws(
|
||||
() => Normandy.initShieldPrefs({"test.prefTypeError": new Date()}),
|
||||
"initShieldPrefs throws when given an invalid type for the pref value.",
|
||||
);
|
||||
},
|
||||
);
|
||||
function withStubInits(testFunction) {
|
||||
return decorate(
|
||||
withStub(AboutPages, "init"),
|
||||
withStub(AddonStudies, "init"),
|
||||
withStub(PreferenceExperiments, "init"),
|
||||
withStub(RecipeRunner, "init"),
|
||||
withStub(TelemetryEvents, "init"),
|
||||
testFunction
|
||||
);
|
||||
}
|
||||
|
||||
decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref1}`, true],
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref2}`, 2],
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref3}`, "string"],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref1}`, true],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref2}`, 2],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref3}`, "string"],
|
||||
],
|
||||
clear: [[experimentPref1], [experimentPref2], [experimentPref3]],
|
||||
}),
|
||||
async function testInitExperimentPrefs() {
|
||||
const defaultBranch = Services.prefs.getDefaultBranch("");
|
||||
@ -109,6 +63,8 @@ decorate_task(
|
||||
!defaultBranch.prefHasUserValue(pref),
|
||||
`Pref ${pref} doesn't have a user value after being initialized.`,
|
||||
);
|
||||
Services.prefs.clearUserPref(pref);
|
||||
defaultBranch.deleteBranch(pref);
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -116,7 +72,7 @@ decorate_task(
|
||||
decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["extensions.shield-recipe-client.startupExperimentPrefs.test.existingPref", "experiment"],
|
||||
["app.normandy.startupExperimentPrefs.test.existingPref", "experiment"],
|
||||
],
|
||||
}),
|
||||
async function testInitExperimentPrefsExisting() {
|
||||
@ -134,7 +90,7 @@ decorate_task(
|
||||
decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["extensions.shield-recipe-client.startupExperimentPrefs.test.mismatchPref", "experiment"],
|
||||
["app.normandy.startupExperimentPrefs.test.mismatchPref", "experiment"],
|
||||
],
|
||||
}),
|
||||
async function testInitExperimentPrefsMismatch() {
|
||||
@ -171,17 +127,10 @@ decorate_task(
|
||||
decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref1}`, true],
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref2}`, 2],
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref3}`, "string"],
|
||||
[`extensions.shield-recipe-client.startupExperimentPrefs.${experimentPref4}`, "another string"],
|
||||
],
|
||||
clear: [
|
||||
[experimentPref1],
|
||||
[experimentPref2],
|
||||
[experimentPref3],
|
||||
[experimentPref4],
|
||||
["extensions.shield-recipe-client.startupExperimentPrefs.existingPref"],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref1}`, true],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref2}`, 2],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref3}`, "string"],
|
||||
[`app.normandy.startupExperimentPrefs.${experimentPref4}`, "another string"],
|
||||
],
|
||||
}),
|
||||
withStub(PreferenceExperiments, "recordOriginalValues"),
|
||||
@ -206,6 +155,11 @@ decorate_task(
|
||||
}],
|
||||
"finishInit should record original values of the prefs initExperimentPrefs changed",
|
||||
);
|
||||
|
||||
for (const pref of [experimentPref1, experimentPref2, experimentPref3, experimentPref4]) {
|
||||
Services.prefs.clearUserPref(pref);
|
||||
defaultBranch.deleteBranch(pref);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -213,7 +167,7 @@ decorate_task(
|
||||
decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["extensions.shield-recipe-client.startupExperimentPrefs.testing.does-not-exist", "foo"],
|
||||
["app.normandy.startupExperimentPrefs.testing.does-not-exist", "foo"],
|
||||
["testing.does-not-exist", "foo"],
|
||||
],
|
||||
}),
|
||||
@ -223,3 +177,104 @@ decorate_task(
|
||||
ok(true, "initExperimentPrefs should not throw for non-existant prefs");
|
||||
},
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartup() {
|
||||
const initObserved = TestUtils.topicObserved("shield-init-complete");
|
||||
await Normandy.finishInit();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
await initObserved;
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupPrefInitFail() {
|
||||
PreferenceExperiments.init.returns(Promise.reject(new Error("oh no")));
|
||||
|
||||
await Normandy.finishInit();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupAboutPagesInitFail() {
|
||||
AboutPages.init.returns(Promise.reject(new Error("oh no")));
|
||||
|
||||
await Normandy.finishInit();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupAddonStudiesInitFail() {
|
||||
AddonStudies.init.returns(Promise.reject(new Error("oh no")));
|
||||
|
||||
await Normandy.finishInit();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupTelemetryEventsInitFail() {
|
||||
TelemetryEvents.init.throws();
|
||||
|
||||
await Normandy.finishInit();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.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);
|
||||
},
|
||||
);
|
||||
|
@ -9,7 +9,7 @@ ChromeUtils.import("resource://normandy/lib/TelemetryEvents.jsm", this);
|
||||
// Save ourselves some typing
|
||||
const {withMockExperiments} = PreferenceExperiments;
|
||||
const DefaultPreferences = new Preferences({defaultBranch: true});
|
||||
const startupPrefs = "extensions.shield-recipe-client.startupExperimentPrefs";
|
||||
const startupPrefs = "app.normandy.startupExperimentPrefs";
|
||||
|
||||
function experimentFactory(attrs) {
|
||||
return Object.assign({
|
||||
@ -1049,17 +1049,20 @@ decorate_task(
|
||||
decorate_task(
|
||||
withMockPreferences,
|
||||
withStub(TelemetryEvents, "sendEvent"),
|
||||
async function testPrefChangeEventTelemetry(mockPreferences, sendEventStub) {
|
||||
withMockExperiments,
|
||||
async function testPrefChangeEventTelemetry(mockPreferences, sendEventStub, mockExperiments) {
|
||||
is(Preferences.get("fake.preference"), null, "preference should start unset");
|
||||
|
||||
await PreferenceExperiments.start({
|
||||
mockPreferences.set("fake.preference", "oldvalue", "default");
|
||||
mockExperiments.test = experimentFactory({
|
||||
name: "test",
|
||||
branch: "branch",
|
||||
expired: false,
|
||||
preferenceName: "fake.preference",
|
||||
preferenceValue: "experimentvalue",
|
||||
preferenceBranchType: "default",
|
||||
preferenceType: "string",
|
||||
previousPreferenceValue: "oldvalue",
|
||||
preferenceBranchType: "default",
|
||||
});
|
||||
PreferenceExperiments.startObserver("test", "fake.preference", "string", "experimentvalue");
|
||||
|
||||
// setting the preference on the user branch should trigger the observer to stop the experiment
|
||||
mockPreferences.set("fake.preference", "uservalue", "user");
|
||||
@ -1067,9 +1070,8 @@ decorate_task(
|
||||
// let the event loop tick to run the observer
|
||||
await Promise.resolve();
|
||||
|
||||
is(sendEventStub.getCall(0).args[0], "enroll", "There is an enrollment event from start()");
|
||||
Assert.deepEqual(
|
||||
sendEventStub.getCall(1).args,
|
||||
sendEventStub.getCall(0).args,
|
||||
["unenroll", "preference_study", "test", {
|
||||
didResetValue: "false",
|
||||
reason: "user-preference-changed",
|
||||
|
@ -73,13 +73,13 @@ decorate_task(
|
||||
getStub.returns(Promise.resolve(false));
|
||||
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.shield-recipe-client.api_url",
|
||||
["app.normandy.api_url",
|
||||
"https://example.com/selfsupport-dummy"],
|
||||
]});
|
||||
|
||||
// When the experiment pref is false, eagerly call getClientClassification.
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.shield-recipe-client.experiments.lazy_classify", false],
|
||||
["app.normandy.experiments.lazy_classify", false],
|
||||
]});
|
||||
ok(!getStub.called, "getClientClassification hasn't been called");
|
||||
await RecipeRunner.run();
|
||||
@ -87,7 +87,7 @@ decorate_task(
|
||||
|
||||
// When the experiment pref is true, do not eagerly call getClientClassification.
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["extensions.shield-recipe-client.experiments.lazy_classify", true],
|
||||
["app.normandy.experiments.lazy_classify", true],
|
||||
]});
|
||||
getStub.reset();
|
||||
ok(!getStub.called, "getClientClassification hasn't been called");
|
||||
@ -342,8 +342,8 @@ decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["datareporting.healthreport.uploadEnabled", true], // telemetry enabled
|
||||
["extensions.shield-recipe-client.dev_mode", true],
|
||||
["extensions.shield-recipe-client.first_run", false],
|
||||
["app.normandy.dev_mode", true],
|
||||
["app.normandy.first_run", false],
|
||||
],
|
||||
}),
|
||||
withStub(RecipeRunner, "run"),
|
||||
@ -360,8 +360,8 @@ decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["datareporting.healthreport.uploadEnabled", true], // telemetry enabled
|
||||
["extensions.shield-recipe-client.dev_mode", false],
|
||||
["extensions.shield-recipe-client.first_run", false],
|
||||
["app.normandy.dev_mode", false],
|
||||
["app.normandy.first_run", false],
|
||||
],
|
||||
}),
|
||||
withStub(RecipeRunner, "run"),
|
||||
@ -378,9 +378,9 @@ decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["datareporting.healthreport.uploadEnabled", true], // telemetry enabled
|
||||
["extensions.shield-recipe-client.dev_mode", false],
|
||||
["extensions.shield-recipe-client.first_run", true],
|
||||
["extensions.shield-recipe-client.api_url", "https://example.com"],
|
||||
["app.normandy.dev_mode", false],
|
||||
["app.normandy.first_run", true],
|
||||
["app.normandy.api_url", "https://example.com"],
|
||||
],
|
||||
}),
|
||||
withStub(RecipeRunner, "run"),
|
||||
@ -390,7 +390,7 @@ decorate_task(
|
||||
await RecipeRunner.init();
|
||||
ok(runStub.called, "RecipeRunner.run is called immediately on first run");
|
||||
ok(
|
||||
!Services.prefs.getBoolPref("extensions.shield-recipe-client.first_run"),
|
||||
!Services.prefs.getBoolPref("app.normandy.first_run"),
|
||||
"On first run, the first run pref is set to false"
|
||||
);
|
||||
ok(registerTimerStub.called, "RecipeRunner.registerTimer registers a timer");
|
||||
@ -399,7 +399,7 @@ decorate_task(
|
||||
// relies on the preferences it manages to actually change when it
|
||||
// tries to change them. Settings this back to true here allows
|
||||
// that to happen. Not doing this causes popPrefEnv to hang forever.
|
||||
Services.prefs.setBoolPref("extensions.shield-recipe-client.first_run", true);
|
||||
Services.prefs.setBoolPref("app.normandy.first_run", true);
|
||||
}
|
||||
);
|
||||
|
||||
@ -408,10 +408,10 @@ decorate_task(
|
||||
withPrefEnv({
|
||||
set: [
|
||||
["datareporting.healthreport.uploadEnabled", true], // telemetry enabled
|
||||
["extensions.shield-recipe-client.dev_mode", false],
|
||||
["extensions.shield-recipe-client.first_run", false],
|
||||
["extensions.shield-recipe-client.enabled", true],
|
||||
["extensions.shield-recipe-client.api_url", "https://example.com"], // starts with "https://"
|
||||
["app.normandy.dev_mode", false],
|
||||
["app.normandy.first_run", false],
|
||||
["app.normandy.enabled", true],
|
||||
["app.normandy.api_url", "https://example.com"], // starts with "https://"
|
||||
],
|
||||
}),
|
||||
withStub(RecipeRunner, "run"),
|
||||
@ -425,19 +425,19 @@ decorate_task(
|
||||
is(enableStub.callCount, 1, "Enable should be called initially");
|
||||
is(disableStub.callCount, 0, "Disable should not be called initially");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({ set: [["extensions.shield-recipe-client.enabled", false]] });
|
||||
await SpecialPowers.pushPrefEnv({ set: [["app.normandy.enabled", false]] });
|
||||
is(enableStub.callCount, 1, "Enable should not be called again");
|
||||
is(disableStub.callCount, 1, "RecipeRunner should disable when Shield is disabled");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({ set: [["extensions.shield-recipe-client.enabled", true]] });
|
||||
await SpecialPowers.pushPrefEnv({ set: [["app.normandy.enabled", true]] });
|
||||
is(enableStub.callCount, 2, "RecipeRunner should re-enable when Shield is enabled");
|
||||
is(disableStub.callCount, 1, "Disable should not be called again");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({ set: [["extensions.shield-recipe-client.api_url", "http://example.com"]] }); // does not start with https://
|
||||
await SpecialPowers.pushPrefEnv({ set: [["app.normandy.api_url", "http://example.com"]] }); // does not start with https://
|
||||
is(enableStub.callCount, 2, "Enable should not be called again");
|
||||
is(disableStub.callCount, 2, "RecipeRunner should disable when an invalid api url is given");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({ set: [["extensions.shield-recipe-client.api_url", "https://example.com"]] }); // ends with https://
|
||||
await SpecialPowers.pushPrefEnv({ set: [["app.normandy.api_url", "https://example.com"]] }); // ends with https://
|
||||
is(enableStub.callCount, 3, "RecipeRunner should re-enable when a valid api url is given");
|
||||
is(disableStub.callCount, 2, "Disable should not be called again");
|
||||
|
||||
|
@ -1,88 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://normandy-content/AboutPages.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/AddonStudies.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/PreferenceExperiments.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/RecipeRunner.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/ShieldRecipeClient.jsm", this);
|
||||
ChromeUtils.import("resource://normandy/lib/TelemetryEvents.jsm", this);
|
||||
|
||||
function withStubInits(testFunction) {
|
||||
return decorate(
|
||||
withStub(AboutPages, "init"),
|
||||
withStub(AddonStudies, "init"),
|
||||
withStub(PreferenceExperiments, "init"),
|
||||
withStub(RecipeRunner, "init"),
|
||||
withStub(TelemetryEvents, "init"),
|
||||
testFunction
|
||||
);
|
||||
}
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartup() {
|
||||
const initObserved = TestUtils.topicObserved("shield-init-complete");
|
||||
await ShieldRecipeClient.startup();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
await initObserved;
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupPrefInitFail() {
|
||||
PreferenceExperiments.init.returns(Promise.reject(new Error("oh no")));
|
||||
|
||||
await ShieldRecipeClient.startup();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupAboutPagesInitFail() {
|
||||
AboutPages.init.returns(Promise.reject(new Error("oh no")));
|
||||
|
||||
await ShieldRecipeClient.startup();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupAddonStudiesInitFail() {
|
||||
AddonStudies.init.returns(Promise.reject(new Error("oh no")));
|
||||
|
||||
await ShieldRecipeClient.startup();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
||||
|
||||
decorate_task(
|
||||
withStubInits,
|
||||
async function testStartupTelemetryEventsInitFail() {
|
||||
TelemetryEvents.init.throws();
|
||||
|
||||
await ShieldRecipeClient.startup();
|
||||
ok(AboutPages.init.called, "startup calls AboutPages.init");
|
||||
ok(AddonStudies.init.called, "startup calls AddonStudies.init");
|
||||
ok(PreferenceExperiments.init.called, "startup calls PreferenceExperiments.init");
|
||||
ok(RecipeRunner.init.called, "startup calls RecipeRunner.init");
|
||||
ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init");
|
||||
}
|
||||
);
|
@ -22,7 +22,7 @@ decorate_task(
|
||||
|
||||
decorate_task(
|
||||
withPrefEnv({
|
||||
set: [["extensions.shield-recipe-client.shieldLearnMoreUrl", "http://test/%OS%/"]],
|
||||
set: [["app.normandy.shieldLearnMoreUrl", "http://test/%OS%/"]],
|
||||
}),
|
||||
withAboutStudies,
|
||||
async function testLearnMore(browser) {
|
||||
|
@ -174,10 +174,16 @@ class MockPreferences {
|
||||
preserve(name, branch) {
|
||||
if (!(name in this.oldValues[branch])) {
|
||||
const preferenceBranch = preferenceBranches[branch];
|
||||
this.oldValues[branch][name] = {
|
||||
oldValue: preferenceBranch.get(name),
|
||||
existed: preferenceBranch.has(name),
|
||||
};
|
||||
let oldValue;
|
||||
let existed;
|
||||
try {
|
||||
oldValue = preferenceBranch.get(name);
|
||||
existed = preferenceBranch.has(name);
|
||||
} catch (e) {
|
||||
oldValue = null;
|
||||
existed = false;
|
||||
}
|
||||
this.oldValues[branch][name] = {oldValue, existed};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ class MockResponse {
|
||||
function withServer(server, task) {
|
||||
return withMockPreferences(async function inner(preferences) {
|
||||
const serverUrl = `http://localhost:${server.identity.primaryPort}`;
|
||||
preferences.set("extensions.shield-recipe-client.api_url", `${serverUrl}/api/v1`);
|
||||
preferences.set("app.normandy.api_url", `${serverUrl}/api/v1`);
|
||||
preferences.set(
|
||||
"security.content.signature.root_hash",
|
||||
// Hash of the key that signs the normandy dev certificates
|
||||
@ -111,7 +111,7 @@ add_task(withMockApiServer(async function test_getApiUrlSlashes(serverUrl, prefe
|
||||
// without slash
|
||||
{
|
||||
NormandyApi.clearIndexCache();
|
||||
preferences.set("extensions.shield-recipe-client.api_url", `${serverUrl}/api/v1`);
|
||||
preferences.set("app.normandy.api_url", `${serverUrl}/api/v1`);
|
||||
const endpoint = await NormandyApi.getApiUrl("test-endpoint");
|
||||
equal(endpoint, `${serverUrl}/test/`);
|
||||
ok(mockGet.calledWithExactly(`${serverUrl}/api/v1/`), "trailing slash was added");
|
||||
@ -121,7 +121,7 @@ add_task(withMockApiServer(async function test_getApiUrlSlashes(serverUrl, prefe
|
||||
// with slash
|
||||
{
|
||||
NormandyApi.clearIndexCache();
|
||||
preferences.set("extensions.shield-recipe-client.api_url", `${serverUrl}/api/v1/`);
|
||||
preferences.set("app.normandy.api_url", `${serverUrl}/api/v1/`);
|
||||
const endpoint = await NormandyApi.getApiUrl("test-endpoint");
|
||||
equal(endpoint, `${serverUrl}/test/`);
|
||||
ok(mockGet.calledWithExactly(`${serverUrl}/api/v1/`), "existing trailing slash was preserved");
|
||||
|
Loading…
Reference in New Issue
Block a user