1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/experiments/test/xpcshell/test_api.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1602 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +"use strict"; 1.8 + 1.9 +Cu.import("resource://testing-common/httpd.js"); 1.10 +Cu.import("resource://testing-common/AddonManagerTesting.jsm"); 1.11 + 1.12 +XPCOMUtils.defineLazyModuleGetter(this, "Experiments", 1.13 + "resource:///modules/experiments/Experiments.jsm"); 1.14 + 1.15 +const FILE_MANIFEST = "experiments.manifest"; 1.16 +const MANIFEST_HANDLER = "manifests/handler"; 1.17 + 1.18 +const SEC_IN_ONE_DAY = 24 * 60 * 60; 1.19 +const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; 1.20 + 1.21 +let gProfileDir = null; 1.22 +let gHttpServer = null; 1.23 +let gHttpRoot = null; 1.24 +let gDataRoot = null; 1.25 +let gReporter = null; 1.26 +let gPolicy = null; 1.27 +let gManifestObject = null; 1.28 +let gManifestHandlerURI = null; 1.29 +let gTimerScheduleOffset = -1; 1.30 + 1.31 +function uninstallExperimentAddons() { 1.32 + return Task.spawn(function* () { 1.33 + let addons = yield getExperimentAddons(); 1.34 + for (let a of addons) { 1.35 + yield AddonTestUtils.uninstallAddonByID(a.id); 1.36 + } 1.37 + }); 1.38 +} 1.39 + 1.40 +function testCleanup(experimentsInstance) { 1.41 + return Task.spawn(function* () { 1.42 + yield experimentsInstance.uninit(); 1.43 + yield removeCacheFile(); 1.44 + yield uninstallExperimentAddons(); 1.45 + restartManager(); 1.46 + }); 1.47 +} 1.48 + 1.49 +function run_test() { 1.50 + run_next_test(); 1.51 +} 1.52 + 1.53 +add_task(function* test_setup() { 1.54 + loadAddonManager(); 1.55 + gProfileDir = do_get_profile(); 1.56 + 1.57 + gHttpServer = new HttpServer(); 1.58 + gHttpServer.start(-1); 1.59 + let port = gHttpServer.identity.primaryPort; 1.60 + gHttpRoot = "http://localhost:" + port + "/"; 1.61 + gDataRoot = gHttpRoot + "data/"; 1.62 + gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; 1.63 + gHttpServer.registerDirectory("/data/", do_get_cwd()); 1.64 + gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { 1.65 + response.setStatusLine(null, 200, "OK"); 1.66 + response.write(JSON.stringify(gManifestObject)); 1.67 + response.processAsync(); 1.68 + response.finish(); 1.69 + }); 1.70 + do_register_cleanup(() => gHttpServer.stop(() => {})); 1.71 + 1.72 + disableCertificateChecks(); 1.73 + 1.74 + Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); 1.75 + Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); 1.76 + Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); 1.77 + Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); 1.78 + Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); 1.79 + 1.80 + gReporter = yield getReporter("json_payload_simple"); 1.81 + yield gReporter.collectMeasurements(); 1.82 + let payload = yield gReporter.getJSONPayload(true); 1.83 + do_register_cleanup(() => gReporter._shutdown()); 1.84 + 1.85 + gPolicy = new Experiments.Policy(); 1.86 + patchPolicy(gPolicy, { 1.87 + updatechannel: () => "nightly", 1.88 + healthReportPayload: () => Promise.resolve(payload), 1.89 + oneshotTimer: (callback, timeout, thisObj, name) => gTimerScheduleOffset = timeout, 1.90 + }); 1.91 +}); 1.92 + 1.93 +add_task(function* test_contract() { 1.94 + Cc["@mozilla.org/browser/experiments-service;1"].getService(); 1.95 +}); 1.96 + 1.97 +// Test basic starting and stopping of experiments. 1.98 + 1.99 +add_task(function* test_getExperiments() { 1.100 + const OBSERVER_TOPIC = "experiments-changed"; 1.101 + let observerFireCount = 0; 1.102 + let expectedObserverFireCount = 0; 1.103 + let observer = () => ++observerFireCount; 1.104 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.105 + 1.106 + // Dates the following tests are based on. 1.107 + 1.108 + let baseDate = new Date(2014, 5, 1, 12); 1.109 + let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); 1.110 + let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.111 + let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY); 1.112 + let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY); 1.113 + 1.114 + // The manifest data we test with. 1.115 + 1.116 + gManifestObject = { 1.117 + "version": 1, 1.118 + experiments: [ 1.119 + { 1.120 + id: EXPERIMENT2_ID, 1.121 + xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, 1.122 + xpiHash: EXPERIMENT2_XPI_SHA1, 1.123 + startTime: dateToSeconds(startDate2), 1.124 + endTime: dateToSeconds(endDate2), 1.125 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.126 + appName: ["XPCShell"], 1.127 + channel: ["nightly"], 1.128 + }, 1.129 + { 1.130 + id: EXPERIMENT1_ID, 1.131 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.132 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.133 + startTime: dateToSeconds(startDate1), 1.134 + endTime: dateToSeconds(endDate1), 1.135 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.136 + appName: ["XPCShell"], 1.137 + channel: ["nightly"], 1.138 + }, 1.139 + ], 1.140 + }; 1.141 + 1.142 + // Data to compare the result of Experiments.getExperiments() against. 1.143 + 1.144 + let experimentListData = [ 1.145 + { 1.146 + id: EXPERIMENT2_ID, 1.147 + name: "Test experiment 2", 1.148 + description: "And yet another experiment that experiments experimentally.", 1.149 + }, 1.150 + { 1.151 + id: EXPERIMENT1_ID, 1.152 + name: EXPERIMENT1_NAME, 1.153 + description: "Yet another experiment that experiments experimentally.", 1.154 + }, 1.155 + ]; 1.156 + 1.157 + let experiments = new Experiments.Experiments(gPolicy); 1.158 + 1.159 + // Trigger update, clock set to before any activation. 1.160 + // Use updateManifest() to provide for coverage of that path. 1.161 + 1.162 + let now = baseDate; 1.163 + gTimerScheduleOffset = -1; 1.164 + defineNow(gPolicy, now); 1.165 + 1.166 + yield experiments.updateManifest(); 1.167 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.168 + "Experiments observer should have been called."); 1.169 + Assert.equal(experiments.getActiveExperimentID(), null, 1.170 + "getActiveExperimentID should return null"); 1.171 + 1.172 + let list = yield experiments.getExperiments(); 1.173 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.174 + let addons = yield getExperimentAddons(); 1.175 + Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed."); 1.176 + 1.177 + try { 1.178 + let b = yield experiments.getExperimentBranch(); 1.179 + Assert.ok(false, "getExperimentBranch should fail with no experiment"); 1.180 + } 1.181 + catch (e) { 1.182 + Assert.ok(true, "getExperimentBranch correctly threw"); 1.183 + } 1.184 + 1.185 + // Trigger update, clock set for experiment 1 to start. 1.186 + 1.187 + now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); 1.188 + gTimerScheduleOffset = -1; 1.189 + defineNow(gPolicy, now); 1.190 + 1.191 + yield experiments.updateManifest(); 1.192 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.193 + "Experiments observer should have been called."); 1.194 + 1.195 + Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID, 1.196 + "getActiveExperimentID should return the active experiment1"); 1.197 + 1.198 + list = yield experiments.getExperiments(); 1.199 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.200 + addons = yield getExperimentAddons(); 1.201 + Assert.equal(addons.length, 1, "An experiment add-on was installed."); 1.202 + 1.203 + experimentListData[1].active = true; 1.204 + experimentListData[1].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; 1.205 + for (let k of Object.keys(experimentListData[1])) { 1.206 + Assert.equal(experimentListData[1][k], list[0][k], 1.207 + "Property " + k + " should match reference data."); 1.208 + } 1.209 + 1.210 + let b = yield experiments.getExperimentBranch(); 1.211 + Assert.strictEqual(b, null, "getExperimentBranch should return null by default"); 1.212 + 1.213 + b = yield experiments.getExperimentBranch(EXPERIMENT1_ID); 1.214 + Assert.strictEqual(b, null, "getExperimentsBranch should return null (with id)"); 1.215 + 1.216 + yield experiments.setExperimentBranch(EXPERIMENT1_ID, "foo"); 1.217 + b = yield experiments.getExperimentBranch(); 1.218 + Assert.strictEqual(b, "foo", "getExperimentsBranch should return the set value"); 1.219 + 1.220 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.221 + "Experiments observer should have been called."); 1.222 + 1.223 + Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY, 1.224 + "Experiment re-evaluation should have been scheduled correctly."); 1.225 + 1.226 + // Trigger update, clock set for experiment 1 to stop. 1.227 + 1.228 + now = futureDate(endDate1, 1000); 1.229 + gTimerScheduleOffset = -1; 1.230 + defineNow(gPolicy, now); 1.231 + 1.232 + yield experiments.updateManifest(); 1.233 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.234 + "Experiments observer should have been called."); 1.235 + 1.236 + Assert.equal(experiments.getActiveExperimentID(), null, 1.237 + "getActiveExperimentID should return null again"); 1.238 + 1.239 + list = yield experiments.getExperiments(); 1.240 + Assert.equal(list.length, 1, "Experiment list should have 1 entry."); 1.241 + addons = yield getExperimentAddons(); 1.242 + Assert.equal(addons.length, 0, "The experiment add-on should be uninstalled."); 1.243 + 1.244 + experimentListData[1].active = false; 1.245 + experimentListData[1].endDate = now.getTime(); 1.246 + for (let k of Object.keys(experimentListData[1])) { 1.247 + Assert.equal(experimentListData[1][k], list[0][k], 1.248 + "Property " + k + " should match reference data."); 1.249 + } 1.250 + 1.251 + Assert.equal(gTimerScheduleOffset, startDate2 - now, 1.252 + "Experiment re-evaluation should have been scheduled correctly."); 1.253 + 1.254 + // Trigger update, clock set for experiment 2 to start. 1.255 + // Use notify() to provide for coverage of that path. 1.256 + 1.257 + now = startDate2; 1.258 + gTimerScheduleOffset = -1; 1.259 + defineNow(gPolicy, now); 1.260 + 1.261 + yield experiments.notify(); 1.262 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.263 + "Experiments observer should have been called."); 1.264 + 1.265 + Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT2_ID, 1.266 + "getActiveExperimentID should return the active experiment2"); 1.267 + 1.268 + list = yield experiments.getExperiments(); 1.269 + Assert.equal(list.length, 2, "Experiment list should have 2 entries now."); 1.270 + addons = yield getExperimentAddons(); 1.271 + Assert.equal(addons.length, 1, "An experiment add-on is installed."); 1.272 + 1.273 + experimentListData[0].active = true; 1.274 + experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; 1.275 + for (let i=0; i<experimentListData.length; ++i) { 1.276 + let entry = experimentListData[i]; 1.277 + for (let k of Object.keys(entry)) { 1.278 + Assert.equal(entry[k], list[i][k], 1.279 + "Entry " + i + " - Property '" + k + "' should match reference data."); 1.280 + } 1.281 + } 1.282 + 1.283 + Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY, 1.284 + "Experiment re-evaluation should have been scheduled correctly."); 1.285 + 1.286 + // Trigger update, clock set for experiment 2 to stop. 1.287 + 1.288 + now = futureDate(startDate2, 10 * MS_IN_ONE_DAY + 1000); 1.289 + gTimerScheduleOffset = -1; 1.290 + defineNow(gPolicy, now); 1.291 + yield experiments.notify(); 1.292 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.293 + "Experiments observer should have been called."); 1.294 + 1.295 + Assert.equal(experiments.getActiveExperimentID(), null, 1.296 + "getActiveExperimentID should return null again2"); 1.297 + 1.298 + list = yield experiments.getExperiments(); 1.299 + Assert.equal(list.length, 2, "Experiment list should have 2 entries now."); 1.300 + addons = yield getExperimentAddons(); 1.301 + Assert.equal(addons.length, 0, "No experiments add-ons are installed."); 1.302 + 1.303 + experimentListData[0].active = false; 1.304 + experimentListData[0].endDate = now.getTime(); 1.305 + for (let i=0; i<experimentListData.length; ++i) { 1.306 + let entry = experimentListData[i]; 1.307 + for (let k of Object.keys(entry)) { 1.308 + Assert.equal(entry[k], list[i][k], 1.309 + "Entry " + i + " - Property '" + k + "' should match reference data."); 1.310 + } 1.311 + } 1.312 + 1.313 + // Cleanup. 1.314 + 1.315 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.316 + yield testCleanup(experiments); 1.317 +}); 1.318 + 1.319 +add_task(function* test_getActiveExperimentID() { 1.320 + // Check that getActiveExperimentID returns the correct result even 1.321 + // after .uninit() 1.322 + 1.323 + // Dates the following tests are based on. 1.324 + 1.325 + let baseDate = new Date(2014, 5, 1, 12); 1.326 + let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); 1.327 + let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.328 + 1.329 + gManifestObject = { 1.330 + "version": 1, 1.331 + experiments: [ 1.332 + { 1.333 + id: EXPERIMENT1_ID, 1.334 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.335 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.336 + startTime: dateToSeconds(startDate1), 1.337 + endTime: dateToSeconds(endDate1), 1.338 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.339 + appName: ["XPCShell"], 1.340 + channel: ["nightly"], 1.341 + }, 1.342 + ], 1.343 + }; 1.344 + 1.345 + let now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); 1.346 + gTimerScheduleOffset = -1; 1.347 + defineNow(gPolicy, now); 1.348 + 1.349 + let experiments = new Experiments.Experiments(gPolicy); 1.350 + yield experiments.updateManifest(); 1.351 + 1.352 + Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID, 1.353 + "getActiveExperimentID should return the active experiment1"); 1.354 + 1.355 + yield experiments.uninit(); 1.356 + Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID, 1.357 + "getActiveExperimentID should return the active experiment1 after uninit()"); 1.358 + 1.359 + yield testCleanup(experiments); 1.360 +}); 1.361 + 1.362 +// Test that we handle the experiments addon already being 1.363 +// installed properly. 1.364 +// We should just pave over them. 1.365 + 1.366 +add_task(function* test_addonAlreadyInstalled() { 1.367 + const OBSERVER_TOPIC = "experiments-changed"; 1.368 + let observerFireCount = 0; 1.369 + let expectedObserverFireCount = 0; 1.370 + let observer = () => ++observerFireCount; 1.371 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.372 + 1.373 + // Dates the following tests are based on. 1.374 + 1.375 + let baseDate = new Date(2014, 5, 1, 12); 1.376 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.377 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.378 + 1.379 + // The manifest data we test with. 1.380 + 1.381 + gManifestObject = { 1.382 + "version": 1, 1.383 + experiments: [ 1.384 + { 1.385 + id: EXPERIMENT1_ID, 1.386 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.387 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.388 + startTime: dateToSeconds(startDate), 1.389 + endTime: dateToSeconds(endDate), 1.390 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.391 + appName: ["XPCShell"], 1.392 + channel: ["nightly"], 1.393 + }, 1.394 + ], 1.395 + }; 1.396 + 1.397 + let experiments = new Experiments.Experiments(gPolicy); 1.398 + 1.399 + // Trigger update, clock set to before any activation. 1.400 + 1.401 + let now = baseDate; 1.402 + defineNow(gPolicy, now); 1.403 + yield experiments.updateManifest(); 1.404 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.405 + "Experiments observer should have been called."); 1.406 + let list = yield experiments.getExperiments(); 1.407 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.408 + 1.409 + // Trigger update, clock set for the experiment to start. 1.410 + 1.411 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.412 + defineNow(gPolicy, now); 1.413 + yield experiments.updateManifest(); 1.414 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.415 + "Experiments observer should have been called."); 1.416 + 1.417 + list = yield experiments.getExperiments(); 1.418 + list = yield experiments.getExperiments(); 1.419 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.420 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.421 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.422 + 1.423 + let addons = yield getExperimentAddons(); 1.424 + Assert.equal(addons.length, 1, "1 add-on is installed."); 1.425 + 1.426 + // Install conflicting addon. 1.427 + 1.428 + yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1); 1.429 + addons = yield getExperimentAddons(); 1.430 + Assert.equal(addons.length, 1, "1 add-on is installed."); 1.431 + list = yield experiments.getExperiments(); 1.432 + Assert.equal(list.length, 1, "Experiment list should still have 1 entry."); 1.433 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.434 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.435 + 1.436 + // Cleanup. 1.437 + 1.438 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.439 + yield testCleanup(experiments); 1.440 +}); 1.441 + 1.442 +add_task(function* test_lastActiveToday() { 1.443 + let experiments = new Experiments.Experiments(gPolicy); 1.444 + 1.445 + replaceExperiments(experiments, FAKE_EXPERIMENTS_1); 1.446 + 1.447 + let e = yield experiments.getExperiments(); 1.448 + Assert.equal(e.length, 1, "Monkeypatch successful."); 1.449 + Assert.equal(e[0].id, "id1", "ID looks sane"); 1.450 + Assert.ok(e[0].active, "Experiment is active."); 1.451 + 1.452 + let lastActive = yield experiments.lastActiveToday(); 1.453 + Assert.equal(e[0], lastActive, "Last active object is expected."); 1.454 + 1.455 + replaceExperiments(experiments, FAKE_EXPERIMENTS_2); 1.456 + e = yield experiments.getExperiments(); 1.457 + Assert.equal(e.length, 2, "Monkeypatch successful."); 1.458 + 1.459 + defineNow(gPolicy, e[0].endDate); 1.460 + 1.461 + lastActive = yield experiments.lastActiveToday(); 1.462 + Assert.ok(lastActive, "Have a last active experiment"); 1.463 + Assert.equal(lastActive, e[0], "Last active object is expected."); 1.464 + 1.465 + yield testCleanup(experiments); 1.466 +}); 1.467 + 1.468 +// Test explicitly disabling experiments. 1.469 + 1.470 +add_task(function* test_disableExperiment() { 1.471 + // Dates this test is based on. 1.472 + 1.473 + let startDate = new Date(2004, 10, 9, 12); 1.474 + let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY); 1.475 + 1.476 + // The manifest data we test with. 1.477 + 1.478 + gManifestObject = { 1.479 + "version": 1, 1.480 + experiments: [ 1.481 + { 1.482 + id: EXPERIMENT1_ID, 1.483 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.484 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.485 + startTime: dateToSeconds(startDate), 1.486 + endTime: dateToSeconds(endDate), 1.487 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.488 + appName: ["XPCShell"], 1.489 + channel: ["nightly"], 1.490 + }, 1.491 + ], 1.492 + }; 1.493 + 1.494 + // Data to compare the result of Experiments.getExperiments() against. 1.495 + 1.496 + let experimentInfo = { 1.497 + id: EXPERIMENT1_ID, 1.498 + name: EXPERIMENT1_NAME, 1.499 + description: "Yet another experiment that experiments experimentally.", 1.500 + }; 1.501 + 1.502 + let experiments = new Experiments.Experiments(gPolicy); 1.503 + 1.504 + // Trigger update, clock set for the experiment to start. 1.505 + 1.506 + let now = futureDate(startDate, 5 * MS_IN_ONE_DAY); 1.507 + defineNow(gPolicy, now); 1.508 + yield experiments.updateManifest(); 1.509 + 1.510 + let list = yield experiments.getExperiments(); 1.511 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.512 + 1.513 + experimentInfo.active = true; 1.514 + experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY; 1.515 + for (let k of Object.keys(experimentInfo)) { 1.516 + Assert.equal(experimentInfo[k], list[0][k], 1.517 + "Property " + k + " should match reference data."); 1.518 + } 1.519 + 1.520 + // Test disabling the experiment. 1.521 + 1.522 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.523 + defineNow(gPolicy, now); 1.524 + yield experiments.disableExperiment("foo"); 1.525 + 1.526 + list = yield experiments.getExperiments(); 1.527 + Assert.equal(list.length, 1, "Experiment list should have 1 entry."); 1.528 + 1.529 + experimentInfo.active = false; 1.530 + experimentInfo.endDate = now.getTime(); 1.531 + for (let k of Object.keys(experimentInfo)) { 1.532 + Assert.equal(experimentInfo[k], list[0][k], 1.533 + "Property " + k + " should match reference data."); 1.534 + } 1.535 + 1.536 + // Test that updating the list doesn't re-enable it. 1.537 + 1.538 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.539 + defineNow(gPolicy, now); 1.540 + yield experiments.updateManifest(); 1.541 + 1.542 + list = yield experiments.getExperiments(); 1.543 + Assert.equal(list.length, 1, "Experiment list should have 1 entry."); 1.544 + 1.545 + for (let k of Object.keys(experimentInfo)) { 1.546 + Assert.equal(experimentInfo[k], list[0][k], 1.547 + "Property " + k + " should match reference data."); 1.548 + } 1.549 + 1.550 + yield testCleanup(experiments); 1.551 +}); 1.552 + 1.553 +add_task(function* test_disableExperimentsFeature() { 1.554 + // Dates this test is based on. 1.555 + 1.556 + let startDate = new Date(2004, 10, 9, 12); 1.557 + let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY); 1.558 + 1.559 + // The manifest data we test with. 1.560 + 1.561 + gManifestObject = { 1.562 + "version": 1, 1.563 + experiments: [ 1.564 + { 1.565 + id: EXPERIMENT1_ID, 1.566 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.567 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.568 + startTime: dateToSeconds(startDate), 1.569 + endTime: dateToSeconds(endDate), 1.570 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.571 + appName: ["XPCShell"], 1.572 + channel: ["nightly"], 1.573 + }, 1.574 + ], 1.575 + }; 1.576 + 1.577 + // Data to compare the result of Experiments.getExperiments() against. 1.578 + 1.579 + let experimentInfo = { 1.580 + id: EXPERIMENT1_ID, 1.581 + name: EXPERIMENT1_NAME, 1.582 + description: "Yet another experiment that experiments experimentally.", 1.583 + }; 1.584 + 1.585 + let experiments = new Experiments.Experiments(gPolicy); 1.586 + Assert.equal(experiments.enabled, true, "Experiments feature should be enabled."); 1.587 + 1.588 + // Trigger update, clock set for the experiment to start. 1.589 + 1.590 + let now = futureDate(startDate, 5 * MS_IN_ONE_DAY); 1.591 + defineNow(gPolicy, now); 1.592 + yield experiments.updateManifest(); 1.593 + 1.594 + let list = yield experiments.getExperiments(); 1.595 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.596 + 1.597 + experimentInfo.active = true; 1.598 + experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY; 1.599 + for (let k of Object.keys(experimentInfo)) { 1.600 + Assert.equal(experimentInfo[k], list[0][k], 1.601 + "Property " + k + " should match reference data."); 1.602 + } 1.603 + 1.604 + // Test disabling experiments. 1.605 + 1.606 + experiments._toggleExperimentsEnabled(false); 1.607 + yield experiments.notify(); 1.608 + Assert.equal(experiments.enabled, false, "Experiments feature should be disabled now."); 1.609 + 1.610 + list = yield experiments.getExperiments(); 1.611 + Assert.equal(list.length, 1, "Experiment list should have 1 entry."); 1.612 + 1.613 + experimentInfo.active = false; 1.614 + experimentInfo.endDate = now.getTime(); 1.615 + for (let k of Object.keys(experimentInfo)) { 1.616 + Assert.equal(experimentInfo[k], list[0][k], 1.617 + "Property " + k + " should match reference data."); 1.618 + } 1.619 + 1.620 + // Test that updating the list doesn't re-enable it. 1.621 + 1.622 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.623 + defineNow(gPolicy, now); 1.624 + try { 1.625 + yield experiments.updateManifest(); 1.626 + } catch (e) { 1.627 + // Exception expected, the feature is disabled. 1.628 + } 1.629 + 1.630 + list = yield experiments.getExperiments(); 1.631 + Assert.equal(list.length, 1, "Experiment list should have 1 entry."); 1.632 + 1.633 + for (let k of Object.keys(experimentInfo)) { 1.634 + Assert.equal(experimentInfo[k], list[0][k], 1.635 + "Property " + k + " should match reference data."); 1.636 + } 1.637 + 1.638 + yield testCleanup(experiments); 1.639 +}); 1.640 + 1.641 +// Test that after a failed experiment install: 1.642 +// * the next applicable experiment gets installed 1.643 +// * changing the experiments data later triggers re-evaluation 1.644 + 1.645 +add_task(function* test_installFailure() { 1.646 + const OBSERVER_TOPIC = "experiments-changed"; 1.647 + let observerFireCount = 0; 1.648 + let expectedObserverFireCount = 0; 1.649 + let observer = () => ++observerFireCount; 1.650 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.651 + 1.652 + // Dates the following tests are based on. 1.653 + 1.654 + let baseDate = new Date(2014, 5, 1, 12); 1.655 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.656 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.657 + 1.658 + // The manifest data we test with. 1.659 + 1.660 + gManifestObject = { 1.661 + "version": 1, 1.662 + experiments: [ 1.663 + { 1.664 + id: EXPERIMENT1_ID, 1.665 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.666 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.667 + startTime: dateToSeconds(startDate), 1.668 + endTime: dateToSeconds(endDate), 1.669 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.670 + appName: ["XPCShell"], 1.671 + channel: ["nightly"], 1.672 + }, 1.673 + { 1.674 + id: EXPERIMENT2_ID, 1.675 + xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, 1.676 + xpiHash: EXPERIMENT2_XPI_SHA1, 1.677 + startTime: dateToSeconds(startDate), 1.678 + endTime: dateToSeconds(endDate), 1.679 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.680 + appName: ["XPCShell"], 1.681 + channel: ["nightly"], 1.682 + }, 1.683 + ], 1.684 + }; 1.685 + 1.686 + // Data to compare the result of Experiments.getExperiments() against. 1.687 + 1.688 + let experimentListData = [ 1.689 + { 1.690 + id: EXPERIMENT1_ID, 1.691 + name: EXPERIMENT1_NAME, 1.692 + description: "Yet another experiment that experiments experimentally.", 1.693 + }, 1.694 + { 1.695 + id: EXPERIMENT2_ID, 1.696 + name: "Test experiment 2", 1.697 + description: "And yet another experiment that experiments experimentally.", 1.698 + }, 1.699 + ]; 1.700 + 1.701 + let experiments = new Experiments.Experiments(gPolicy); 1.702 + 1.703 + // Trigger update, clock set to before any activation. 1.704 + 1.705 + let now = baseDate; 1.706 + defineNow(gPolicy, now); 1.707 + yield experiments.updateManifest(); 1.708 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.709 + "Experiments observer should have been called."); 1.710 + let list = yield experiments.getExperiments(); 1.711 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.712 + 1.713 + // Trigger update, clock set for experiment 1 & 2 to start, 1.714 + // invalid hash for experiment 1. 1.715 + // Order in the manifest matters, so we should start experiment 1, 1.716 + // fail to install it & start experiment 2 instead. 1.717 + 1.718 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.719 + defineNow(gPolicy, now); 1.720 + gManifestObject.experiments[0].xpiHash = "sha1:0000000000000000000000000000000000000000"; 1.721 + yield experiments.updateManifest(); 1.722 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.723 + "Experiments observer should have been called."); 1.724 + 1.725 + list = yield experiments.getExperiments(); 1.726 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.727 + Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry."); 1.728 + Assert.equal(list[0].active, true, "Experiment 2 should be active."); 1.729 + 1.730 + // Trigger update, clock set for experiment 2 to stop. 1.731 + 1.732 + now = futureDate(now, 20 * MS_IN_ONE_DAY); 1.733 + defineNow(gPolicy, now); 1.734 + yield experiments.updateManifest(); 1.735 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.736 + "Experiments observer should have been called."); 1.737 + 1.738 + experimentListData[0].active = false; 1.739 + experimentListData[0].endDate = now; 1.740 + 1.741 + list = yield experiments.getExperiments(); 1.742 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.743 + Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry."); 1.744 + Assert.equal(list[0].active, false, "Experiment should not be active."); 1.745 + 1.746 + // Trigger update with a fixed entry for experiment 1, 1.747 + // which should get re-evaluated & started now. 1.748 + 1.749 + now = futureDate(now, 20 * MS_IN_ONE_DAY); 1.750 + defineNow(gPolicy, now); 1.751 + gManifestObject.experiments[0].xpiHash = EXPERIMENT1_XPI_SHA1; 1.752 + yield experiments.updateManifest(); 1.753 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.754 + "Experiments observer should have been called."); 1.755 + 1.756 + experimentListData[0].active = true; 1.757 + experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY; 1.758 + 1.759 + list = yield experiments.getExperiments(); 1.760 + Assert.equal(list.length, 2, "Experiment list should have 2 entries now."); 1.761 + 1.762 + for (let i=0; i<experimentListData.length; ++i) { 1.763 + let entry = experimentListData[i]; 1.764 + for (let k of Object.keys(entry)) { 1.765 + Assert.equal(entry[k], list[i][k], 1.766 + "Entry " + i + " - Property '" + k + "' should match reference data."); 1.767 + } 1.768 + } 1.769 + 1.770 + yield testCleanup(experiments); 1.771 +}); 1.772 + 1.773 +// Test that after an experiment was disabled by user action, 1.774 +// the experiment is not activated again if manifest data changes. 1.775 + 1.776 +add_task(function* test_userDisabledAndUpdated() { 1.777 + const OBSERVER_TOPIC = "experiments-changed"; 1.778 + let observerFireCount = 0; 1.779 + let expectedObserverFireCount = 0; 1.780 + let observer = () => ++observerFireCount; 1.781 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.782 + 1.783 + // Dates the following tests are based on. 1.784 + 1.785 + let baseDate = new Date(2014, 5, 1, 12); 1.786 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.787 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.788 + 1.789 + // The manifest data we test with. 1.790 + 1.791 + gManifestObject = { 1.792 + "version": 1, 1.793 + experiments: [ 1.794 + { 1.795 + id: EXPERIMENT1_ID, 1.796 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.797 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.798 + startTime: dateToSeconds(startDate), 1.799 + endTime: dateToSeconds(endDate), 1.800 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.801 + appName: ["XPCShell"], 1.802 + channel: ["nightly"], 1.803 + }, 1.804 + ], 1.805 + }; 1.806 + 1.807 + let experiments = new Experiments.Experiments(gPolicy); 1.808 + 1.809 + // Trigger update, clock set to before any activation. 1.810 + 1.811 + let now = baseDate; 1.812 + defineNow(gPolicy, now); 1.813 + yield experiments.updateManifest(); 1.814 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.815 + "Experiments observer should have been called."); 1.816 + let list = yield experiments.getExperiments(); 1.817 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.818 + 1.819 + // Trigger update, clock set for experiment 1 to start. 1.820 + 1.821 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.822 + defineNow(gPolicy, now); 1.823 + yield experiments.updateManifest(); 1.824 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.825 + "Experiments observer should have been called."); 1.826 + 1.827 + list = yield experiments.getExperiments(); 1.828 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.829 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.830 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.831 + let todayActive = yield experiments.lastActiveToday(); 1.832 + Assert.ok(todayActive, "Last active for today reports a value."); 1.833 + Assert.equal(todayActive.id, list[0].id, "The entry is what we expect."); 1.834 + 1.835 + // Explicitly disable an experiment. 1.836 + 1.837 + now = futureDate(now, 20 * MS_IN_ONE_DAY); 1.838 + defineNow(gPolicy, now); 1.839 + yield experiments.disableExperiment("foo"); 1.840 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.841 + "Experiments observer should have been called."); 1.842 + 1.843 + list = yield experiments.getExperiments(); 1.844 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.845 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.846 + Assert.equal(list[0].active, false, "Experiment should not be active anymore."); 1.847 + todayActive = yield experiments.lastActiveToday(); 1.848 + Assert.ok(todayActive, "Last active for today still returns a value."); 1.849 + Assert.equal(todayActive.id, list[0].id, "The ID is still the same."); 1.850 + 1.851 + // Trigger an update with a faked change for experiment 1. 1.852 + 1.853 + now = futureDate(now, 20 * MS_IN_ONE_DAY); 1.854 + defineNow(gPolicy, now); 1.855 + experiments._experiments.get(EXPERIMENT1_ID)._manifestData.xpiHash = 1.856 + "sha1:0000000000000000000000000000000000000000"; 1.857 + yield experiments.updateManifest(); 1.858 + Assert.equal(observerFireCount, expectedObserverFireCount, 1.859 + "Experiments observer should not have been called."); 1.860 + 1.861 + list = yield experiments.getExperiments(); 1.862 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.863 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.864 + Assert.equal(list[0].active, false, "Experiment should still be inactive."); 1.865 + 1.866 + // Cleanup. 1.867 + 1.868 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.869 + yield testCleanup(experiments); 1.870 +}); 1.871 + 1.872 +// Test that changing the hash for an active experiments triggers an 1.873 +// update for it. 1.874 + 1.875 +add_task(function* test_updateActiveExperiment() { 1.876 + const OBSERVER_TOPIC = "experiments-changed"; 1.877 + let observerFireCount = 0; 1.878 + let expectedObserverFireCount = 0; 1.879 + let observer = () => ++observerFireCount; 1.880 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.881 + 1.882 + // Dates the following tests are based on. 1.883 + 1.884 + let baseDate = new Date(2014, 5, 1, 12); 1.885 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.886 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.887 + 1.888 + // The manifest data we test with. 1.889 + 1.890 + gManifestObject = { 1.891 + "version": 1, 1.892 + experiments: [ 1.893 + { 1.894 + id: EXPERIMENT1_ID, 1.895 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.896 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.897 + startTime: dateToSeconds(startDate), 1.898 + endTime: dateToSeconds(endDate), 1.899 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.900 + appName: ["XPCShell"], 1.901 + channel: ["nightly"], 1.902 + }, 1.903 + ], 1.904 + }; 1.905 + 1.906 + let experiments = new Experiments.Experiments(gPolicy); 1.907 + 1.908 + // Trigger update, clock set to before any activation. 1.909 + 1.910 + let now = baseDate; 1.911 + defineNow(gPolicy, now); 1.912 + yield experiments.updateManifest(); 1.913 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.914 + "Experiments observer should have been called."); 1.915 + let list = yield experiments.getExperiments(); 1.916 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.917 + 1.918 + let todayActive = yield experiments.lastActiveToday(); 1.919 + Assert.equal(todayActive, null, "No experiment active today."); 1.920 + 1.921 + // Trigger update, clock set for the experiment to start. 1.922 + 1.923 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.924 + defineNow(gPolicy, now); 1.925 + yield experiments.updateManifest(); 1.926 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.927 + "Experiments observer should have been called."); 1.928 + 1.929 + list = yield experiments.getExperiments(); 1.930 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.931 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.932 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.933 + Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); 1.934 + todayActive = yield experiments.lastActiveToday(); 1.935 + Assert.ok(todayActive, "todayActive() returns a value."); 1.936 + Assert.equal(todayActive.id, list[0].id, "It returns the active experiment."); 1.937 + 1.938 + // Trigger an update for the active experiment by changing it's hash (and xpi) 1.939 + // in the manifest. 1.940 + 1.941 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.942 + defineNow(gPolicy, now); 1.943 + gManifestObject.experiments[0].xpiHash = EXPERIMENT1A_XPI_SHA1; 1.944 + gManifestObject.experiments[0].xpiURL = gDataRoot + EXPERIMENT1A_XPI_NAME; 1.945 + yield experiments.updateManifest(); 1.946 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.947 + "Experiments observer should have been called."); 1.948 + 1.949 + list = yield experiments.getExperiments(); 1.950 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.951 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.952 + Assert.equal(list[0].active, true, "Experiment 1 should still be active."); 1.953 + Assert.equal(list[0].name, EXPERIMENT1A_NAME, "Experiments name should have been updated."); 1.954 + todayActive = yield experiments.lastActiveToday(); 1.955 + Assert.equal(todayActive.id, list[0].id, "last active today is still sane."); 1.956 + 1.957 + // Cleanup. 1.958 + 1.959 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.960 + yield testCleanup(experiments); 1.961 +}); 1.962 + 1.963 +// Tests that setting the disable flag for an active experiment 1.964 +// stops it. 1.965 + 1.966 +add_task(function* test_disableActiveExperiment() { 1.967 + const OBSERVER_TOPIC = "experiments-changed"; 1.968 + let observerFireCount = 0; 1.969 + let expectedObserverFireCount = 0; 1.970 + let observer = () => ++observerFireCount; 1.971 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.972 + 1.973 + // Dates the following tests are based on. 1.974 + 1.975 + let baseDate = new Date(2014, 5, 1, 12); 1.976 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.977 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.978 + 1.979 + // The manifest data we test with. 1.980 + 1.981 + gManifestObject = { 1.982 + "version": 1, 1.983 + experiments: [ 1.984 + { 1.985 + id: EXPERIMENT1_ID, 1.986 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.987 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.988 + startTime: dateToSeconds(startDate), 1.989 + endTime: dateToSeconds(endDate), 1.990 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.991 + appName: ["XPCShell"], 1.992 + channel: ["nightly"], 1.993 + }, 1.994 + ], 1.995 + }; 1.996 + 1.997 + let experiments = new Experiments.Experiments(gPolicy); 1.998 + 1.999 + // Trigger update, clock set to before any activation. 1.1000 + 1.1001 + let now = baseDate; 1.1002 + defineNow(gPolicy, now); 1.1003 + yield experiments.updateManifest(); 1.1004 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1005 + "Experiments observer should have been called."); 1.1006 + let list = yield experiments.getExperiments(); 1.1007 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.1008 + 1.1009 + // Trigger update, clock set for the experiment to start. 1.1010 + 1.1011 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.1012 + defineNow(gPolicy, now); 1.1013 + yield experiments.updateManifest(); 1.1014 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1015 + "Experiments observer should have been called."); 1.1016 + 1.1017 + list = yield experiments.getExperiments(); 1.1018 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1019 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1020 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.1021 + 1.1022 + // Trigger an update with the experiment being disabled. 1.1023 + 1.1024 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.1025 + defineNow(gPolicy, now); 1.1026 + gManifestObject.experiments[0].disabled = true; 1.1027 + yield experiments.updateManifest(); 1.1028 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1029 + "Experiments observer should have been called."); 1.1030 + 1.1031 + list = yield experiments.getExperiments(); 1.1032 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1033 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1034 + Assert.equal(list[0].active, false, "Experiment 1 should be disabled."); 1.1035 + 1.1036 + // Check that the experiment stays disabled. 1.1037 + 1.1038 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.1039 + defineNow(gPolicy, now); 1.1040 + delete gManifestObject.experiments[0].disabled; 1.1041 + yield experiments.updateManifest(); 1.1042 + 1.1043 + list = yield experiments.getExperiments(); 1.1044 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1045 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1046 + Assert.equal(list[0].active, false, "Experiment 1 should still be disabled."); 1.1047 + 1.1048 + // Cleanup. 1.1049 + 1.1050 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.1051 + yield testCleanup(experiments); 1.1052 +}); 1.1053 + 1.1054 +// Test that: 1.1055 +// * setting the frozen flag for a not-yet-started experiment keeps 1.1056 +// it from starting 1.1057 +// * after a removing the frozen flag, the experiment can still start 1.1058 + 1.1059 +add_task(function* test_freezePendingExperiment() { 1.1060 + const OBSERVER_TOPIC = "experiments-changed"; 1.1061 + let observerFireCount = 0; 1.1062 + let expectedObserverFireCount = 0; 1.1063 + let observer = () => ++observerFireCount; 1.1064 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.1065 + 1.1066 + // Dates the following tests are based on. 1.1067 + 1.1068 + let baseDate = new Date(2014, 5, 1, 12); 1.1069 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.1070 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.1071 + 1.1072 + // The manifest data we test with. 1.1073 + 1.1074 + gManifestObject = { 1.1075 + "version": 1, 1.1076 + experiments: [ 1.1077 + { 1.1078 + id: EXPERIMENT1_ID, 1.1079 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1080 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1081 + startTime: dateToSeconds(startDate), 1.1082 + endTime: dateToSeconds(endDate), 1.1083 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1084 + appName: ["XPCShell"], 1.1085 + channel: ["nightly"], 1.1086 + }, 1.1087 + ], 1.1088 + }; 1.1089 + 1.1090 + let experiments = new Experiments.Experiments(gPolicy); 1.1091 + 1.1092 + // Trigger update, clock set to before any activation. 1.1093 + 1.1094 + let now = baseDate; 1.1095 + defineNow(gPolicy, now); 1.1096 + yield experiments.updateManifest(); 1.1097 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1098 + "Experiments observer should have been called."); 1.1099 + let list = yield experiments.getExperiments(); 1.1100 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.1101 + 1.1102 + // Trigger update, clock set for the experiment to start but frozen. 1.1103 + 1.1104 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.1105 + defineNow(gPolicy, now); 1.1106 + gManifestObject.experiments[0].frozen = true; 1.1107 + yield experiments.updateManifest(); 1.1108 + Assert.equal(observerFireCount, expectedObserverFireCount, 1.1109 + "Experiments observer should have not been called."); 1.1110 + 1.1111 + list = yield experiments.getExperiments(); 1.1112 + Assert.equal(list.length, 0, "Experiment list should have no entries yet."); 1.1113 + 1.1114 + // Trigger an update with the experiment not being frozen anymore. 1.1115 + 1.1116 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.1117 + defineNow(gPolicy, now); 1.1118 + delete gManifestObject.experiments[0].frozen; 1.1119 + yield experiments.updateManifest(); 1.1120 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1121 + "Experiments observer should have been called."); 1.1122 + 1.1123 + list = yield experiments.getExperiments(); 1.1124 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1125 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1126 + Assert.equal(list[0].active, true, "Experiment 1 should be active now."); 1.1127 + 1.1128 + // Cleanup. 1.1129 + 1.1130 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.1131 + yield testCleanup(experiments); 1.1132 +}); 1.1133 + 1.1134 +// Test that setting the frozen flag for an active experiment doesn't 1.1135 +// stop it. 1.1136 + 1.1137 +add_task(function* test_freezeActiveExperiment() { 1.1138 + const OBSERVER_TOPIC = "experiments-changed"; 1.1139 + let observerFireCount = 0; 1.1140 + let expectedObserverFireCount = 0; 1.1141 + let observer = () => ++observerFireCount; 1.1142 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.1143 + 1.1144 + // Dates the following tests are based on. 1.1145 + 1.1146 + let baseDate = new Date(2014, 5, 1, 12); 1.1147 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.1148 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.1149 + 1.1150 + // The manifest data we test with. 1.1151 + 1.1152 + gManifestObject = { 1.1153 + "version": 1, 1.1154 + experiments: [ 1.1155 + { 1.1156 + id: EXPERIMENT1_ID, 1.1157 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1158 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1159 + startTime: dateToSeconds(startDate), 1.1160 + endTime: dateToSeconds(endDate), 1.1161 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1162 + appName: ["XPCShell"], 1.1163 + channel: ["nightly"], 1.1164 + }, 1.1165 + ], 1.1166 + }; 1.1167 + 1.1168 + let experiments = new Experiments.Experiments(gPolicy); 1.1169 + 1.1170 + // Trigger update, clock set to before any activation. 1.1171 + 1.1172 + let now = baseDate; 1.1173 + defineNow(gPolicy, now); 1.1174 + yield experiments.updateManifest(); 1.1175 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1176 + "Experiments observer should have been called."); 1.1177 + let list = yield experiments.getExperiments(); 1.1178 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.1179 + 1.1180 + // Trigger update, clock set for the experiment to start. 1.1181 + 1.1182 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.1183 + defineNow(gPolicy, now); 1.1184 + yield experiments.updateManifest(); 1.1185 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1186 + "Experiments observer should have been called."); 1.1187 + 1.1188 + list = yield experiments.getExperiments(); 1.1189 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1190 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1191 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.1192 + Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); 1.1193 + 1.1194 + // Trigger an update with the experiment being disabled. 1.1195 + 1.1196 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.1197 + defineNow(gPolicy, now); 1.1198 + gManifestObject.experiments[0].frozen = true; 1.1199 + yield experiments.updateManifest(); 1.1200 + Assert.equal(observerFireCount, expectedObserverFireCount, 1.1201 + "Experiments observer should have been called."); 1.1202 + 1.1203 + list = yield experiments.getExperiments(); 1.1204 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1205 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1206 + Assert.equal(list[0].active, true, "Experiment 1 should still be active."); 1.1207 + 1.1208 + // Cleanup. 1.1209 + 1.1210 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.1211 + yield testCleanup(experiments); 1.1212 +}); 1.1213 + 1.1214 +// Test that removing an active experiment from the manifest doesn't 1.1215 +// stop it. 1.1216 + 1.1217 +add_task(function* test_removeActiveExperiment() { 1.1218 + const OBSERVER_TOPIC = "experiments-changed"; 1.1219 + let observerFireCount = 0; 1.1220 + let expectedObserverFireCount = 0; 1.1221 + let observer = () => ++observerFireCount; 1.1222 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.1223 + 1.1224 + // Dates the following tests are based on. 1.1225 + 1.1226 + let baseDate = new Date(2014, 5, 1, 12); 1.1227 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.1228 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.1229 + let startDate2 = futureDate(baseDate, 20000 * MS_IN_ONE_DAY); 1.1230 + let endDate2 = futureDate(baseDate, 30000 * MS_IN_ONE_DAY); 1.1231 + 1.1232 + // The manifest data we test with. 1.1233 + 1.1234 + gManifestObject = { 1.1235 + "version": 1, 1.1236 + experiments: [ 1.1237 + { 1.1238 + id: EXPERIMENT1_ID, 1.1239 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1240 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1241 + startTime: dateToSeconds(startDate), 1.1242 + endTime: dateToSeconds(endDate), 1.1243 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1244 + appName: ["XPCShell"], 1.1245 + channel: ["nightly"], 1.1246 + }, 1.1247 + { 1.1248 + id: EXPERIMENT2_ID, 1.1249 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1250 + xpiHash: EXPERIMENT2_XPI_SHA1, 1.1251 + startTime: dateToSeconds(startDate2), 1.1252 + endTime: dateToSeconds(endDate2), 1.1253 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1254 + appName: ["XPCShell"], 1.1255 + channel: ["nightly"], 1.1256 + }, 1.1257 + ], 1.1258 + }; 1.1259 + 1.1260 + let experiments = new Experiments.Experiments(gPolicy); 1.1261 + 1.1262 + // Trigger update, clock set to before any activation. 1.1263 + 1.1264 + let now = baseDate; 1.1265 + defineNow(gPolicy, now); 1.1266 + yield experiments.updateManifest(); 1.1267 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1268 + "Experiments observer should have been called."); 1.1269 + let list = yield experiments.getExperiments(); 1.1270 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.1271 + 1.1272 + // Trigger update, clock set for the experiment to start. 1.1273 + 1.1274 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.1275 + defineNow(gPolicy, now); 1.1276 + yield experiments.updateManifest(); 1.1277 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1278 + "Experiments observer should have been called."); 1.1279 + 1.1280 + list = yield experiments.getExperiments(); 1.1281 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1282 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1283 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.1284 + Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match."); 1.1285 + 1.1286 + // Trigger an update with experiment 1 missing from the manifest 1.1287 + 1.1288 + now = futureDate(now, 1 * MS_IN_ONE_DAY); 1.1289 + defineNow(gPolicy, now); 1.1290 + gManifestObject.experiments[0].frozen = true; 1.1291 + yield experiments.updateManifest(); 1.1292 + Assert.equal(observerFireCount, expectedObserverFireCount, 1.1293 + "Experiments observer should have been called."); 1.1294 + 1.1295 + list = yield experiments.getExperiments(); 1.1296 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1297 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1298 + Assert.equal(list[0].active, true, "Experiment 1 should still be active."); 1.1299 + 1.1300 + // Cleanup. 1.1301 + 1.1302 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.1303 + yield testCleanup(experiments); 1.1304 +}); 1.1305 + 1.1306 +// Test that we correctly handle experiment start & install failures. 1.1307 + 1.1308 +add_task(function* test_invalidUrl() { 1.1309 + const OBSERVER_TOPIC = "experiments-changed"; 1.1310 + let observerFireCount = 0; 1.1311 + let expectedObserverFireCount = 0; 1.1312 + let observer = () => ++observerFireCount; 1.1313 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.1314 + 1.1315 + // Dates the following tests are based on. 1.1316 + 1.1317 + let baseDate = new Date(2014, 5, 1, 12); 1.1318 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.1319 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.1320 + 1.1321 + // The manifest data we test with. 1.1322 + 1.1323 + gManifestObject = { 1.1324 + "version": 1, 1.1325 + experiments: [ 1.1326 + { 1.1327 + id: EXPERIMENT1_ID, 1.1328 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME + ".invalid", 1.1329 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1330 + startTime: 0, 1.1331 + endTime: dateToSeconds(endDate), 1.1332 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1333 + appName: ["XPCShell"], 1.1334 + channel: ["nightly"], 1.1335 + }, 1.1336 + ], 1.1337 + }; 1.1338 + 1.1339 + let experiments = new Experiments.Experiments(gPolicy); 1.1340 + 1.1341 + // Trigger update, clock set for the experiment to start. 1.1342 + 1.1343 + let now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.1344 + defineNow(gPolicy, now); 1.1345 + gTimerScheduleOffset = null; 1.1346 + 1.1347 + yield experiments.updateManifest(); 1.1348 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1349 + "Experiments observer should have been called."); 1.1350 + Assert.equal(gTimerScheduleOffset, null, "No new timer should have been scheduled."); 1.1351 + 1.1352 + let list = yield experiments.getExperiments(); 1.1353 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.1354 + 1.1355 + // Cleanup. 1.1356 + 1.1357 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.1358 + yield testCleanup(experiments); 1.1359 +}); 1.1360 + 1.1361 +// Test that we handle it properly when active experiment addons are being 1.1362 +// uninstalled. 1.1363 + 1.1364 +add_task(function* test_unexpectedUninstall() { 1.1365 + const OBSERVER_TOPIC = "experiments-changed"; 1.1366 + let observerFireCount = 0; 1.1367 + let expectedObserverFireCount = 0; 1.1368 + let observer = () => ++observerFireCount; 1.1369 + Services.obs.addObserver(observer, OBSERVER_TOPIC, false); 1.1370 + 1.1371 + // Dates the following tests are based on. 1.1372 + 1.1373 + let baseDate = new Date(2014, 5, 1, 12); 1.1374 + let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY); 1.1375 + let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY); 1.1376 + 1.1377 + // The manifest data we test with. 1.1378 + 1.1379 + gManifestObject = { 1.1380 + "version": 1, 1.1381 + experiments: [ 1.1382 + { 1.1383 + id: EXPERIMENT1_ID, 1.1384 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1385 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1386 + startTime: dateToSeconds(startDate), 1.1387 + endTime: dateToSeconds(endDate), 1.1388 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1389 + appName: ["XPCShell"], 1.1390 + channel: ["nightly"], 1.1391 + }, 1.1392 + ], 1.1393 + }; 1.1394 + 1.1395 + let experiments = new Experiments.Experiments(gPolicy); 1.1396 + 1.1397 + // Trigger update, clock set to before any activation. 1.1398 + 1.1399 + let now = baseDate; 1.1400 + defineNow(gPolicy, now); 1.1401 + yield experiments.updateManifest(); 1.1402 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1403 + "Experiments observer should have been called."); 1.1404 + let list = yield experiments.getExperiments(); 1.1405 + Assert.equal(list.length, 0, "Experiment list should be empty."); 1.1406 + 1.1407 + // Trigger update, clock set for the experiment to start. 1.1408 + 1.1409 + now = futureDate(startDate, 10 * MS_IN_ONE_DAY); 1.1410 + defineNow(gPolicy, now); 1.1411 + yield experiments.updateManifest(); 1.1412 + Assert.equal(observerFireCount, ++expectedObserverFireCount, 1.1413 + "Experiments observer should have been called."); 1.1414 + 1.1415 + list = yield experiments.getExperiments(); 1.1416 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1417 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1418 + Assert.equal(list[0].active, true, "Experiment 1 should be active."); 1.1419 + 1.1420 + // Uninstall the addon through the addon manager instead of stopping it through 1.1421 + // the experiments API. 1.1422 + 1.1423 + yield AddonTestUtils.uninstallAddonByID(EXPERIMENT1_ID); 1.1424 + yield experiments._mainTask; 1.1425 + 1.1426 + yield experiments.notify(); 1.1427 + 1.1428 + list = yield experiments.getExperiments(); 1.1429 + Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); 1.1430 + Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1431 + Assert.equal(list[0].active, false, "Experiment 1 should not be active anymore."); 1.1432 + 1.1433 + // Cleanup. 1.1434 + 1.1435 + Services.obs.removeObserver(observer, OBSERVER_TOPIC); 1.1436 + yield testCleanup(experiments); 1.1437 +}); 1.1438 + 1.1439 +// If the Addon Manager knows of an experiment that we don't, it should get 1.1440 +// uninstalled. 1.1441 +add_task(function* testUnknownExperimentsUninstalled() { 1.1442 + let experiments = new Experiments.Experiments(gPolicy); 1.1443 + 1.1444 + let addons = yield getExperimentAddons(); 1.1445 + Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are present."); 1.1446 + 1.1447 + // Simulate us not listening. 1.1448 + experiments._unregisterWithAddonManager(); 1.1449 + yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1); 1.1450 + experiments._registerWithAddonManager(); 1.1451 + 1.1452 + addons = yield getExperimentAddons(); 1.1453 + Assert.equal(addons.length, 1, "Experiment 1 installed via AddonManager"); 1.1454 + 1.1455 + // Simulate no known experiments. 1.1456 + gManifestObject = { 1.1457 + "version": 1, 1.1458 + experiments: [], 1.1459 + }; 1.1460 + 1.1461 + yield experiments.updateManifest(); 1.1462 + let fromManifest = yield experiments.getExperiments(); 1.1463 + Assert.equal(fromManifest.length, 0, "No experiments known in manifest."); 1.1464 + 1.1465 + // And the unknown add-on should be gone. 1.1466 + addons = yield getExperimentAddons(); 1.1467 + Assert.equal(addons.length, 0, "Experiment 1 was uninstalled."); 1.1468 + 1.1469 + yield testCleanup(experiments); 1.1470 +}); 1.1471 + 1.1472 +// If someone else installs an experiment add-on, we detect and stop that. 1.1473 +add_task(function* testForeignExperimentInstall() { 1.1474 + let experiments = new Experiments.Experiments(gPolicy); 1.1475 + 1.1476 + gManifestObject = { 1.1477 + "version": 1, 1.1478 + experiments: [], 1.1479 + }; 1.1480 + 1.1481 + yield experiments.init(); 1.1482 + 1.1483 + let addons = yield getExperimentAddons(); 1.1484 + Assert.equal(addons.length, 0, "Precondition: No experiment add-ons present."); 1.1485 + 1.1486 + let failed = false; 1.1487 + try { 1.1488 + yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1); 1.1489 + } catch (ex) { 1.1490 + failed = true; 1.1491 + } 1.1492 + Assert.ok(failed, "Add-on install should not have completed successfully"); 1.1493 + addons = yield getExperimentAddons(); 1.1494 + Assert.equal(addons.length, 0, "Add-on install should have been cancelled."); 1.1495 + 1.1496 + yield testCleanup(experiments); 1.1497 +}); 1.1498 + 1.1499 +// Experiment add-ons will be disabled after Addon Manager restarts. Ensure 1.1500 +// we enable them automatically. 1.1501 +add_task(function* testEnabledAfterRestart() { 1.1502 + let experiments = new Experiments.Experiments(gPolicy); 1.1503 + 1.1504 + gManifestObject = { 1.1505 + "version": 1, 1.1506 + experiments: [ 1.1507 + { 1.1508 + id: EXPERIMENT1_ID, 1.1509 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1510 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1511 + startTime: gPolicy.now().getTime() / 1000 - 60, 1.1512 + endTime: gPolicy.now().getTime() / 1000 + 60, 1.1513 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1514 + appName: ["XPCShell"], 1.1515 + channel: ["nightly"], 1.1516 + }, 1.1517 + ], 1.1518 + }; 1.1519 + 1.1520 + let addons = yield getExperimentAddons(); 1.1521 + Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed."); 1.1522 + 1.1523 + yield experiments.updateManifest(); 1.1524 + let fromManifest = yield experiments.getExperiments(); 1.1525 + Assert.equal(fromManifest.length, 1, "A single experiment is known."); 1.1526 + 1.1527 + addons = yield getExperimentAddons(); 1.1528 + Assert.equal(addons.length, 1, "A single experiment add-on is installed."); 1.1529 + Assert.ok(addons[0].isActive, "That experiment is active."); 1.1530 + 1.1531 + dump("Restarting Addon Manager\n"); 1.1532 + experiments._unregisterWithAddonManager(); 1.1533 + restartManager(); 1.1534 + experiments._registerWithAddonManager(); 1.1535 + 1.1536 + addons = yield getExperimentAddons(); 1.1537 + Assert.equal(addons.length, 1, "The experiment is still there after restart."); 1.1538 + Assert.ok(addons[0].userDisabled, "But it is disabled."); 1.1539 + Assert.equal(addons[0].isActive, false, "And not active."); 1.1540 + 1.1541 + yield experiments.updateManifest(); 1.1542 + Assert.ok(addons[0].isActive, "It activates when the manifest is evaluated."); 1.1543 + 1.1544 + yield testCleanup(experiments); 1.1545 +}); 1.1546 + 1.1547 +// Test coverage for an add-on uninstall disabling the experiment and that it stays 1.1548 +// disabled over restarts. 1.1549 +add_task(function* test_foreignUninstallAndRestart() { 1.1550 + let experiments = new Experiments.Experiments(gPolicy); 1.1551 + 1.1552 + gManifestObject = { 1.1553 + "version": 1, 1.1554 + experiments: [ 1.1555 + { 1.1556 + id: EXPERIMENT1_ID, 1.1557 + xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, 1.1558 + xpiHash: EXPERIMENT1_XPI_SHA1, 1.1559 + startTime: gPolicy.now().getTime() / 1000 - 60, 1.1560 + endTime: gPolicy.now().getTime() / 1000 + 60, 1.1561 + maxActiveSeconds: 10 * SEC_IN_ONE_DAY, 1.1562 + appName: ["XPCShell"], 1.1563 + channel: ["nightly"], 1.1564 + }, 1.1565 + ], 1.1566 + }; 1.1567 + 1.1568 + let addons = yield getExperimentAddons(); 1.1569 + Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed."); 1.1570 + 1.1571 + yield experiments.updateManifest(); 1.1572 + let experimentList = yield experiments.getExperiments(); 1.1573 + Assert.equal(experimentList.length, 1, "A single experiment is known."); 1.1574 + 1.1575 + addons = yield getExperimentAddons(); 1.1576 + Assert.equal(addons.length, 1, "A single experiment add-on is installed."); 1.1577 + Assert.ok(addons[0].isActive, "That experiment is active."); 1.1578 + 1.1579 + yield AddonTestUtils.uninstallAddonByID(EXPERIMENT1_ID); 1.1580 + yield experiments._mainTask; 1.1581 + 1.1582 + let addons = yield getExperimentAddons(); 1.1583 + Assert.equal(addons.length, 0, "Experiment add-on should have been removed."); 1.1584 + 1.1585 + experimentList = yield experiments.getExperiments(); 1.1586 + Assert.equal(experimentList.length, 1, "A single experiment is known."); 1.1587 + Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1588 + Assert.ok(!experimentList[0].active, "Experiment 1 should not be active anymore."); 1.1589 + 1.1590 + // Fake restart behaviour. 1.1591 + experiments.uninit(); 1.1592 + restartManager(); 1.1593 + experiments = new Experiments.Experiments(gPolicy); 1.1594 + yield experiments.updateManifest(); 1.1595 + 1.1596 + let addons = yield getExperimentAddons(); 1.1597 + Assert.equal(addons.length, 0, "No experiment add-ons installed."); 1.1598 + 1.1599 + experimentList = yield experiments.getExperiments(); 1.1600 + Assert.equal(experimentList.length, 1, "A single experiment is known."); 1.1601 + Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry."); 1.1602 + Assert.ok(!experimentList[0].active, "Experiment 1 should not be active."); 1.1603 + 1.1604 + yield testCleanup(experiments); 1.1605 +});