--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1765,8 +1765,21 @@ pref("browser.chrome.errorReporter.sampl
pref("browser.chrome.errorReporter.publicKey", "c709cb7a2c0b4f0882fcc84a5af161ec");
pref("browser.chrome.errorReporter.projectId", "339");
pref("browser.chrome.errorReporter.submitUrl", "https://sentry.prod.mozaws.net/api/339/store/");
pref("browser.chrome.errorReporter.logLevel", "Error");
// URL for Learn More link for browser error logging in preferences
pref("browser.chrome.errorReporter.infoURL",
"https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/nightly-error-collection");
+
+// 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
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_shield.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_shield.js
@@ -1,18 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
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]]});
ok(RecipeRunner, "RecipeRunner exists");
RecipeRunner.checkPrefs();
is(RecipeRunner.enabled, true, "RecipeRunner is enabled");
await setupPolicyEngineWithJson({
--- a/layout/tools/reftest/reftest-preferences.js
+++ b/layout/tools/reftest/reftest-preferences.js
@@ -59,17 +59,17 @@ user_pref("layout.interruptible-reflow.e
// Tell the search service we are running in the US. This also has the
// desired side-effect of preventing our geoip lookup.
user_pref("browser.search.isUS", true);
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");
user_pref("browser.ping-centre.production.endpoint", "https://localhost");
// use about:blank, not browser.startup.homepage
user_pref("browser.startup.page", 0);
--- a/testing/geckodriver/CHANGES.md
+++ b/testing/geckodriver/CHANGES.md
@@ -4,33 +4,35 @@ Change log
All notable changes to this program is documented in this file.
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
- HTTP status code for the [`StaleElementReference`] error changed
from 400 (Bad Request) to 404 (Not Found)
- Backtraces from geckodriver no longer substitute for missing
Marionette stacktraces
- `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
0.19.1 (2017-10-30)
-------------------
--- a/testing/geckodriver/src/prefs.rs
+++ b/testing/geckodriver/src/prefs.rs
@@ -147,17 +147,17 @@ lazy_static! {
// Disable metadata caching for installed add-ons by default
("extensions.getAddons.cache.enabled", Pref::new(false)),
// Disable intalling any distribution extensions or add-ons
("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)),
// Turn off extension updates so they do not bother tests
("extensions.update.enabled", Pref::new(false)),
("extensions.update.notifyUser", Pref::new(false)),
// Make sure opening about:addons will not hit the network
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -48,17 +48,17 @@ class GeckoInstance(object):
# AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
"extensions.autoDisableScopes": 0,
"extensions.enabledScopes": 5,
# Disable metadata caching for installed add-ons by default
"extensions.getAddons.cache.enabled": False,
# 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,
"extensions.update.notifyUser": False,
# Make sure opening about:addons won"t hit the network
"extensions.webservice.discoverURL": "http://%(server)s/dummy/discoveryURL",
# Allow the application to have focus even it runs in the background
--- a/testing/marionette/server.js
+++ b/testing/marionette/server.js
@@ -207,17 +207,17 @@ const RECOMMENDED_PREFS = new Map([
// Disable metadata caching for installed add-ons by default
["extensions.getAddons.cache.enabled", false],
// Disable installing any distribution extensions or add-ons.
// Should be set in profile.
["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 do not bother tests
["extensions.update.enabled", false],
["extensions.update.notifyUser", false],
// Make sure opening about:addons will not hit the network
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -312,17 +312,17 @@ user_pref("browser.uitour.url", "http://
// Tell the search service we are running in the US. This also has the desired
// side-effect of preventing our geoip lookup.
user_pref("browser.search.isUS", true);
user_pref("browser.search.countryCode", "US");
// This will prevent HTTP requests for region defaults.
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", "");
user_pref("browser.ping-centre.production.endpoint", "");
user_pref("media.eme.enabled", true);
// Set the number of shmems the PChromiumCDM protocol pre-allocates to 0,
--- a/testing/talos/talos/config.py
+++ b/testing/talos/talos/config.py
@@ -163,17 +163,17 @@ DEFAULTS = dict(
'/repositoryGetWithPerformanceURL',
'extensions.getAddons.search.browseURL':
'http://127.0.0.1/extensions-dummy/repositoryBrowseURL',
'media.gmp-manager.url':
'http://127.0.0.1/gmpmanager-dummy/update.xml',
'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/',
'browser.ping-centre.production.endpoint':
'https://127.0.0.1/pingcentre/dummy/',
'media.navigator.enabled': True,
'media.peerconnection.enabled': True,
'media.navigator.permission.disabled': True,
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -1468,18 +1468,17 @@ try {
}
} catch (e) { }
// We need to avoid hitting the network with certain components.
try {
if (runningInParent) {
_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");
}
} catch (e) { }
// Make tests run consistently on DevEdition (which has a lightweight theme
// selected by default).
--- a/toolkit/components/normandy/Normandy.jsm
+++ b/toolkit/components/normandy/Normandy.jsm
@@ -3,101 +3,157 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
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);
log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
log.level = Services.prefs.getIntPref(PREF_LOGGING_LEVEL, Log.Level.Warn);
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.
Services.obs.addObserver(this, UI_AVAILABLE_NOTIFICATION);
},
observe(subject, topic, data) {
if (topic === UI_AVAILABLE_NOTIFICATION) {
Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
this.finishInit();
}
},
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 {
Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
} catch (err) {
// It must already be removed!
}
},
- initShieldPrefs(defaultPrefs) {
- const prefBranch = Services.prefs.getDefaultBranch("");
- for (const [name, value] of Object.entries(defaultPrefs)) {
- switch (typeof value) {
- case "string":
- prefBranch.setCharPref(name, 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 "number":
- prefBranch.setIntPref(name, value);
+
+ 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 "boolean":
- prefBranch.setBoolPref(name, value);
+
+ case Services.prefs.PREF_INVALID:
+ // This should never happen.
+ log.error(`Error migrating pref ${prefName}; pref type is invalid (${legacyPrefType}).`);
break;
+
default:
- throw new Error(`Invalid default preference type ${typeof value}`);
+ // This should never happen either.
+ log.error(`Error getting startup pref ${prefName}; unknown value type ${legacyPrefType}.`);
}
+
+ legacyBranch.clearUserPref(prefName);
}
},
initExperimentPrefs() {
studyPrefsChanged = {};
const defaultBranch = Services.prefs.getDefaultBranch("");
const experimentBranch = Services.prefs.getBranch(STARTUP_EXPERIMENT_PREFS_BRANCH);
--- a/toolkit/components/normandy/content/AboutPages.jsm
+++ b/toolkit/components/normandy/content/AboutPages.jsm
@@ -14,17 +14,17 @@ ChromeUtils.defineModuleGetter(
this, "AddonStudies", "resource://normandy/lib/AddonStudies.jsm",
);
ChromeUtils.defineModuleGetter(
this, "RecipeRunner", "resource://normandy/lib/RecipeRunner.jsm",
);
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.
const PROCESS_SCRIPT = (
`resource://normandy-content/shield-content-process.js?${Math.random()}`
);
const FRAME_SCRIPT = (
`resource://normandy-content/shield-content-frame.js?${Math.random()}`
--- a/toolkit/components/normandy/docs/data-collection.rst
+++ b/toolkit/components/normandy/docs/data-collection.rst
@@ -1,27 +1,27 @@
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
There was a network-related error while fetching recipes.
.. data:: RUNNER_SERVER_ERROR
The data returned by the server when fetching the recipe is invalid in some
@@ -29,19 +29,19 @@ reported under the key ``shield-recipe-c
.. data:: RUNNER_SUCCESS
The operation completed successfully. Individual failures with actions and
recipes may have been reported separately.
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
There was a network-related error while fetching actions
.. data:: ACTION_PRE_EXECUTION_ERROR
There was an error while running the pre-execution hook for the action.
@@ -58,17 +58,17 @@ following statuses is reported under the
.. data:: ACTION_SUCCESS
The operation completed successfully. Individual failures with recipes may
be reported separately.
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
The action for this recipe failed in some way and was disabled, so the recipe
could not be executed.
.. data:: RECIPE_EXECUTION_ERROR
@@ -80,17 +80,17 @@ reported under the key ``shield-recipe-c
.. data:: RECIPE_SUCCESS
The recipe was executed successfully.
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.
.. _Telemetry Events: https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/collection/events.html
Preference Studies
^^^^^^^^^^^^^^^^^^
Enrollment
@@ -129,17 +129,17 @@ Unenrollment
applicable to this client This can be because the recipe
was disabled, or the user no longer matches the recipe's
filter.
* ``"user-preference-changed"``: The study preference was
changed on the user branch. This could mean the user
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
considered a bug.
Add-on Studies
^^^^^^^^^^^^^^
Enrollment
@@ -191,13 +191,13 @@ Unenrollment
* ``"recipe-not-seen"``: The recipe was no longer applicable
to this client. This can be because the recipe was
disabled, or the user no longer matches the recipe's
filter.
* ``"uninstalled"``: The study's add-on as uninstalled by some
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
considered a bug.
--- a/toolkit/components/normandy/lib/ClientEnvironment.jsm
+++ b/toolkit/components/normandy/lib/ClientEnvironment.jsm
@@ -72,21 +72,21 @@ var ClientEnvironment = {
* Also note that, because filter expressions implicitly resolve promises, you
* can add getter functions that return promises for async data.
* @return {Object}
*/
getEnvironment() {
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;
});
XPCOMUtils.defineLazyGetter(environment, "country", () => {
return ClientEnvironment.getClientClassification()
.then(classification => classification.country);
});
@@ -199,14 +199,14 @@ var ClientEnvironment = {
});
XPCOMUtils.defineLazyGetter(environment, "addons", async () => {
const addons = await Addons.getAll();
return Utils.keyBy(addons, "id");
});
XPCOMUtils.defineLazyGetter(environment, "isFirstRun", () => {
- return Preferences.get("extensions.shield-recipe-client.first_run");
+ return Preferences.get("app.normandy.first_run");
});
return environment;
},
};
--- a/toolkit/components/normandy/lib/LogManager.jsm
+++ b/toolkit/components/normandy/lib/LogManager.jsm
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
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 = {
/**
* Configure the root logger for the Recipe Client. Must be called at
* least once before using any loggers created via getLogger.
* @param {Number} loggingLevel
* Logging level to use as defined in Log.jsm
--- a/toolkit/components/normandy/lib/NormandyApi.jsm
+++ b/toolkit/components/normandy/lib/NormandyApi.jsm
@@ -11,17 +11,17 @@ ChromeUtils.import("resource://normandy/
ChromeUtils.defineModuleGetter(
this, "CanonicalJSON", "resource://gre/modules/CanonicalJSON.jsm");
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;
var NormandyApi = {
InvalidSignatureError: class InvalidSignatureError extends Error {},
clearIndexCache() {
indexPromise = null;
--- a/toolkit/components/normandy/lib/PreferenceExperiments.jsm
+++ b/toolkit/components/normandy/lib/PreferenceExperiments.jsm
@@ -60,17 +60,17 @@ ChromeUtils.defineModuleGetter(this, "JS
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
ChromeUtils.defineModuleGetter(this, "LogManager", "resource://normandy/lib/LogManager.jsm");
ChromeUtils.defineModuleGetter(this, "TelemetryEnvironment", "resource://gre/modules/TelemetryEnvironment.jsm");
ChromeUtils.defineModuleGetter(this, "TelemetryEvents", "resource://normandy/lib/TelemetryEvents.jsm");
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-";
const MAX_EXPERIMENT_SUBTYPE_LENGTH = MAX_EXPERIMENT_TYPE_LENGTH - EXPERIMENT_TYPE_PREFIX.length;
const PREFERENCE_TYPE_MAP = {
boolean: Services.prefs.PREF_BOOL,
string: Services.prefs.PREF_STRING,
--- a/toolkit/components/normandy/lib/RecipeRunner.jsm
+++ b/toolkit/components/normandy/lib/RecipeRunner.jsm
@@ -38,40 +38,40 @@ Cu.importGlobalProperties(["fetch"]);
var EXPORTED_SYMBOLS = ["RecipeRunner"];
const log = LogManager.getLogger("recipe-runner");
const TIMER_NAME = "recipe-client-addon-run";
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,
TELEMETRY_ENABLED_PREF,
SHIELD_ENABLED_PREF,
API_URL_PREF,
];
var RecipeRunner = {
async init() {
this.enabled = null;
this.checkPrefs(); // sets this.enabled
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();
}
if (firstRun) {
Services.prefs.setBoolPref(FIRST_RUN_PREF, false);
}
},
--- a/toolkit/components/normandy/lib/Uptake.jsm
+++ b/toolkit/components/normandy/lib/Uptake.jsm
@@ -6,17 +6,17 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(
this, "UptakeTelemetry", "resource://services-common/uptake-telemetry.js");
var EXPORTED_SYMBOLS = ["Uptake"];
-const SOURCE_PREFIX = "shield-recipe-client";
+const SOURCE_PREFIX = "normandy";
var Uptake = {
// Action uptake
ACTION_NETWORK_ERROR: UptakeTelemetry.STATUS.NETWORK_ERROR,
ACTION_PRE_EXECUTION_ERROR: UptakeTelemetry.STATUS.CUSTOM_1_ERROR,
ACTION_POST_EXECUTION_ERROR: UptakeTelemetry.STATUS.CUSTOM_2_ERROR,
ACTION_SERVER_ERROR: UptakeTelemetry.STATUS.SERVER_ERROR,
ACTION_SUCCESS: UptakeTelemetry.STATUS.SUCCESS,
--- a/toolkit/components/normandy/test/browser/browser.ini
+++ b/toolkit/components/normandy/test/browser/browser.ini
@@ -16,10 +16,9 @@ skip-if = !healthreport || !telemetry
[browser_FilterExpressions.js]
[browser_Heartbeat.js]
[browser_LogManager.js]
[browser_Normandy.js]
[browser_NormandyDriver.js]
[browser_PreferenceExperiments.js]
[browser_RecipeRunner.js]
[browser_ShieldPreferences.js]
-[browser_ShieldRecipeClient.js]
[browser_Storage.js]
--- a/toolkit/components/normandy/test/browser/browser_ClientEnvironment.js
+++ b/toolkit/components/normandy/test/browser/browser_ClientEnvironment.js
@@ -28,17 +28,17 @@ add_task(async function testTelemetry()
add_task(async function testUserId() {
let environment = ClientEnvironment.getEnvironment();
// Test that userId is available
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");
});
add_task(async function testDistribution() {
let environment = ClientEnvironment.getEnvironment();
// distribution id defaults to "default"
@@ -133,12 +133,12 @@ add_task(withDriver(Assert, async functi
isActive: true,
type: "extension",
}, "addons should be available in context");
await driver.addons.uninstall(addonId);
}));
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");
});
--- a/toolkit/components/normandy/test/browser/browser_Normandy.js
+++ b/toolkit/components/normandy/test/browser/browser_Normandy.js
@@ -1,84 +1,39 @@
"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("");
for (const pref of [experimentPref1, experimentPref2, experimentPref3]) {
is(
defaultBranch.getPrefType(pref),
@@ -111,17 +66,17 @@ decorate_task(
);
}
},
);
decorate_task(
withPrefEnv({
set: [
- ["extensions.shield-recipe-client.startupExperimentPrefs.test.existingPref", "experiment"],
+ ["app.normandy.startupExperimentPrefs.test.existingPref", "experiment"],
],
}),
async function testInitExperimentPrefsExisting() {
const defaultBranch = Services.prefs.getDefaultBranch("");
defaultBranch.setCharPref("test.existingPref", "default");
Normandy.initExperimentPrefs();
is(
defaultBranch.getCharPref("test.existingPref"),
@@ -129,17 +84,17 @@ decorate_task(
"initExperimentPrefs overwrites the default values of existing preferences.",
);
},
);
decorate_task(
withPrefEnv({
set: [
- ["extensions.shield-recipe-client.startupExperimentPrefs.test.mismatchPref", "experiment"],
+ ["app.normandy.startupExperimentPrefs.test.mismatchPref", "experiment"],
],
}),
async function testInitExperimentPrefsMismatch() {
const defaultBranch = Services.prefs.getDefaultBranch("");
defaultBranch.setIntPref("test.mismatchPref", 2);
Normandy.initExperimentPrefs();
is(
defaultBranch.getPrefType("test.mismatchPref"),
@@ -166,27 +121,27 @@ decorate_task(
},
);
// During startup, preferences that are changed for experiments should
// be record by calling PreferenceExperiments.recordOriginalValues.
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"],
+ [`app.normandy.startupExperimentPrefs.${experimentPref1}`, true],
+ [`app.normandy.startupExperimentPrefs.${experimentPref2}`, 2],
+ [`app.normandy.startupExperimentPrefs.${experimentPref3}`, "string"],
+ [`app.normandy.startupExperimentPrefs.${experimentPref4}`, "another string"],
],
clear: [
[experimentPref1],
[experimentPref2],
[experimentPref3],
[experimentPref4],
- ["extensions.shield-recipe-client.startupExperimentPrefs.existingPref"],
+ ["app.normandy.startupExperimentPrefs.existingPref"],
],
}),
withStub(PreferenceExperiments, "recordOriginalValues"),
async function testInitExperimentPrefs(recordOriginalValuesStub) {
const defaultBranch = Services.prefs.getDefaultBranch("");
defaultBranch.setBoolPref(experimentPref1, false);
defaultBranch.setIntPref(experimentPref2, 1);
@@ -208,18 +163,117 @@ decorate_task(
);
},
);
// Test that startup prefs are handled correctly when there is a value on the user branch but not the default branch.
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"],
],
}),
withStub(PreferenceExperiments, "recordOriginalValues"),
async function testInitExperimentPrefsNoDefaultValue() {
Normandy.initExperimentPrefs();
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");
+ },
+);
--- a/toolkit/components/normandy/test/browser/browser_PreferenceExperiments.js
+++ b/toolkit/components/normandy/test/browser/browser_PreferenceExperiments.js
@@ -4,17 +4,17 @@ ChromeUtils.import("resource://gre/modul
ChromeUtils.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
ChromeUtils.import("resource://normandy/lib/PreferenceExperiments.jsm", this);
ChromeUtils.import("resource://normandy/lib/CleanupManager.jsm", this);
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({
name: "fakename",
branch: "fakebranch",
expired: false,
lastSeen: new Date().toJSON(),
preferenceName: "fake.preference",
--- a/toolkit/components/normandy/test/browser/browser_RecipeRunner.js
+++ b/toolkit/components/normandy/test/browser/browser_RecipeRunner.js
@@ -68,31 +68,31 @@ add_task(async function checkFilter() {
decorate_task(
withMockNormandyApi,
withStub(ClientEnvironment, "getClientClassification"),
async function testClientClassificationCache(api, getStub) {
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();
ok(getStub.called, "getClientClassification was called eagerly");
// 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");
await RecipeRunner.run();
ok(!getStub.called, "getClientClassification was not called eagerly");
}
);
@@ -337,112 +337,112 @@ decorate_task(
}
);
// test init() in dev mode
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"),
withStub(RecipeRunner, "registerTimer"),
async function testInitDevMode(runStub, registerTimerStub, updateRunIntervalStub) {
await RecipeRunner.init();
ok(runStub.called, "RecipeRunner.run is called immediately when in dev mode");
ok(registerTimerStub.called, "RecipeRunner.init registers a timer");
}
);
// Test init() during normal operation
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"),
withStub(RecipeRunner, "registerTimer"),
async function testInit(runStub, registerTimerStub) {
await RecipeRunner.init();
ok(!runStub.called, "RecipeRunner.run is called immediately when not in dev mode or first run");
ok(registerTimerStub.called, "RecipeRunner.init registers a timer");
}
);
// Test init() first run
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"),
withStub(RecipeRunner, "registerTimer"),
withStub(RecipeRunner, "watchPrefs"),
async function testInitFirstRun(runStub, registerTimerStub, watchPrefsStub) {
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");
// RecipeRunner.init() sets this to false, but SpecialPowers
// 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);
}
);
// Test that prefs are watched correctly
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"),
withStub(RecipeRunner, "enable"),
withStub(RecipeRunner, "disable"),
withStub(CleanupManager, "addCleanupHandler"),
withStub(AddonStudies, "stop"),
async function testPrefWatching(runStub, enableStub, disableStub, addCleanupHandlerStub, stopStub) {
await RecipeRunner.init();
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");
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]] });
deleted file mode 100644
--- a/toolkit/components/normandy/test/browser/browser_ShieldRecipeClient.js
+++ /dev/null
@@ -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");
- }
-);
--- a/toolkit/components/normandy/test/browser/browser_about_studies.js
+++ b/toolkit/components/normandy/test/browser/browser_about_studies.js
@@ -17,17 +17,17 @@ decorate_task(
async function testAboutStudiesWorks(browser) {
// eslint-disable-next-line mozilla/no-cpows-in-tests
ok(browser.contentDocumentAsCPOW.getElementById("app"), "App element was found");
}
);
decorate_task(
withPrefEnv({
- set: [["extensions.shield-recipe-client.shieldLearnMoreUrl", "http://test/%OS%/"]],
+ set: [["app.normandy.shieldLearnMoreUrl", "http://test/%OS%/"]],
}),
withAboutStudies,
async function testLearnMore(browser) {
ContentTask.spawn(browser, null, () => {
content.document.getElementById("shield-studies-learn-more").click();
});
await BrowserTestUtils.waitForLocationChange(gBrowser);
--- a/toolkit/components/normandy/test/unit/test_NormandyApi.js
+++ b/toolkit/components/normandy/test/unit/test_NormandyApi.js
@@ -21,17 +21,17 @@ class MockResponse {
async json() {
return JSON.parse(this.content);
}
}
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
"4C:35:B1:C3:E3:12:D9:55:E7:78:ED:D0:A7:E7:8A:38:83:04:EF:01:BF:FA:03:29:B2:46:9F:3C:C5:EC:36:04"
);
NormandyApi.clearIndexCache();
try {
@@ -106,27 +106,27 @@ add_task(withMockApiServer(async functio
add_task(withMockApiServer(async function test_getApiUrlSlashes(serverUrl, preferences) {
const fakeResponse = new MockResponse(JSON.stringify({"test-endpoint": `${serverUrl}/test/`}));
const mockGet = sinon.stub(NormandyApi, "get", async () => fakeResponse);
// 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");
mockGet.reset();
}
// 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");
mockGet.reset();
}
NormandyApi.clearIndexCache();
mockGet.restore();