Bug 989137 - Part 17: Add browser chrome testing of Experiments. r=unfocused,gfritzsche
authorGeorg Fritzsche <georg.fritzsche@googlemail.com>
Thu, 17 Apr 2014 15:47:37 +0200
changeset 197557 57bc0a61010365d8b53c82e3e12daafc7e59e438
parent 197556 71fe0bf5ef8422177624856229c083761ca89500
child 197558 36bc9e63aba710eb6b0c4ac72553d04259c073c6
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersunfocused, gfritzsche
bugs989137
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 989137 - Part 17: Add browser chrome testing of Experiments. r=unfocused,gfritzsche
testing/profiles/prefs_general.js
toolkit/mozapps/extensions/test/browser/browser_experiments.js
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -50,16 +50,19 @@ user_pref("toolkit.telemetry.notifiedOpt
 // Existing tests assume there is no font size inflation.
 user_pref("font.size.inflation.emPerLine", 0);
 user_pref("font.size.inflation.minTwips", 0);
 
 // AddonManager tests require that the experiments feature be enabled.
 user_pref("experiments.enabled", true);
 user_pref("experiments.supported", true);
 user_pref("experiments.logging.level", "Trace");
+// Point the manifest at something local so we don't risk it hitting production
+// data and installing experiments that may vary over time.
+user_pref("experiments.manifest.uri", "http://%(server)s/experiments-dummy/manifest");
 
 // Only load extensions from the application and user profile
 // AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
 user_pref("extensions.enabledScopes", 5);
 // Disable metadata caching for installed add-ons by default
 user_pref("extensions.getAddons.cache.enabled", false);
 // Disable intalling any distribution add-ons
 user_pref("extensions.installDistroAddons", false);
--- a/toolkit/mozapps/extensions/test/browser/browser_experiments.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_experiments.js
@@ -1,55 +1,70 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+let {AddonTestUtils} = Components.utils.import("resource://testing-common/AddonManagerTesting.jsm", {});
+let {HttpServer} = Components.utils.import("resource://testing-common/httpd.js", {});
+
 let gManagerWindow;
 let gCategoryUtilities;
-let gInstalledAddons = [];
-let gContext = this;
+let gExperiments;
+let gHttpServer;
+
+function getExperimentAddons() {
+  let deferred = Promise.defer();
+  AddonManager.getAddonsByTypes(["experiment"], (addons) => {
+    deferred.resolve(addons);
+  });
+  return deferred.promise;
+}
 
 add_task(function* initializeState() {
   gManagerWindow = yield open_manager();
   gCategoryUtilities = new CategoryUtilities(gManagerWindow);
 
+  registerCleanupFunction(() => {
+    if (gHttpServer) {
+      gHttpServer.stop(() => {});
+    }
+  });
+
   // The Experiments Manager will interfere with us by preventing installs
   // of experiments it doesn't know about. We remove it from the equation
   // because here we are only concerned with core Addon Manager operation,
   // not the superset Experiments Manager has imposed.
   if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
-    Components.utils.import("resource:///modules/experiments/Experiments.jsm", gContext);
-
+    let tmp = {};
+    Components.utils.import("resource:///modules/experiments/Experiments.jsm", tmp);
     // There is a race condition between XPCOM service initialization and
     // this test running. We have to initialize the instance first, then
     // uninitialize it to prevent this.
-    let instance = gContext.Experiments.instance();
-    yield instance.uninit();
+    gExperiments = tmp.Experiments.instance();
+    yield gExperiments.uninit();
   }
 });
 
 // On an empty profile with no experiments, the experiment category
 // should be hidden.
 add_task(function* testInitialState() {
   Assert.ok(gCategoryUtilities.get("experiment", false), "Experiment tab is defined.");
-
   Assert.ok(!gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab hidden by default.");
 });
 
 add_task(function* testExperimentInfoNotVisible() {
   yield gCategoryUtilities.openType("extension");
   let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
   is_element_hidden(el, "Experiment info not visible on other types.");
 });
 
 // If we have an active experiment, we should see the experiments tab
 // and that tab should have some messages.
 add_task(function* testActiveExperiment() {
   let addon = yield install_addon("addons/browser_experiment1.xpi");
-  gInstalledAddons.push(addon);
 
   Assert.ok(addon.userDisabled, "Add-on is disabled upon initial install.");
   Assert.equal(addon.isActive, false, "Add-on is not active.");
 
   Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible.");
 
   yield gCategoryUtilities.openType("experiment");
   let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
@@ -138,19 +153,132 @@ add_task(function* testButtonPresence() 
   // Corresponds to lack of disable permission.
   el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
   is_element_hidden(el, "Disable button not visible.");
   // Corresponds to lack of enable permission.
   el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
   is_element_hidden(el, "Enable button not visible.");
 });
 
+// Remove the add-on we've been testing with.
 add_task(function* testCleanup() {
-  for (let addon of gInstalledAddons) {
-    addon.uninstall();
+  yield AddonTestUtils.uninstallAddonByID("test-experiment1@experiments.mozilla.org");
+  // Verify some conditions, just in case.
+  let addons = yield getExperimentAddons();
+  Assert.equal(addons.length, 0, "No experiment add-ons are installed.");
+});
+
+// We need to initialize the experiments service for the following tests.
+add_task(function* initializeExperiments() {
+  if (!gExperiments) {
+    return;
+  }
+
+  // We need to remove the cache file to help ensure consistent state.
+  yield OS.File.remove(gExperiments._cacheFilePath);
+
+  info("Initializing experiments service.");
+  yield gExperiments.init();
+  info("Experiments service finished first run.");
+
+  // Check conditions, just to be sure.
+  let experiments = yield gExperiments.getExperiments();
+  Assert.equal(experiments.length, 0, "No experiments known to the service.");
+});
+
+// The following tests should ideally live in browser/experiments/. However,
+// they rely on some of the helper functions from head.js, which can't easily
+// be consumed from other directories. So, they live here.
+
+add_task(function* testActivateExperiment() {
+  if (!gExperiments) {
+    info("Skipping experiments test because that feature isn't available.");
+    return;
   }
 
+  gHttpServer = new HttpServer();
+  gHttpServer.start(-1);
+  let root = "http://localhost:" + gHttpServer.identity.primaryPort + "/";
+  gHttpServer.registerPathHandler("/manifest", (request, response) => {
+    response.setStatusLine(null, 200, "OK");
+    response.write(JSON.stringify({
+      "version": 1,
+      "experiments": [
+        {
+          id: "experiment-1",
+          xpiURL: TESTROOT + "addons/browser_experiment1.xpi",
+          xpiHash: "IRRELEVANT",
+          startTime: Date.now() / 1000 - 3600,
+          endTime: Date.now() / 1000 + 3600,
+          maxActiveSeconds: 600,
+          appName: [Services.appinfo.name],
+          channel: [gExperiments._policy.updatechannel()],
+        },
+      ],
+    }));
+    response.processAsync();
+    response.finish();
+  });
+
+  Services.prefs.setBoolPref("experiments.manifest.cert.checkAttributes", false);
+  Services.prefs.setCharPref("experiments.manifest.uri", root + "manifest");
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("experiments.manifest.cert.checkAttributes");
+    Services.prefs.clearUserPref("experiments.manifest.uri");
+  });
+
+  // This makes testing easier.
+  gExperiments._policy.ignoreHashes = true;
+  registerCleanupFunction(() => { gExperiments._policy.ignoreHashes = false; });
+
+  info("Manually updating experiments manifest.");
+  yield gExperiments.updateManifest();
+  info("Experiments update complete.");
+
+  let deferred = Promise.defer();
+  gHttpServer.stop(() => {
+    gHttpServer = null;
+
+    info("getting experiment by ID");
+    AddonManager.getAddonByID("test-experiment1@experiments.mozilla.org", (addon) => {
+      Assert.ok(addon, "Add-on installed via Experiments manager.");
+
+      deferred.resolve();
+    });
+  });
+
+  yield deferred.promise;
+
+  Assert.ok(gCategoryUtilities.isTypeVisible, "experiment", "Experiment tab visible.");
+  yield gCategoryUtilities.openType("experiment");
+  let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
+  is_element_visible(el, "Experiment info is visible on experiment tab.");
+});
+
+add_task(function testDeactivateExperiment() {
+  if (!gExperiments) {
+    return;
+  }
+
+  yield gExperiments._updateExperiments({
+    "version": 1,
+    "experiments": [],
+  });
+
+  yield gExperiments.disableExperiment("testing");
+});
+
+add_task(function* testCleanup() {
+  if (gExperiments) {
+    // We perform the uninit/init cycle to purge any leftover state.
+    yield OS.File.remove(gExperiments._cacheFilePath);
+    yield gExperiments.uninit();
+    yield gExperiments.init();
+  }
+
+  // Check post-conditions.
+  let addons = yield getExperimentAddons();
+  Assert.equal(addons.length, 0, "No experiment add-ons are installed.");
+
   yield close_manager(gManagerWindow);
 
-  if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
-    yield gContext.Experiments.instance().init();
-  }
 });
+