From 8191ee17a1c4fc8397f060f3156632216b76f299 Mon Sep 17 00:00:00 2001 From: Michael Cooper Date: Wed, 3 Jun 2020 19:39:06 +0000 Subject: [PATCH] Bug 1643079 - Normandy initialize should be idempotent r=rhelmer Differential Revision: https://phabricator.services.mozilla.com/D78121 --- toolkit/components/normandy/Normandy.jsm | 19 +++++++++++++++++++ .../normandy/test/browser/browser_Normandy.js | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/toolkit/components/normandy/Normandy.jsm b/toolkit/components/normandy/Normandy.jsm index dc6f33dee3f7..d5665b976701 100644 --- a/toolkit/components/normandy/Normandy.jsm +++ b/toolkit/components/normandy/Normandy.jsm @@ -46,7 +46,19 @@ var Normandy = { studyPrefsChanged: {}, rolloutPrefsChanged: {}, + STATE_UNINITIALIZED: 1, + STATE_QUEUED: 2, + STATE_IN_PROGRESS: 3, + STATE_FINISHED: 4, + _state: 1, // uninitialized + async init({ runAsync = true } = {}) { + if (this._state != this.STATE_UNINITIALIZED) { + // initialization has already started. + return; + } + this._state = this.STATE_QUEUED; + // Initialization that needs to happen before the first paint on startup. Services.obs.addObserver( this, @@ -90,6 +102,12 @@ var Normandy = { }, async finishInit() { + if (this._state !== this.STATE_QUEUED) { + // already in progress + return; + } + this._state = this.STATE_IN_PROGRESS; + try { TelemetryEvents.init(); } catch (err) { @@ -151,6 +169,7 @@ var Normandy = { } await RecipeRunner.init(); + this._state = this.STATE_FINISHED; Services.obs.notifyObservers(null, SHIELD_INIT_NOTIFICATION); }, diff --git a/toolkit/components/normandy/test/browser/browser_Normandy.js b/toolkit/components/normandy/test/browser/browser_Normandy.js index fb7380dfb29b..01f32f0b87b7 100644 --- a/toolkit/components/normandy/test/browser/browser_Normandy.js +++ b/toolkit/components/normandy/test/browser/browser_Normandy.js @@ -140,6 +140,7 @@ decorate_task( decorate_task( withStub(Normandy, "finishInit"), async function testStartupDelayed(finishInitStub) { + Normandy._state = Normandy.STATE_UNINITIALIZED; await Normandy.init(); ok( !finishInitStub.called, @@ -173,6 +174,7 @@ decorate_task( Normandy.applyStartupPrefs("app.normandy.startupExperimentPrefs."); Normandy.studyPrefsChanged = { "test.study-pref": 1 }; Normandy.rolloutPrefsChanged = { "test.rollout-pref": 1 }; + Normandy._state = Normandy.STATE_QUEUED; await Normandy.finishInit(); Assert.deepEqual( @@ -213,6 +215,7 @@ decorate_task( decorate_task(withStubInits, async function testStartup() { const initObserved = TestUtils.topicObserved("shield-init-complete"); + Normandy._state = Normandy.STATE_QUEUED; await Normandy.finishInit(); ok(AddonStudies.init.called, "startup calls AddonStudies.init"); ok( @@ -226,6 +229,7 @@ decorate_task(withStubInits, async function testStartup() { decorate_task(withStubInits, async function testStartupPrefInitFail() { PreferenceExperiments.init.rejects(); + Normandy._state = Normandy.STATE_QUEUED; await Normandy.finishInit(); ok(AddonStudies.init.called, "startup calls AddonStudies.init"); ok(AddonRollouts.init.called, "startup calls AddonRollouts.init"); @@ -241,6 +245,7 @@ decorate_task(withStubInits, async function testStartupPrefInitFail() { decorate_task(withStubInits, async function testStartupAddonStudiesInitFail() { AddonStudies.init.rejects(); + Normandy._state = Normandy.STATE_QUEUED; await Normandy.finishInit(); ok(AddonStudies.init.called, "startup calls AddonStudies.init"); ok(AddonRollouts.init.called, "startup calls AddonRollouts.init"); @@ -258,6 +263,7 @@ decorate_task( async function testStartupTelemetryEventsInitFail() { TelemetryEvents.init.throws(); + Normandy._state = Normandy.STATE_QUEUED; await Normandy.finishInit(); ok(AddonStudies.init.called, "startup calls AddonStudies.init"); ok(AddonRollouts.init.called, "startup calls AddonRollouts.init"); @@ -276,6 +282,7 @@ decorate_task( async function testStartupPreferenceRolloutsInitFail() { PreferenceRollouts.init.throws(); + Normandy._state = Normandy.STATE_QUEUED; await Normandy.finishInit(); ok(AddonStudies.init.called, "startup calls AddonStudies.init"); ok(AddonRollouts.init.called, "startup calls AddonRollouts.init");