Bug 1383338 - fetch and run shield studies soon after UI startup r?gijs r?mythmon
MozReview-Commit-ID: CWRQmwKplII
--- a/browser/extensions/shield-recipe-client/install.rdf.in
+++ b/browser/extensions/shield-recipe-client/install.rdf.in
@@ -3,17 +3,17 @@
#filter substitution
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>shield-recipe-client@mozilla.org</em:id>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack>
- <em:version>55</em:version>
+ <em:version>55.1</em:version>
<em:name>Shield Recipe Client</em:name>
<em:description>Client to download and run recipes for SHIELD, Heartbeat, etc.</em:description>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
--- a/browser/extensions/shield-recipe-client/lib/ClientEnvironment.jsm
+++ b/browser/extensions/shield-recipe-client/lib/ClientEnvironment.jsm
@@ -192,11 +192,15 @@ this.ClientEnvironment = {
} else {
names.active.push(experiment.name);
}
}
return names;
});
+ XPCOMUtils.defineLazyGetter(environment, "isFirstRun", () => {
+ return Preferences.get("extensions.shield-recipe-client.first_run");
+ });
+
return environment;
},
};
--- a/browser/extensions/shield-recipe-client/lib/RecipeRunner.jsm
+++ b/browser/extensions/shield-recipe-client/lib/RecipeRunner.jsm
@@ -33,28 +33,53 @@ XPCOMUtils.defineLazyModuleGetter(this,
Cu.importGlobalProperties(["fetch"]);
this.EXPORTED_SYMBOLS = ["RecipeRunner"];
const log = LogManager.getLogger("recipe-runner");
const prefs = Services.prefs.getBranch("extensions.shield-recipe-client.");
const TIMER_NAME = "recipe-client-addon-run";
const RUN_INTERVAL_PREF = "run_interval_seconds";
+const FIRST_RUN_PREF = "first_run";
+const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored";
+const SHIELD_INIT_NOTIFICATION = "shield-init-complete";
this.RecipeRunner = {
init() {
if (!this.checkPrefs()) {
return;
}
if (prefs.getBoolPref("dev_mode")) {
// Run right now in dev mode
this.run();
}
+ if (prefs.getBoolPref(FIRST_RUN_PREF)) {
+ // Run once immediately after the UI is available. Do this before adding the
+ // timer so we can't end up racing it.
+ const observer = {
+ observe: (subject, topic, data) => {
+ Services.obs.removeObserver(observer, UI_AVAILABLE_NOTIFICATION);
+
+ this.run();
+ this.registerTimer();
+ prefs.setBoolPref(FIRST_RUN_PREF, false);
+
+ Services.obs.notifyObservers(null, SHIELD_INIT_NOTIFICATION);
+ },
+ };
+ Services.obs.addObserver(observer, UI_AVAILABLE_NOTIFICATION);
+ CleanupManager.addCleanupHandler(() => Services.obs.removeObserver(observer, UI_AVAILABLE_NOTIFICATION));
+ } else {
+ this.registerTimer();
+ }
+ },
+
+ registerTimer() {
this.updateRunInterval();
CleanupManager.addCleanupHandler(() => timerManager.unregisterTimer(TIMER_NAME));
// Watch for the run interval to change, and re-register the timer with the new value
prefs.addObserver(RUN_INTERVAL_PREF, this);
CleanupManager.addCleanupHandler(() => prefs.removeObserver(RUN_INTERVAL_PREF, this));
},
--- a/browser/extensions/shield-recipe-client/lib/ShieldRecipeClient.jsm
+++ b/browser/extensions/shield-recipe-client/lib/ShieldRecipeClient.jsm
@@ -34,16 +34,17 @@ const PREF_BRANCH = "extensions.shield-r
const DEFAULT_PREFS = {
api_url: "https://normandy.cdn.mozilla.net/api/v1",
dev_mode: false,
enabled: true,
startup_delay_seconds: 300,
"logging.level": Log.Level.Warn,
user_id: "",
run_interval_seconds: 86400, // 24 hours
+ first_run: true,
};
const PREF_DEV_MODE = "extensions.shield-recipe-client.dev_mode";
const PREF_SELF_SUPPORT_ENABLED = "browser.selfsupport.enabled";
const PREF_LOGGING_LEVEL = PREF_BRANCH + "logging.level";
let log = null;
/**
--- a/browser/extensions/shield-recipe-client/test/browser/browser_ClientEnvironment.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_ClientEnvironment.js
@@ -107,8 +107,18 @@ add_task(async function testExperiments(
Assert.deepEqual(
experiments.expired,
["expired"],
"experiments.expired returns all expired experiment names",
);
getAll.restore();
});
+
+add_task(async function isFirstRun() {
+ let environment = ClientEnvironment.getEnvironment();
+
+ // isFirstRun is read from a preference
+ await SpecialPowers.pushPrefEnv({set: [["extensions.shield-recipe-client.first_run", true]]});
+ environment = ClientEnvironment.getEnvironment();
+ ok(environment.isFirstRun, "isFirstRun is read from preferences");
+});
+
--- a/browser/extensions/shield-recipe-client/test/browser/browser_RecipeRunner.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_RecipeRunner.js
@@ -195,28 +195,40 @@ add_task(withMockNormandyApi(async funct
}));
add_task(async function testStartup() {
const runStub = sinon.stub(RecipeRunner, "run");
const addCleanupHandlerStub = sinon.stub(CleanupManager, "addCleanupHandler");
const updateRunIntervalStub = sinon.stub(RecipeRunner, "updateRunInterval");
// in dev mode
- await SpecialPowers.pushPrefEnv({set: [["extensions.shield-recipe-client.dev_mode", true]]});
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.shield-recipe-client.dev_mode", true],
+ ["extensions.shield-recipe-client.first_run", false],
+ ],
+ });
+
RecipeRunner.init();
ok(runStub.called, "RecipeRunner.run is called immediately when in dev mode");
ok(addCleanupHandlerStub.called, "A cleanup function is registered when in dev mode");
ok(updateRunIntervalStub.called, "A timer is registered when in dev mode");
runStub.reset();
addCleanupHandlerStub.reset();
updateRunIntervalStub.reset();
// not in dev mode
- await SpecialPowers.pushPrefEnv({set: [["extensions.shield-recipe-client.dev_mode", false]]});
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.shield-recipe-client.dev_mode", false],
+ ["extensions.shield-recipe-client.first_run", false],
+ ],
+ });
+
RecipeRunner.init();
ok(!runStub.called, "RecipeRunner.run is not called immediately when not in dev mode");
ok(addCleanupHandlerStub.called, "A cleanup function is registered when not in dev mode");
ok(updateRunIntervalStub.called, "A timer is registered when not in dev mode");
runStub.restore();
addCleanupHandlerStub.restore();
updateRunIntervalStub.restore();