diff --git a/browser/experiments/test/experiment-1a.xpi b/browser/experiments/test/experiment-1a.xpi new file mode 100644 index 000000000000..4d67787e63e7 Binary files /dev/null and b/browser/experiments/test/experiment-1a.xpi differ diff --git a/browser/experiments/test/xpcshell/head.js b/browser/experiments/test/xpcshell/head.js index 0ef6b8f39a7c..2ee10c971c12 100644 --- a/browser/experiments/test/xpcshell/head.js +++ b/browser/experiments/test/xpcshell/head.js @@ -15,6 +15,11 @@ Cu.import("resource://gre/modules/services/healthreport/providers.jsm"); const EXPERIMENT1_ID = "test-experiment-1@tests.mozilla.org"; const EXPERIMENT1_XPI_SHA1 = "sha1:08c4d3ef1d0fc74faa455e85106ef0bc8cf8ca90"; const EXPERIMENT1_XPI_NAME = "experiment-1.xpi"; +const EXPERIMENT1_NAME = "Test experiment 1"; + +const EXPERIMENT1A_XPI_SHA1 = "sha1:2b8d14e3e06a54d5ce628fe3598cbb364cff9e6b"; +const EXPERIMENT1A_XPI_NAME = "experiment-1a.xpi"; +const EXPERIMENT1A_NAME = "Test experiment 1.1"; const EXPERIMENT2_ID = "test-experiment-2@tests.mozilla.org" const EXPERIMENT2_XPI_SHA1 = "sha1:81877991ec70360fb48db84c34a9b2da7aa41d6a"; @@ -34,6 +39,11 @@ function getReporter(name, uri, inspected) { }); } +function removeCacheFile() { + let path = OS.Path.join(OS.Constants.Path.profileDir, "experiments.json"); + return OS.File.remove(path); +} + function disableCertificateChecks() { let pref = "experiments.manifest.cert.checkAttributes"; Services.prefs.setBoolPref(pref, false); diff --git a/browser/experiments/test/xpcshell/test_activate.js b/browser/experiments/test/xpcshell/test_activate.js index 17adc8a6f226..57755e46729f 100644 --- a/browser/experiments/test/xpcshell/test_activate.js +++ b/browser/experiments/test/xpcshell/test_activate.js @@ -134,4 +134,5 @@ add_task(function* test_startStop() { add_task(function* shutdown() { yield gReporter._shutdown(); + yield removeCacheFile(); }); diff --git a/browser/experiments/test/xpcshell/test_api.js b/browser/experiments/test/xpcshell/test_api.js index b47568868172..001f50df5ee5 100644 --- a/browser/experiments/test/xpcshell/test_api.js +++ b/browser/experiments/test/xpcshell/test_api.js @@ -140,7 +140,7 @@ add_task(function* test_getExperiments() { }, { id: EXPERIMENT1_ID, - name: "Test experiment 1", + name: EXPERIMENT1_NAME, description: "Yet another experiment that experiments experimentally.", }, ]; @@ -261,6 +261,7 @@ add_task(function* test_getExperiments() { Services.obs.removeObserver(observer, OBSERVER_TOPIC); yield experiments.uninit(); + yield removeCacheFile(); }); // Test explicitly disabling experiments. @@ -293,7 +294,7 @@ add_task(function* test_disableExperiment() { let experimentInfo = { id: EXPERIMENT1_ID, - name: "Test experiment 1", + name: EXPERIMENT1_NAME, description: "Yet another experiment that experiments experimentally.", }; @@ -348,6 +349,7 @@ add_task(function* test_disableExperiment() { // Cleanup. yield experiments.uninit(); + yield removeCacheFile(); }); add_task(function* test_disableExperimentsFeature() { @@ -378,7 +380,7 @@ add_task(function* test_disableExperimentsFeature() { let experimentInfo = { id: EXPERIMENT1_ID, - name: "Test experiment 1", + name: EXPERIMENT1_NAME, description: "Yet another experiment that experiments experimentally.", }; @@ -437,6 +439,7 @@ add_task(function* test_disableExperimentsFeature() { // Cleanup. yield experiments.uninit(); + yield removeCacheFile(); }); // Test that after a failed experiment install: @@ -489,7 +492,7 @@ add_task(function* test_installFailure() { let experimentListData = [ { id: EXPERIMENT1_ID, - name: "Test experiment 1", + name: EXPERIMENT1_NAME, description: "Yet another experiment that experiments experimentally.", }, { @@ -572,6 +575,7 @@ add_task(function* test_installFailure() { Services.obs.removeObserver(observer, OBSERVER_TOPIC); yield experiments.uninit(); + yield removeCacheFile(); }); // Test that after an experiment was disabled by user action, @@ -665,8 +669,94 @@ add_task(function* test_userDisabledAndUpdated() { Services.obs.removeObserver(observer, OBSERVER_TOPIC); yield experiments.uninit(); + yield removeCacheFile(); +}); + +// Test that changing the hash for an active experiments triggers an +// update for it. + +add_task(function* test_updateActiveExperiment() { + const OBSERVER_TOPIC = "experiments-changed"; + let observerFireCount = 0; + let expectedObserverFireCount = 0; + let observer = () => ++observerFireCount; + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); + + // Dates the following tests are based on. + + let baseDate = new Date(2014, 5, 1, 12); + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); + + // The manifest data we test with. + + gManifestObject = { + "version": 1, + experiments: [ + { + id: EXPERIMENT1_ID, + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, + xpiHash: EXPERIMENT1_XPI_SHA1, + startTime: dateToSeconds(startDate), + endTime: dateToSeconds(endDate), + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, + appName: ["XPCShell"], + channel: ["nightly"], + }, + ], + }; + + 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."); + 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(); + Assert.equal(observerFireCount, ++expectedObserverFireCount, + "Experiments observer should have been called."); + + list = yield experiments.getExperiments(); + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); + Assert.equal(list[0].active, true, "Experiment 1 should be active."); + Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); + + // Trigger an update for the active experiment by changing it's hash (and xpi) + // in the manifest. + + now = futureDate(now, 1 * MS_IN_ONE_DAY); + defineNow(gPolicy, now); + gManifestObject.experiments[0].xpiHash = EXPERIMENT1A_XPI_SHA1; + gManifestObject.experiments[0].xpiURL = gDataRoot + EXPERIMENT1A_XPI_NAME; + yield experiments.updateManifest(); + Assert.equal(observerFireCount, ++expectedObserverFireCount, + "Experiments observer should have been called."); + + list = yield experiments.getExperiments(); + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); + Assert.equal(list[0].active, true, "Experiment 1 should still be active."); + Assert.equal(list[0].name, EXPERIMENT1A_NAME, "Experiments name should have been updated."); + + // Cleanup. + + Services.obs.removeObserver(observer, OBSERVER_TOPIC); + yield experiments.uninit(); + yield removeCacheFile(); }); add_task(function* shutdown() { yield gReporter._shutdown(); + yield removeCacheFile(); }); diff --git a/browser/experiments/test/xpcshell/test_conditions.js b/browser/experiments/test/xpcshell/test_conditions.js index e08f19ea1ba3..ea9a68bd254a 100644 --- a/browser/experiments/test/xpcshell/test_conditions.js +++ b/browser/experiments/test/xpcshell/test_conditions.js @@ -170,4 +170,5 @@ add_task(function* test_times() { add_task(function* shutdown() { yield gReporter._shutdown(); + yield removeCacheFile(); }); diff --git a/browser/experiments/test/xpcshell/test_fetch.js b/browser/experiments/test/xpcshell/test_fetch.js index 0a6d5a5c982c..0599b62fc559 100644 --- a/browser/experiments/test/xpcshell/test_fetch.js +++ b/browser/experiments/test/xpcshell/test_fetch.js @@ -8,7 +8,6 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/osfile.jsm"); Cu.import("resource:///modules/experiments/Experiments.jsm"); -const FILE_CACHE = "experiments.json"; const PREF_EXPERIMENTS_ENABLED = "experiments.enabled"; const PREF_LOGGING_LEVEL = "experiments.logging.level"; const PREF_LOGGING_DUMP = "experiments.logging.dump"; @@ -20,11 +19,6 @@ let gHttpServer = null; let gHttpRoot = null; let gPolicy = new Experiments.Policy(); -function removeCacheFile() { - let path = OS.Path.join(OS.Constants.Path.profileDir, FILE_CACHE); - return OS.File.remove(path); -} - function run_test() { createAppInfo(); gProfileDir = do_get_profile(); @@ -84,3 +78,7 @@ add_task(function* test_fetchInvalid() { yield ex.uninit(); }); + +add_task(function* shutdown() { + yield removeCacheFile(); +}); diff --git a/browser/experiments/test/xpcshell/xpcshell.ini b/browser/experiments/test/xpcshell/xpcshell.ini index cf5eb9317799..94b245c1f091 100644 --- a/browser/experiments/test/xpcshell/xpcshell.ini +++ b/browser/experiments/test/xpcshell/xpcshell.ini @@ -5,9 +5,10 @@ firefox-appdir = browser support-files = experiments_1.manifest ../experiment-1.xpi + ../experiment-1a.xpi ../experiment-2.xpi [test_activate.js] [test_api.js] [test_conditions.js] -[test_fetch.js] \ No newline at end of file +[test_fetch.js]