Bug 1005270 - Trigger experiments initialization on opening the addon manager UI. r=bsmedberg, a=sledru
authorGeorg Fritzsche <georg.fritzsche@googlemail.com>
Fri, 16 May 2014 12:56:25 +0200
changeset 200406 2c7882800cdd322de35efc4d06b324ce635f9f9e
parent 200405 406ff46c498b145fd560824a3633480bbd1bd418
child 200407 67145b77ac8476e3d65d3a87d893ee8c5030c5d7
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg, sledru
bugs1005270
milestone31.0a2
Bug 1005270 - Trigger experiments initialization on opening the addon manager UI. r=bsmedberg, a=sledru
browser/experiments/Experiments.jsm
browser/experiments/ExperimentsService.js
browser/experiments/test/xpcshell/test_api.js
browser/experiments/test/xpcshell/test_disableExperiments.js
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -374,16 +374,20 @@ Experiments.Experiments = function (poli
   // * saving the cache (if _dirty)
   this._mainTask = null;
 
   // Timer for re-evaluating experiment status.
   this._timer = null;
 
   this._shutdown = false;
 
+  // We need to tell when we first evaluated the experiments to fire an
+  // experiments-changed notification when we only loaded completed experiments.
+  this._firstEvaluate = true;
+
   this.init();
 };
 
 Experiments.Experiments.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback, Ci.nsIObserver]),
 
   init: function () {
     this._shutdown = false;
@@ -1153,18 +1157,19 @@ Experiments.Experiments.prototype = {
           experiment._enabled = false;
           yield experiment.reconcileAddonState();
         }
       }
     }
 
     gPrefs.set(PREF_ACTIVE_EXPERIMENT, activeExperiment != null);
 
-    if (activeChanged) {
+    if (activeChanged || this._firstEvaluate) {
       Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
+      this._firstEvaluate = false;
     }
 
     if ("@mozilla.org/toolkit/crash-reporter;1" in Cc && activeExperiment) {
       try {
         gCrashReporter.annotateCrashReport("ActiveExperiment", activeExperiment.id);
       } catch (e) {
         // It's ok if crash reporting is disabled.
       }
--- a/browser/experiments/ExperimentsService.js
+++ b/browser/experiments/ExperimentsService.js
@@ -67,31 +67,43 @@ ExperimentsService.prototype = {
   },
 
   observe: function (subject, topic, data) {
     switch (topic) {
       case "profile-after-change":
         if (gExperimentsEnabled) {
           Services.obs.addObserver(this, "quit-application", false);
           Services.obs.addObserver(this, "sessionstore-state-finalized", false);
+          Services.obs.addObserver(this, "EM-loaded", false);
 
           if (gActiveExperiment) {
             this._initialized = true;
             Experiments.instance(); // for side effects
           }
         }
         break;
       case "sessionstore-state-finalized":
         if (!this._initialized) {
           CommonUtils.namedTimer(this._delayedInit, DELAY_INIT_MS, this, "_delayedInitTimer");
         }
         break;
+      case "EM-loaded":
+        if (!this._initialized) {
+          Experiments.instance(); // for side effects
+          this._initialized = true;
+
+          if (this._delayedInitTimer) {
+            this._delayedInitTimer.clear();
+          }
+        }
+        break;
       case "quit-application":
         Services.obs.removeObserver(this, "quit-application");
         Services.obs.removeObserver(this, "sessionstore-state-finalized");
+        Services.obs.removeObserver(this, "EM-loaded");
         if (this._delayedInitTimer) {
           this._delayedInitTimer.clear();
         }
         break;
     }
   },
 };
 
--- a/browser/experiments/test/xpcshell/test_api.js
+++ b/browser/experiments/test/xpcshell/test_api.js
@@ -156,18 +156,18 @@ add_task(function* test_getExperiments()
   // Trigger update, clock set to before any activation.
   // Use updateManifest() to provide for coverage of that path.
 
   let now = baseDate;
   gTimerScheduleOffset = -1;
   defineNow(gPolicy, now);
 
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
   let addons = yield getExperimentAddons();
   Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed.");
 
   // Trigger update, clock set for experiment 1 to start.
 
   now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
@@ -314,18 +314,18 @@ add_task(function* test_addonAlreadyInst
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for the experiment to start.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
@@ -618,18 +618,18 @@ add_task(function* test_installFailure()
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for experiment 1 & 2 to start,
   // invalid hash for experiment 1.
   // Order in the manifest matters, so we should start experiment 1,
   // fail to install it & start experiment 2 instead.
 
@@ -724,18 +724,18 @@ add_task(function* test_userDisabledAndU
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for experiment 1 to start.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
@@ -823,18 +823,18 @@ add_task(function* test_updateActiveExpe
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   let todayActive = yield experiments.lastActiveToday();
   Assert.equal(todayActive, null, "No experiment active today.");
 
   // Trigger update, clock set for the experiment to start.
 
@@ -914,18 +914,18 @@ add_task(function* test_disableActiveExp
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for the experiment to start.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
@@ -1007,29 +1007,29 @@ add_task(function* test_freezePendingExp
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for the experiment to start but frozen.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   gManifestObject.experiments[0].frozen = true;
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called.");
+  Assert.equal(observerFireCount, expectedObserverFireCount,
+               "Experiments observer should have not been called.");
 
   list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should have no entries yet.");
 
   // Trigger an update with the experiment not being frozen anymore.
 
   now = futureDate(now, 1 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
@@ -1085,18 +1085,18 @@ add_task(function* test_freezeActiveExpe
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for the experiment to start.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
@@ -1177,18 +1177,18 @@ add_task(function* test_removeActiveExpe
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for the experiment to start.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
@@ -1258,18 +1258,18 @@ add_task(function* test_invalidUrl() {
 
   // Trigger update, clock set for the experiment to start.
 
   let now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   gTimerScheduleOffset = null;
 
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, expectedObserverFireCount,
-               "Experiments observer should not have been called.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   Assert.equal(gTimerScheduleOffset, null, "No new timer should have been scheduled.");
 
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Cleanup.
 
   Services.obs.removeObserver(observer, OBSERVER_TOPIC);
@@ -1312,18 +1312,18 @@ add_task(function* test_unexpectedUninst
 
   let experiments = new Experiments.Experiments(gPolicy);
 
   // Trigger update, clock set to before any activation.
 
   let now = baseDate;
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
 
   // Trigger update, clock set for the experiment to start.
 
   now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
   defineNow(gPolicy, now);
   yield experiments.updateManifest();
--- a/browser/experiments/test/xpcshell/test_disableExperiments.js
+++ b/browser/experiments/test/xpcshell/test_disableExperiments.js
@@ -117,18 +117,18 @@ add_task(function* test_disableExperimen
 
   // Trigger update, clock set to before any activation.
   // Use updateManifest() to provide for coverage of that path.
 
   let now = baseDate;
   defineNow(gPolicy, now);
 
   yield experiments.updateManifest();
-  Assert.equal(observerFireCount, 0,
-               "Experiments observer should not have been called yet.");
+  Assert.equal(observerFireCount, ++expectedObserverFireCount,
+               "Experiments observer should have been called.");
   let list = yield experiments.getExperiments();
   Assert.equal(list.length, 0, "Experiment list should be empty.");
   let addons = yield getExperimentAddons();
   Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed.");
 
   // Trigger update, clock set for experiment 1 to start.
 
   now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);