browser/experiments/test/xpcshell/test_api.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 * http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 "use strict";
michael@0 5
michael@0 6 Cu.import("resource://testing-common/httpd.js");
michael@0 7 Cu.import("resource://testing-common/AddonManagerTesting.jsm");
michael@0 8
michael@0 9 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
michael@0 10 "resource:///modules/experiments/Experiments.jsm");
michael@0 11
michael@0 12 const FILE_MANIFEST = "experiments.manifest";
michael@0 13 const MANIFEST_HANDLER = "manifests/handler";
michael@0 14
michael@0 15 const SEC_IN_ONE_DAY = 24 * 60 * 60;
michael@0 16 const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
michael@0 17
michael@0 18 let gProfileDir = null;
michael@0 19 let gHttpServer = null;
michael@0 20 let gHttpRoot = null;
michael@0 21 let gDataRoot = null;
michael@0 22 let gReporter = null;
michael@0 23 let gPolicy = null;
michael@0 24 let gManifestObject = null;
michael@0 25 let gManifestHandlerURI = null;
michael@0 26 let gTimerScheduleOffset = -1;
michael@0 27
michael@0 28 function uninstallExperimentAddons() {
michael@0 29 return Task.spawn(function* () {
michael@0 30 let addons = yield getExperimentAddons();
michael@0 31 for (let a of addons) {
michael@0 32 yield AddonTestUtils.uninstallAddonByID(a.id);
michael@0 33 }
michael@0 34 });
michael@0 35 }
michael@0 36
michael@0 37 function testCleanup(experimentsInstance) {
michael@0 38 return Task.spawn(function* () {
michael@0 39 yield experimentsInstance.uninit();
michael@0 40 yield removeCacheFile();
michael@0 41 yield uninstallExperimentAddons();
michael@0 42 restartManager();
michael@0 43 });
michael@0 44 }
michael@0 45
michael@0 46 function run_test() {
michael@0 47 run_next_test();
michael@0 48 }
michael@0 49
michael@0 50 add_task(function* test_setup() {
michael@0 51 loadAddonManager();
michael@0 52 gProfileDir = do_get_profile();
michael@0 53
michael@0 54 gHttpServer = new HttpServer();
michael@0 55 gHttpServer.start(-1);
michael@0 56 let port = gHttpServer.identity.primaryPort;
michael@0 57 gHttpRoot = "http://localhost:" + port + "/";
michael@0 58 gDataRoot = gHttpRoot + "data/";
michael@0 59 gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER;
michael@0 60 gHttpServer.registerDirectory("/data/", do_get_cwd());
michael@0 61 gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => {
michael@0 62 response.setStatusLine(null, 200, "OK");
michael@0 63 response.write(JSON.stringify(gManifestObject));
michael@0 64 response.processAsync();
michael@0 65 response.finish();
michael@0 66 });
michael@0 67 do_register_cleanup(() => gHttpServer.stop(() => {}));
michael@0 68
michael@0 69 disableCertificateChecks();
michael@0 70
michael@0 71 Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
michael@0 72 Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
michael@0 73 Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
michael@0 74 Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI);
michael@0 75 Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
michael@0 76
michael@0 77 gReporter = yield getReporter("json_payload_simple");
michael@0 78 yield gReporter.collectMeasurements();
michael@0 79 let payload = yield gReporter.getJSONPayload(true);
michael@0 80 do_register_cleanup(() => gReporter._shutdown());
michael@0 81
michael@0 82 gPolicy = new Experiments.Policy();
michael@0 83 patchPolicy(gPolicy, {
michael@0 84 updatechannel: () => "nightly",
michael@0 85 healthReportPayload: () => Promise.resolve(payload),
michael@0 86 oneshotTimer: (callback, timeout, thisObj, name) => gTimerScheduleOffset = timeout,
michael@0 87 });
michael@0 88 });
michael@0 89
michael@0 90 add_task(function* test_contract() {
michael@0 91 Cc["@mozilla.org/browser/experiments-service;1"].getService();
michael@0 92 });
michael@0 93
michael@0 94 // Test basic starting and stopping of experiments.
michael@0 95
michael@0 96 add_task(function* test_getExperiments() {
michael@0 97 const OBSERVER_TOPIC = "experiments-changed";
michael@0 98 let observerFireCount = 0;
michael@0 99 let expectedObserverFireCount = 0;
michael@0 100 let observer = () => ++observerFireCount;
michael@0 101 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 102
michael@0 103 // Dates the following tests are based on.
michael@0 104
michael@0 105 let baseDate = new Date(2014, 5, 1, 12);
michael@0 106 let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY);
michael@0 107 let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 108 let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY);
michael@0 109 let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY);
michael@0 110
michael@0 111 // The manifest data we test with.
michael@0 112
michael@0 113 gManifestObject = {
michael@0 114 "version": 1,
michael@0 115 experiments: [
michael@0 116 {
michael@0 117 id: EXPERIMENT2_ID,
michael@0 118 xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
michael@0 119 xpiHash: EXPERIMENT2_XPI_SHA1,
michael@0 120 startTime: dateToSeconds(startDate2),
michael@0 121 endTime: dateToSeconds(endDate2),
michael@0 122 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 123 appName: ["XPCShell"],
michael@0 124 channel: ["nightly"],
michael@0 125 },
michael@0 126 {
michael@0 127 id: EXPERIMENT1_ID,
michael@0 128 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 129 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 130 startTime: dateToSeconds(startDate1),
michael@0 131 endTime: dateToSeconds(endDate1),
michael@0 132 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 133 appName: ["XPCShell"],
michael@0 134 channel: ["nightly"],
michael@0 135 },
michael@0 136 ],
michael@0 137 };
michael@0 138
michael@0 139 // Data to compare the result of Experiments.getExperiments() against.
michael@0 140
michael@0 141 let experimentListData = [
michael@0 142 {
michael@0 143 id: EXPERIMENT2_ID,
michael@0 144 name: "Test experiment 2",
michael@0 145 description: "And yet another experiment that experiments experimentally.",
michael@0 146 },
michael@0 147 {
michael@0 148 id: EXPERIMENT1_ID,
michael@0 149 name: EXPERIMENT1_NAME,
michael@0 150 description: "Yet another experiment that experiments experimentally.",
michael@0 151 },
michael@0 152 ];
michael@0 153
michael@0 154 let experiments = new Experiments.Experiments(gPolicy);
michael@0 155
michael@0 156 // Trigger update, clock set to before any activation.
michael@0 157 // Use updateManifest() to provide for coverage of that path.
michael@0 158
michael@0 159 let now = baseDate;
michael@0 160 gTimerScheduleOffset = -1;
michael@0 161 defineNow(gPolicy, now);
michael@0 162
michael@0 163 yield experiments.updateManifest();
michael@0 164 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 165 "Experiments observer should have been called.");
michael@0 166 Assert.equal(experiments.getActiveExperimentID(), null,
michael@0 167 "getActiveExperimentID should return null");
michael@0 168
michael@0 169 let list = yield experiments.getExperiments();
michael@0 170 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 171 let addons = yield getExperimentAddons();
michael@0 172 Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed.");
michael@0 173
michael@0 174 try {
michael@0 175 let b = yield experiments.getExperimentBranch();
michael@0 176 Assert.ok(false, "getExperimentBranch should fail with no experiment");
michael@0 177 }
michael@0 178 catch (e) {
michael@0 179 Assert.ok(true, "getExperimentBranch correctly threw");
michael@0 180 }
michael@0 181
michael@0 182 // Trigger update, clock set for experiment 1 to start.
michael@0 183
michael@0 184 now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
michael@0 185 gTimerScheduleOffset = -1;
michael@0 186 defineNow(gPolicy, now);
michael@0 187
michael@0 188 yield experiments.updateManifest();
michael@0 189 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 190 "Experiments observer should have been called.");
michael@0 191
michael@0 192 Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID,
michael@0 193 "getActiveExperimentID should return the active experiment1");
michael@0 194
michael@0 195 list = yield experiments.getExperiments();
michael@0 196 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 197 addons = yield getExperimentAddons();
michael@0 198 Assert.equal(addons.length, 1, "An experiment add-on was installed.");
michael@0 199
michael@0 200 experimentListData[1].active = true;
michael@0 201 experimentListData[1].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
michael@0 202 for (let k of Object.keys(experimentListData[1])) {
michael@0 203 Assert.equal(experimentListData[1][k], list[0][k],
michael@0 204 "Property " + k + " should match reference data.");
michael@0 205 }
michael@0 206
michael@0 207 let b = yield experiments.getExperimentBranch();
michael@0 208 Assert.strictEqual(b, null, "getExperimentBranch should return null by default");
michael@0 209
michael@0 210 b = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
michael@0 211 Assert.strictEqual(b, null, "getExperimentsBranch should return null (with id)");
michael@0 212
michael@0 213 yield experiments.setExperimentBranch(EXPERIMENT1_ID, "foo");
michael@0 214 b = yield experiments.getExperimentBranch();
michael@0 215 Assert.strictEqual(b, "foo", "getExperimentsBranch should return the set value");
michael@0 216
michael@0 217 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 218 "Experiments observer should have been called.");
michael@0 219
michael@0 220 Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY,
michael@0 221 "Experiment re-evaluation should have been scheduled correctly.");
michael@0 222
michael@0 223 // Trigger update, clock set for experiment 1 to stop.
michael@0 224
michael@0 225 now = futureDate(endDate1, 1000);
michael@0 226 gTimerScheduleOffset = -1;
michael@0 227 defineNow(gPolicy, now);
michael@0 228
michael@0 229 yield experiments.updateManifest();
michael@0 230 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 231 "Experiments observer should have been called.");
michael@0 232
michael@0 233 Assert.equal(experiments.getActiveExperimentID(), null,
michael@0 234 "getActiveExperimentID should return null again");
michael@0 235
michael@0 236 list = yield experiments.getExperiments();
michael@0 237 Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
michael@0 238 addons = yield getExperimentAddons();
michael@0 239 Assert.equal(addons.length, 0, "The experiment add-on should be uninstalled.");
michael@0 240
michael@0 241 experimentListData[1].active = false;
michael@0 242 experimentListData[1].endDate = now.getTime();
michael@0 243 for (let k of Object.keys(experimentListData[1])) {
michael@0 244 Assert.equal(experimentListData[1][k], list[0][k],
michael@0 245 "Property " + k + " should match reference data.");
michael@0 246 }
michael@0 247
michael@0 248 Assert.equal(gTimerScheduleOffset, startDate2 - now,
michael@0 249 "Experiment re-evaluation should have been scheduled correctly.");
michael@0 250
michael@0 251 // Trigger update, clock set for experiment 2 to start.
michael@0 252 // Use notify() to provide for coverage of that path.
michael@0 253
michael@0 254 now = startDate2;
michael@0 255 gTimerScheduleOffset = -1;
michael@0 256 defineNow(gPolicy, now);
michael@0 257
michael@0 258 yield experiments.notify();
michael@0 259 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 260 "Experiments observer should have been called.");
michael@0 261
michael@0 262 Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT2_ID,
michael@0 263 "getActiveExperimentID should return the active experiment2");
michael@0 264
michael@0 265 list = yield experiments.getExperiments();
michael@0 266 Assert.equal(list.length, 2, "Experiment list should have 2 entries now.");
michael@0 267 addons = yield getExperimentAddons();
michael@0 268 Assert.equal(addons.length, 1, "An experiment add-on is installed.");
michael@0 269
michael@0 270 experimentListData[0].active = true;
michael@0 271 experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
michael@0 272 for (let i=0; i<experimentListData.length; ++i) {
michael@0 273 let entry = experimentListData[i];
michael@0 274 for (let k of Object.keys(entry)) {
michael@0 275 Assert.equal(entry[k], list[i][k],
michael@0 276 "Entry " + i + " - Property '" + k + "' should match reference data.");
michael@0 277 }
michael@0 278 }
michael@0 279
michael@0 280 Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY,
michael@0 281 "Experiment re-evaluation should have been scheduled correctly.");
michael@0 282
michael@0 283 // Trigger update, clock set for experiment 2 to stop.
michael@0 284
michael@0 285 now = futureDate(startDate2, 10 * MS_IN_ONE_DAY + 1000);
michael@0 286 gTimerScheduleOffset = -1;
michael@0 287 defineNow(gPolicy, now);
michael@0 288 yield experiments.notify();
michael@0 289 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 290 "Experiments observer should have been called.");
michael@0 291
michael@0 292 Assert.equal(experiments.getActiveExperimentID(), null,
michael@0 293 "getActiveExperimentID should return null again2");
michael@0 294
michael@0 295 list = yield experiments.getExperiments();
michael@0 296 Assert.equal(list.length, 2, "Experiment list should have 2 entries now.");
michael@0 297 addons = yield getExperimentAddons();
michael@0 298 Assert.equal(addons.length, 0, "No experiments add-ons are installed.");
michael@0 299
michael@0 300 experimentListData[0].active = false;
michael@0 301 experimentListData[0].endDate = now.getTime();
michael@0 302 for (let i=0; i<experimentListData.length; ++i) {
michael@0 303 let entry = experimentListData[i];
michael@0 304 for (let k of Object.keys(entry)) {
michael@0 305 Assert.equal(entry[k], list[i][k],
michael@0 306 "Entry " + i + " - Property '" + k + "' should match reference data.");
michael@0 307 }
michael@0 308 }
michael@0 309
michael@0 310 // Cleanup.
michael@0 311
michael@0 312 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 313 yield testCleanup(experiments);
michael@0 314 });
michael@0 315
michael@0 316 add_task(function* test_getActiveExperimentID() {
michael@0 317 // Check that getActiveExperimentID returns the correct result even
michael@0 318 // after .uninit()
michael@0 319
michael@0 320 // Dates the following tests are based on.
michael@0 321
michael@0 322 let baseDate = new Date(2014, 5, 1, 12);
michael@0 323 let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY);
michael@0 324 let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 325
michael@0 326 gManifestObject = {
michael@0 327 "version": 1,
michael@0 328 experiments: [
michael@0 329 {
michael@0 330 id: EXPERIMENT1_ID,
michael@0 331 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 332 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 333 startTime: dateToSeconds(startDate1),
michael@0 334 endTime: dateToSeconds(endDate1),
michael@0 335 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 336 appName: ["XPCShell"],
michael@0 337 channel: ["nightly"],
michael@0 338 },
michael@0 339 ],
michael@0 340 };
michael@0 341
michael@0 342 let now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
michael@0 343 gTimerScheduleOffset = -1;
michael@0 344 defineNow(gPolicy, now);
michael@0 345
michael@0 346 let experiments = new Experiments.Experiments(gPolicy);
michael@0 347 yield experiments.updateManifest();
michael@0 348
michael@0 349 Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID,
michael@0 350 "getActiveExperimentID should return the active experiment1");
michael@0 351
michael@0 352 yield experiments.uninit();
michael@0 353 Assert.equal(experiments.getActiveExperimentID(), EXPERIMENT1_ID,
michael@0 354 "getActiveExperimentID should return the active experiment1 after uninit()");
michael@0 355
michael@0 356 yield testCleanup(experiments);
michael@0 357 });
michael@0 358
michael@0 359 // Test that we handle the experiments addon already being
michael@0 360 // installed properly.
michael@0 361 // We should just pave over them.
michael@0 362
michael@0 363 add_task(function* test_addonAlreadyInstalled() {
michael@0 364 const OBSERVER_TOPIC = "experiments-changed";
michael@0 365 let observerFireCount = 0;
michael@0 366 let expectedObserverFireCount = 0;
michael@0 367 let observer = () => ++observerFireCount;
michael@0 368 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 369
michael@0 370 // Dates the following tests are based on.
michael@0 371
michael@0 372 let baseDate = new Date(2014, 5, 1, 12);
michael@0 373 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 374 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 375
michael@0 376 // The manifest data we test with.
michael@0 377
michael@0 378 gManifestObject = {
michael@0 379 "version": 1,
michael@0 380 experiments: [
michael@0 381 {
michael@0 382 id: EXPERIMENT1_ID,
michael@0 383 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 384 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 385 startTime: dateToSeconds(startDate),
michael@0 386 endTime: dateToSeconds(endDate),
michael@0 387 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 388 appName: ["XPCShell"],
michael@0 389 channel: ["nightly"],
michael@0 390 },
michael@0 391 ],
michael@0 392 };
michael@0 393
michael@0 394 let experiments = new Experiments.Experiments(gPolicy);
michael@0 395
michael@0 396 // Trigger update, clock set to before any activation.
michael@0 397
michael@0 398 let now = baseDate;
michael@0 399 defineNow(gPolicy, now);
michael@0 400 yield experiments.updateManifest();
michael@0 401 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 402 "Experiments observer should have been called.");
michael@0 403 let list = yield experiments.getExperiments();
michael@0 404 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 405
michael@0 406 // Trigger update, clock set for the experiment to start.
michael@0 407
michael@0 408 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 409 defineNow(gPolicy, now);
michael@0 410 yield experiments.updateManifest();
michael@0 411 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 412 "Experiments observer should have been called.");
michael@0 413
michael@0 414 list = yield experiments.getExperiments();
michael@0 415 list = yield experiments.getExperiments();
michael@0 416 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 417 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 418 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 419
michael@0 420 let addons = yield getExperimentAddons();
michael@0 421 Assert.equal(addons.length, 1, "1 add-on is installed.");
michael@0 422
michael@0 423 // Install conflicting addon.
michael@0 424
michael@0 425 yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1);
michael@0 426 addons = yield getExperimentAddons();
michael@0 427 Assert.equal(addons.length, 1, "1 add-on is installed.");
michael@0 428 list = yield experiments.getExperiments();
michael@0 429 Assert.equal(list.length, 1, "Experiment list should still have 1 entry.");
michael@0 430 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 431 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 432
michael@0 433 // Cleanup.
michael@0 434
michael@0 435 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 436 yield testCleanup(experiments);
michael@0 437 });
michael@0 438
michael@0 439 add_task(function* test_lastActiveToday() {
michael@0 440 let experiments = new Experiments.Experiments(gPolicy);
michael@0 441
michael@0 442 replaceExperiments(experiments, FAKE_EXPERIMENTS_1);
michael@0 443
michael@0 444 let e = yield experiments.getExperiments();
michael@0 445 Assert.equal(e.length, 1, "Monkeypatch successful.");
michael@0 446 Assert.equal(e[0].id, "id1", "ID looks sane");
michael@0 447 Assert.ok(e[0].active, "Experiment is active.");
michael@0 448
michael@0 449 let lastActive = yield experiments.lastActiveToday();
michael@0 450 Assert.equal(e[0], lastActive, "Last active object is expected.");
michael@0 451
michael@0 452 replaceExperiments(experiments, FAKE_EXPERIMENTS_2);
michael@0 453 e = yield experiments.getExperiments();
michael@0 454 Assert.equal(e.length, 2, "Monkeypatch successful.");
michael@0 455
michael@0 456 defineNow(gPolicy, e[0].endDate);
michael@0 457
michael@0 458 lastActive = yield experiments.lastActiveToday();
michael@0 459 Assert.ok(lastActive, "Have a last active experiment");
michael@0 460 Assert.equal(lastActive, e[0], "Last active object is expected.");
michael@0 461
michael@0 462 yield testCleanup(experiments);
michael@0 463 });
michael@0 464
michael@0 465 // Test explicitly disabling experiments.
michael@0 466
michael@0 467 add_task(function* test_disableExperiment() {
michael@0 468 // Dates this test is based on.
michael@0 469
michael@0 470 let startDate = new Date(2004, 10, 9, 12);
michael@0 471 let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY);
michael@0 472
michael@0 473 // The manifest data we test with.
michael@0 474
michael@0 475 gManifestObject = {
michael@0 476 "version": 1,
michael@0 477 experiments: [
michael@0 478 {
michael@0 479 id: EXPERIMENT1_ID,
michael@0 480 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 481 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 482 startTime: dateToSeconds(startDate),
michael@0 483 endTime: dateToSeconds(endDate),
michael@0 484 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 485 appName: ["XPCShell"],
michael@0 486 channel: ["nightly"],
michael@0 487 },
michael@0 488 ],
michael@0 489 };
michael@0 490
michael@0 491 // Data to compare the result of Experiments.getExperiments() against.
michael@0 492
michael@0 493 let experimentInfo = {
michael@0 494 id: EXPERIMENT1_ID,
michael@0 495 name: EXPERIMENT1_NAME,
michael@0 496 description: "Yet another experiment that experiments experimentally.",
michael@0 497 };
michael@0 498
michael@0 499 let experiments = new Experiments.Experiments(gPolicy);
michael@0 500
michael@0 501 // Trigger update, clock set for the experiment to start.
michael@0 502
michael@0 503 let now = futureDate(startDate, 5 * MS_IN_ONE_DAY);
michael@0 504 defineNow(gPolicy, now);
michael@0 505 yield experiments.updateManifest();
michael@0 506
michael@0 507 let list = yield experiments.getExperiments();
michael@0 508 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 509
michael@0 510 experimentInfo.active = true;
michael@0 511 experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
michael@0 512 for (let k of Object.keys(experimentInfo)) {
michael@0 513 Assert.equal(experimentInfo[k], list[0][k],
michael@0 514 "Property " + k + " should match reference data.");
michael@0 515 }
michael@0 516
michael@0 517 // Test disabling the experiment.
michael@0 518
michael@0 519 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 520 defineNow(gPolicy, now);
michael@0 521 yield experiments.disableExperiment("foo");
michael@0 522
michael@0 523 list = yield experiments.getExperiments();
michael@0 524 Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
michael@0 525
michael@0 526 experimentInfo.active = false;
michael@0 527 experimentInfo.endDate = now.getTime();
michael@0 528 for (let k of Object.keys(experimentInfo)) {
michael@0 529 Assert.equal(experimentInfo[k], list[0][k],
michael@0 530 "Property " + k + " should match reference data.");
michael@0 531 }
michael@0 532
michael@0 533 // Test that updating the list doesn't re-enable it.
michael@0 534
michael@0 535 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 536 defineNow(gPolicy, now);
michael@0 537 yield experiments.updateManifest();
michael@0 538
michael@0 539 list = yield experiments.getExperiments();
michael@0 540 Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
michael@0 541
michael@0 542 for (let k of Object.keys(experimentInfo)) {
michael@0 543 Assert.equal(experimentInfo[k], list[0][k],
michael@0 544 "Property " + k + " should match reference data.");
michael@0 545 }
michael@0 546
michael@0 547 yield testCleanup(experiments);
michael@0 548 });
michael@0 549
michael@0 550 add_task(function* test_disableExperimentsFeature() {
michael@0 551 // Dates this test is based on.
michael@0 552
michael@0 553 let startDate = new Date(2004, 10, 9, 12);
michael@0 554 let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY);
michael@0 555
michael@0 556 // The manifest data we test with.
michael@0 557
michael@0 558 gManifestObject = {
michael@0 559 "version": 1,
michael@0 560 experiments: [
michael@0 561 {
michael@0 562 id: EXPERIMENT1_ID,
michael@0 563 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 564 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 565 startTime: dateToSeconds(startDate),
michael@0 566 endTime: dateToSeconds(endDate),
michael@0 567 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 568 appName: ["XPCShell"],
michael@0 569 channel: ["nightly"],
michael@0 570 },
michael@0 571 ],
michael@0 572 };
michael@0 573
michael@0 574 // Data to compare the result of Experiments.getExperiments() against.
michael@0 575
michael@0 576 let experimentInfo = {
michael@0 577 id: EXPERIMENT1_ID,
michael@0 578 name: EXPERIMENT1_NAME,
michael@0 579 description: "Yet another experiment that experiments experimentally.",
michael@0 580 };
michael@0 581
michael@0 582 let experiments = new Experiments.Experiments(gPolicy);
michael@0 583 Assert.equal(experiments.enabled, true, "Experiments feature should be enabled.");
michael@0 584
michael@0 585 // Trigger update, clock set for the experiment to start.
michael@0 586
michael@0 587 let now = futureDate(startDate, 5 * MS_IN_ONE_DAY);
michael@0 588 defineNow(gPolicy, now);
michael@0 589 yield experiments.updateManifest();
michael@0 590
michael@0 591 let list = yield experiments.getExperiments();
michael@0 592 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 593
michael@0 594 experimentInfo.active = true;
michael@0 595 experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
michael@0 596 for (let k of Object.keys(experimentInfo)) {
michael@0 597 Assert.equal(experimentInfo[k], list[0][k],
michael@0 598 "Property " + k + " should match reference data.");
michael@0 599 }
michael@0 600
michael@0 601 // Test disabling experiments.
michael@0 602
michael@0 603 experiments._toggleExperimentsEnabled(false);
michael@0 604 yield experiments.notify();
michael@0 605 Assert.equal(experiments.enabled, false, "Experiments feature should be disabled now.");
michael@0 606
michael@0 607 list = yield experiments.getExperiments();
michael@0 608 Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
michael@0 609
michael@0 610 experimentInfo.active = false;
michael@0 611 experimentInfo.endDate = now.getTime();
michael@0 612 for (let k of Object.keys(experimentInfo)) {
michael@0 613 Assert.equal(experimentInfo[k], list[0][k],
michael@0 614 "Property " + k + " should match reference data.");
michael@0 615 }
michael@0 616
michael@0 617 // Test that updating the list doesn't re-enable it.
michael@0 618
michael@0 619 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 620 defineNow(gPolicy, now);
michael@0 621 try {
michael@0 622 yield experiments.updateManifest();
michael@0 623 } catch (e) {
michael@0 624 // Exception expected, the feature is disabled.
michael@0 625 }
michael@0 626
michael@0 627 list = yield experiments.getExperiments();
michael@0 628 Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
michael@0 629
michael@0 630 for (let k of Object.keys(experimentInfo)) {
michael@0 631 Assert.equal(experimentInfo[k], list[0][k],
michael@0 632 "Property " + k + " should match reference data.");
michael@0 633 }
michael@0 634
michael@0 635 yield testCleanup(experiments);
michael@0 636 });
michael@0 637
michael@0 638 // Test that after a failed experiment install:
michael@0 639 // * the next applicable experiment gets installed
michael@0 640 // * changing the experiments data later triggers re-evaluation
michael@0 641
michael@0 642 add_task(function* test_installFailure() {
michael@0 643 const OBSERVER_TOPIC = "experiments-changed";
michael@0 644 let observerFireCount = 0;
michael@0 645 let expectedObserverFireCount = 0;
michael@0 646 let observer = () => ++observerFireCount;
michael@0 647 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 648
michael@0 649 // Dates the following tests are based on.
michael@0 650
michael@0 651 let baseDate = new Date(2014, 5, 1, 12);
michael@0 652 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 653 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 654
michael@0 655 // The manifest data we test with.
michael@0 656
michael@0 657 gManifestObject = {
michael@0 658 "version": 1,
michael@0 659 experiments: [
michael@0 660 {
michael@0 661 id: EXPERIMENT1_ID,
michael@0 662 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 663 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 664 startTime: dateToSeconds(startDate),
michael@0 665 endTime: dateToSeconds(endDate),
michael@0 666 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 667 appName: ["XPCShell"],
michael@0 668 channel: ["nightly"],
michael@0 669 },
michael@0 670 {
michael@0 671 id: EXPERIMENT2_ID,
michael@0 672 xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
michael@0 673 xpiHash: EXPERIMENT2_XPI_SHA1,
michael@0 674 startTime: dateToSeconds(startDate),
michael@0 675 endTime: dateToSeconds(endDate),
michael@0 676 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 677 appName: ["XPCShell"],
michael@0 678 channel: ["nightly"],
michael@0 679 },
michael@0 680 ],
michael@0 681 };
michael@0 682
michael@0 683 // Data to compare the result of Experiments.getExperiments() against.
michael@0 684
michael@0 685 let experimentListData = [
michael@0 686 {
michael@0 687 id: EXPERIMENT1_ID,
michael@0 688 name: EXPERIMENT1_NAME,
michael@0 689 description: "Yet another experiment that experiments experimentally.",
michael@0 690 },
michael@0 691 {
michael@0 692 id: EXPERIMENT2_ID,
michael@0 693 name: "Test experiment 2",
michael@0 694 description: "And yet another experiment that experiments experimentally.",
michael@0 695 },
michael@0 696 ];
michael@0 697
michael@0 698 let experiments = new Experiments.Experiments(gPolicy);
michael@0 699
michael@0 700 // Trigger update, clock set to before any activation.
michael@0 701
michael@0 702 let now = baseDate;
michael@0 703 defineNow(gPolicy, now);
michael@0 704 yield experiments.updateManifest();
michael@0 705 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 706 "Experiments observer should have been called.");
michael@0 707 let list = yield experiments.getExperiments();
michael@0 708 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 709
michael@0 710 // Trigger update, clock set for experiment 1 & 2 to start,
michael@0 711 // invalid hash for experiment 1.
michael@0 712 // Order in the manifest matters, so we should start experiment 1,
michael@0 713 // fail to install it & start experiment 2 instead.
michael@0 714
michael@0 715 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 716 defineNow(gPolicy, now);
michael@0 717 gManifestObject.experiments[0].xpiHash = "sha1:0000000000000000000000000000000000000000";
michael@0 718 yield experiments.updateManifest();
michael@0 719 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 720 "Experiments observer should have been called.");
michael@0 721
michael@0 722 list = yield experiments.getExperiments();
michael@0 723 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 724 Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry.");
michael@0 725 Assert.equal(list[0].active, true, "Experiment 2 should be active.");
michael@0 726
michael@0 727 // Trigger update, clock set for experiment 2 to stop.
michael@0 728
michael@0 729 now = futureDate(now, 20 * MS_IN_ONE_DAY);
michael@0 730 defineNow(gPolicy, now);
michael@0 731 yield experiments.updateManifest();
michael@0 732 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 733 "Experiments observer should have been called.");
michael@0 734
michael@0 735 experimentListData[0].active = false;
michael@0 736 experimentListData[0].endDate = now;
michael@0 737
michael@0 738 list = yield experiments.getExperiments();
michael@0 739 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 740 Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry.");
michael@0 741 Assert.equal(list[0].active, false, "Experiment should not be active.");
michael@0 742
michael@0 743 // Trigger update with a fixed entry for experiment 1,
michael@0 744 // which should get re-evaluated & started now.
michael@0 745
michael@0 746 now = futureDate(now, 20 * MS_IN_ONE_DAY);
michael@0 747 defineNow(gPolicy, now);
michael@0 748 gManifestObject.experiments[0].xpiHash = EXPERIMENT1_XPI_SHA1;
michael@0 749 yield experiments.updateManifest();
michael@0 750 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 751 "Experiments observer should have been called.");
michael@0 752
michael@0 753 experimentListData[0].active = true;
michael@0 754 experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
michael@0 755
michael@0 756 list = yield experiments.getExperiments();
michael@0 757 Assert.equal(list.length, 2, "Experiment list should have 2 entries now.");
michael@0 758
michael@0 759 for (let i=0; i<experimentListData.length; ++i) {
michael@0 760 let entry = experimentListData[i];
michael@0 761 for (let k of Object.keys(entry)) {
michael@0 762 Assert.equal(entry[k], list[i][k],
michael@0 763 "Entry " + i + " - Property '" + k + "' should match reference data.");
michael@0 764 }
michael@0 765 }
michael@0 766
michael@0 767 yield testCleanup(experiments);
michael@0 768 });
michael@0 769
michael@0 770 // Test that after an experiment was disabled by user action,
michael@0 771 // the experiment is not activated again if manifest data changes.
michael@0 772
michael@0 773 add_task(function* test_userDisabledAndUpdated() {
michael@0 774 const OBSERVER_TOPIC = "experiments-changed";
michael@0 775 let observerFireCount = 0;
michael@0 776 let expectedObserverFireCount = 0;
michael@0 777 let observer = () => ++observerFireCount;
michael@0 778 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 779
michael@0 780 // Dates the following tests are based on.
michael@0 781
michael@0 782 let baseDate = new Date(2014, 5, 1, 12);
michael@0 783 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 784 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 785
michael@0 786 // The manifest data we test with.
michael@0 787
michael@0 788 gManifestObject = {
michael@0 789 "version": 1,
michael@0 790 experiments: [
michael@0 791 {
michael@0 792 id: EXPERIMENT1_ID,
michael@0 793 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 794 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 795 startTime: dateToSeconds(startDate),
michael@0 796 endTime: dateToSeconds(endDate),
michael@0 797 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 798 appName: ["XPCShell"],
michael@0 799 channel: ["nightly"],
michael@0 800 },
michael@0 801 ],
michael@0 802 };
michael@0 803
michael@0 804 let experiments = new Experiments.Experiments(gPolicy);
michael@0 805
michael@0 806 // Trigger update, clock set to before any activation.
michael@0 807
michael@0 808 let now = baseDate;
michael@0 809 defineNow(gPolicy, now);
michael@0 810 yield experiments.updateManifest();
michael@0 811 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 812 "Experiments observer should have been called.");
michael@0 813 let list = yield experiments.getExperiments();
michael@0 814 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 815
michael@0 816 // Trigger update, clock set for experiment 1 to start.
michael@0 817
michael@0 818 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 819 defineNow(gPolicy, now);
michael@0 820 yield experiments.updateManifest();
michael@0 821 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 822 "Experiments observer should have been called.");
michael@0 823
michael@0 824 list = yield experiments.getExperiments();
michael@0 825 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 826 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 827 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 828 let todayActive = yield experiments.lastActiveToday();
michael@0 829 Assert.ok(todayActive, "Last active for today reports a value.");
michael@0 830 Assert.equal(todayActive.id, list[0].id, "The entry is what we expect.");
michael@0 831
michael@0 832 // Explicitly disable an experiment.
michael@0 833
michael@0 834 now = futureDate(now, 20 * MS_IN_ONE_DAY);
michael@0 835 defineNow(gPolicy, now);
michael@0 836 yield experiments.disableExperiment("foo");
michael@0 837 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 838 "Experiments observer should have been called.");
michael@0 839
michael@0 840 list = yield experiments.getExperiments();
michael@0 841 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 842 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 843 Assert.equal(list[0].active, false, "Experiment should not be active anymore.");
michael@0 844 todayActive = yield experiments.lastActiveToday();
michael@0 845 Assert.ok(todayActive, "Last active for today still returns a value.");
michael@0 846 Assert.equal(todayActive.id, list[0].id, "The ID is still the same.");
michael@0 847
michael@0 848 // Trigger an update with a faked change for experiment 1.
michael@0 849
michael@0 850 now = futureDate(now, 20 * MS_IN_ONE_DAY);
michael@0 851 defineNow(gPolicy, now);
michael@0 852 experiments._experiments.get(EXPERIMENT1_ID)._manifestData.xpiHash =
michael@0 853 "sha1:0000000000000000000000000000000000000000";
michael@0 854 yield experiments.updateManifest();
michael@0 855 Assert.equal(observerFireCount, expectedObserverFireCount,
michael@0 856 "Experiments observer should not have been called.");
michael@0 857
michael@0 858 list = yield experiments.getExperiments();
michael@0 859 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 860 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 861 Assert.equal(list[0].active, false, "Experiment should still be inactive.");
michael@0 862
michael@0 863 // Cleanup.
michael@0 864
michael@0 865 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 866 yield testCleanup(experiments);
michael@0 867 });
michael@0 868
michael@0 869 // Test that changing the hash for an active experiments triggers an
michael@0 870 // update for it.
michael@0 871
michael@0 872 add_task(function* test_updateActiveExperiment() {
michael@0 873 const OBSERVER_TOPIC = "experiments-changed";
michael@0 874 let observerFireCount = 0;
michael@0 875 let expectedObserverFireCount = 0;
michael@0 876 let observer = () => ++observerFireCount;
michael@0 877 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 878
michael@0 879 // Dates the following tests are based on.
michael@0 880
michael@0 881 let baseDate = new Date(2014, 5, 1, 12);
michael@0 882 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 883 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 884
michael@0 885 // The manifest data we test with.
michael@0 886
michael@0 887 gManifestObject = {
michael@0 888 "version": 1,
michael@0 889 experiments: [
michael@0 890 {
michael@0 891 id: EXPERIMENT1_ID,
michael@0 892 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 893 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 894 startTime: dateToSeconds(startDate),
michael@0 895 endTime: dateToSeconds(endDate),
michael@0 896 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 897 appName: ["XPCShell"],
michael@0 898 channel: ["nightly"],
michael@0 899 },
michael@0 900 ],
michael@0 901 };
michael@0 902
michael@0 903 let experiments = new Experiments.Experiments(gPolicy);
michael@0 904
michael@0 905 // Trigger update, clock set to before any activation.
michael@0 906
michael@0 907 let now = baseDate;
michael@0 908 defineNow(gPolicy, now);
michael@0 909 yield experiments.updateManifest();
michael@0 910 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 911 "Experiments observer should have been called.");
michael@0 912 let list = yield experiments.getExperiments();
michael@0 913 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 914
michael@0 915 let todayActive = yield experiments.lastActiveToday();
michael@0 916 Assert.equal(todayActive, null, "No experiment active today.");
michael@0 917
michael@0 918 // Trigger update, clock set for the experiment to start.
michael@0 919
michael@0 920 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 921 defineNow(gPolicy, now);
michael@0 922 yield experiments.updateManifest();
michael@0 923 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 924 "Experiments observer should have been called.");
michael@0 925
michael@0 926 list = yield experiments.getExperiments();
michael@0 927 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 928 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 929 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 930 Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match.");
michael@0 931 todayActive = yield experiments.lastActiveToday();
michael@0 932 Assert.ok(todayActive, "todayActive() returns a value.");
michael@0 933 Assert.equal(todayActive.id, list[0].id, "It returns the active experiment.");
michael@0 934
michael@0 935 // Trigger an update for the active experiment by changing it's hash (and xpi)
michael@0 936 // in the manifest.
michael@0 937
michael@0 938 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 939 defineNow(gPolicy, now);
michael@0 940 gManifestObject.experiments[0].xpiHash = EXPERIMENT1A_XPI_SHA1;
michael@0 941 gManifestObject.experiments[0].xpiURL = gDataRoot + EXPERIMENT1A_XPI_NAME;
michael@0 942 yield experiments.updateManifest();
michael@0 943 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 944 "Experiments observer should have been called.");
michael@0 945
michael@0 946 list = yield experiments.getExperiments();
michael@0 947 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 948 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 949 Assert.equal(list[0].active, true, "Experiment 1 should still be active.");
michael@0 950 Assert.equal(list[0].name, EXPERIMENT1A_NAME, "Experiments name should have been updated.");
michael@0 951 todayActive = yield experiments.lastActiveToday();
michael@0 952 Assert.equal(todayActive.id, list[0].id, "last active today is still sane.");
michael@0 953
michael@0 954 // Cleanup.
michael@0 955
michael@0 956 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 957 yield testCleanup(experiments);
michael@0 958 });
michael@0 959
michael@0 960 // Tests that setting the disable flag for an active experiment
michael@0 961 // stops it.
michael@0 962
michael@0 963 add_task(function* test_disableActiveExperiment() {
michael@0 964 const OBSERVER_TOPIC = "experiments-changed";
michael@0 965 let observerFireCount = 0;
michael@0 966 let expectedObserverFireCount = 0;
michael@0 967 let observer = () => ++observerFireCount;
michael@0 968 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 969
michael@0 970 // Dates the following tests are based on.
michael@0 971
michael@0 972 let baseDate = new Date(2014, 5, 1, 12);
michael@0 973 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 974 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 975
michael@0 976 // The manifest data we test with.
michael@0 977
michael@0 978 gManifestObject = {
michael@0 979 "version": 1,
michael@0 980 experiments: [
michael@0 981 {
michael@0 982 id: EXPERIMENT1_ID,
michael@0 983 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 984 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 985 startTime: dateToSeconds(startDate),
michael@0 986 endTime: dateToSeconds(endDate),
michael@0 987 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 988 appName: ["XPCShell"],
michael@0 989 channel: ["nightly"],
michael@0 990 },
michael@0 991 ],
michael@0 992 };
michael@0 993
michael@0 994 let experiments = new Experiments.Experiments(gPolicy);
michael@0 995
michael@0 996 // Trigger update, clock set to before any activation.
michael@0 997
michael@0 998 let now = baseDate;
michael@0 999 defineNow(gPolicy, now);
michael@0 1000 yield experiments.updateManifest();
michael@0 1001 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1002 "Experiments observer should have been called.");
michael@0 1003 let list = yield experiments.getExperiments();
michael@0 1004 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 1005
michael@0 1006 // Trigger update, clock set for the experiment to start.
michael@0 1007
michael@0 1008 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 1009 defineNow(gPolicy, now);
michael@0 1010 yield experiments.updateManifest();
michael@0 1011 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1012 "Experiments observer should have been called.");
michael@0 1013
michael@0 1014 list = yield experiments.getExperiments();
michael@0 1015 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1016 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1017 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 1018
michael@0 1019 // Trigger an update with the experiment being disabled.
michael@0 1020
michael@0 1021 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 1022 defineNow(gPolicy, now);
michael@0 1023 gManifestObject.experiments[0].disabled = true;
michael@0 1024 yield experiments.updateManifest();
michael@0 1025 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1026 "Experiments observer should have been called.");
michael@0 1027
michael@0 1028 list = yield experiments.getExperiments();
michael@0 1029 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1030 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1031 Assert.equal(list[0].active, false, "Experiment 1 should be disabled.");
michael@0 1032
michael@0 1033 // Check that the experiment stays disabled.
michael@0 1034
michael@0 1035 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 1036 defineNow(gPolicy, now);
michael@0 1037 delete gManifestObject.experiments[0].disabled;
michael@0 1038 yield experiments.updateManifest();
michael@0 1039
michael@0 1040 list = yield experiments.getExperiments();
michael@0 1041 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1042 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1043 Assert.equal(list[0].active, false, "Experiment 1 should still be disabled.");
michael@0 1044
michael@0 1045 // Cleanup.
michael@0 1046
michael@0 1047 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 1048 yield testCleanup(experiments);
michael@0 1049 });
michael@0 1050
michael@0 1051 // Test that:
michael@0 1052 // * setting the frozen flag for a not-yet-started experiment keeps
michael@0 1053 // it from starting
michael@0 1054 // * after a removing the frozen flag, the experiment can still start
michael@0 1055
michael@0 1056 add_task(function* test_freezePendingExperiment() {
michael@0 1057 const OBSERVER_TOPIC = "experiments-changed";
michael@0 1058 let observerFireCount = 0;
michael@0 1059 let expectedObserverFireCount = 0;
michael@0 1060 let observer = () => ++observerFireCount;
michael@0 1061 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 1062
michael@0 1063 // Dates the following tests are based on.
michael@0 1064
michael@0 1065 let baseDate = new Date(2014, 5, 1, 12);
michael@0 1066 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 1067 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 1068
michael@0 1069 // The manifest data we test with.
michael@0 1070
michael@0 1071 gManifestObject = {
michael@0 1072 "version": 1,
michael@0 1073 experiments: [
michael@0 1074 {
michael@0 1075 id: EXPERIMENT1_ID,
michael@0 1076 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1077 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1078 startTime: dateToSeconds(startDate),
michael@0 1079 endTime: dateToSeconds(endDate),
michael@0 1080 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1081 appName: ["XPCShell"],
michael@0 1082 channel: ["nightly"],
michael@0 1083 },
michael@0 1084 ],
michael@0 1085 };
michael@0 1086
michael@0 1087 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1088
michael@0 1089 // Trigger update, clock set to before any activation.
michael@0 1090
michael@0 1091 let now = baseDate;
michael@0 1092 defineNow(gPolicy, now);
michael@0 1093 yield experiments.updateManifest();
michael@0 1094 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1095 "Experiments observer should have been called.");
michael@0 1096 let list = yield experiments.getExperiments();
michael@0 1097 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 1098
michael@0 1099 // Trigger update, clock set for the experiment to start but frozen.
michael@0 1100
michael@0 1101 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 1102 defineNow(gPolicy, now);
michael@0 1103 gManifestObject.experiments[0].frozen = true;
michael@0 1104 yield experiments.updateManifest();
michael@0 1105 Assert.equal(observerFireCount, expectedObserverFireCount,
michael@0 1106 "Experiments observer should have not been called.");
michael@0 1107
michael@0 1108 list = yield experiments.getExperiments();
michael@0 1109 Assert.equal(list.length, 0, "Experiment list should have no entries yet.");
michael@0 1110
michael@0 1111 // Trigger an update with the experiment not being frozen anymore.
michael@0 1112
michael@0 1113 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 1114 defineNow(gPolicy, now);
michael@0 1115 delete gManifestObject.experiments[0].frozen;
michael@0 1116 yield experiments.updateManifest();
michael@0 1117 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1118 "Experiments observer should have been called.");
michael@0 1119
michael@0 1120 list = yield experiments.getExperiments();
michael@0 1121 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1122 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1123 Assert.equal(list[0].active, true, "Experiment 1 should be active now.");
michael@0 1124
michael@0 1125 // Cleanup.
michael@0 1126
michael@0 1127 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 1128 yield testCleanup(experiments);
michael@0 1129 });
michael@0 1130
michael@0 1131 // Test that setting the frozen flag for an active experiment doesn't
michael@0 1132 // stop it.
michael@0 1133
michael@0 1134 add_task(function* test_freezeActiveExperiment() {
michael@0 1135 const OBSERVER_TOPIC = "experiments-changed";
michael@0 1136 let observerFireCount = 0;
michael@0 1137 let expectedObserverFireCount = 0;
michael@0 1138 let observer = () => ++observerFireCount;
michael@0 1139 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 1140
michael@0 1141 // Dates the following tests are based on.
michael@0 1142
michael@0 1143 let baseDate = new Date(2014, 5, 1, 12);
michael@0 1144 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 1145 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 1146
michael@0 1147 // The manifest data we test with.
michael@0 1148
michael@0 1149 gManifestObject = {
michael@0 1150 "version": 1,
michael@0 1151 experiments: [
michael@0 1152 {
michael@0 1153 id: EXPERIMENT1_ID,
michael@0 1154 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1155 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1156 startTime: dateToSeconds(startDate),
michael@0 1157 endTime: dateToSeconds(endDate),
michael@0 1158 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1159 appName: ["XPCShell"],
michael@0 1160 channel: ["nightly"],
michael@0 1161 },
michael@0 1162 ],
michael@0 1163 };
michael@0 1164
michael@0 1165 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1166
michael@0 1167 // Trigger update, clock set to before any activation.
michael@0 1168
michael@0 1169 let now = baseDate;
michael@0 1170 defineNow(gPolicy, now);
michael@0 1171 yield experiments.updateManifest();
michael@0 1172 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1173 "Experiments observer should have been called.");
michael@0 1174 let list = yield experiments.getExperiments();
michael@0 1175 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 1176
michael@0 1177 // Trigger update, clock set for the experiment to start.
michael@0 1178
michael@0 1179 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 1180 defineNow(gPolicy, now);
michael@0 1181 yield experiments.updateManifest();
michael@0 1182 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1183 "Experiments observer should have been called.");
michael@0 1184
michael@0 1185 list = yield experiments.getExperiments();
michael@0 1186 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1187 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1188 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 1189 Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match.");
michael@0 1190
michael@0 1191 // Trigger an update with the experiment being disabled.
michael@0 1192
michael@0 1193 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 1194 defineNow(gPolicy, now);
michael@0 1195 gManifestObject.experiments[0].frozen = true;
michael@0 1196 yield experiments.updateManifest();
michael@0 1197 Assert.equal(observerFireCount, expectedObserverFireCount,
michael@0 1198 "Experiments observer should have been called.");
michael@0 1199
michael@0 1200 list = yield experiments.getExperiments();
michael@0 1201 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1202 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1203 Assert.equal(list[0].active, true, "Experiment 1 should still be active.");
michael@0 1204
michael@0 1205 // Cleanup.
michael@0 1206
michael@0 1207 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 1208 yield testCleanup(experiments);
michael@0 1209 });
michael@0 1210
michael@0 1211 // Test that removing an active experiment from the manifest doesn't
michael@0 1212 // stop it.
michael@0 1213
michael@0 1214 add_task(function* test_removeActiveExperiment() {
michael@0 1215 const OBSERVER_TOPIC = "experiments-changed";
michael@0 1216 let observerFireCount = 0;
michael@0 1217 let expectedObserverFireCount = 0;
michael@0 1218 let observer = () => ++observerFireCount;
michael@0 1219 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 1220
michael@0 1221 // Dates the following tests are based on.
michael@0 1222
michael@0 1223 let baseDate = new Date(2014, 5, 1, 12);
michael@0 1224 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 1225 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 1226 let startDate2 = futureDate(baseDate, 20000 * MS_IN_ONE_DAY);
michael@0 1227 let endDate2 = futureDate(baseDate, 30000 * MS_IN_ONE_DAY);
michael@0 1228
michael@0 1229 // The manifest data we test with.
michael@0 1230
michael@0 1231 gManifestObject = {
michael@0 1232 "version": 1,
michael@0 1233 experiments: [
michael@0 1234 {
michael@0 1235 id: EXPERIMENT1_ID,
michael@0 1236 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1237 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1238 startTime: dateToSeconds(startDate),
michael@0 1239 endTime: dateToSeconds(endDate),
michael@0 1240 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1241 appName: ["XPCShell"],
michael@0 1242 channel: ["nightly"],
michael@0 1243 },
michael@0 1244 {
michael@0 1245 id: EXPERIMENT2_ID,
michael@0 1246 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1247 xpiHash: EXPERIMENT2_XPI_SHA1,
michael@0 1248 startTime: dateToSeconds(startDate2),
michael@0 1249 endTime: dateToSeconds(endDate2),
michael@0 1250 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1251 appName: ["XPCShell"],
michael@0 1252 channel: ["nightly"],
michael@0 1253 },
michael@0 1254 ],
michael@0 1255 };
michael@0 1256
michael@0 1257 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1258
michael@0 1259 // Trigger update, clock set to before any activation.
michael@0 1260
michael@0 1261 let now = baseDate;
michael@0 1262 defineNow(gPolicy, now);
michael@0 1263 yield experiments.updateManifest();
michael@0 1264 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1265 "Experiments observer should have been called.");
michael@0 1266 let list = yield experiments.getExperiments();
michael@0 1267 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 1268
michael@0 1269 // Trigger update, clock set for the experiment to start.
michael@0 1270
michael@0 1271 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 1272 defineNow(gPolicy, now);
michael@0 1273 yield experiments.updateManifest();
michael@0 1274 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1275 "Experiments observer should have been called.");
michael@0 1276
michael@0 1277 list = yield experiments.getExperiments();
michael@0 1278 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1279 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1280 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 1281 Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match.");
michael@0 1282
michael@0 1283 // Trigger an update with experiment 1 missing from the manifest
michael@0 1284
michael@0 1285 now = futureDate(now, 1 * MS_IN_ONE_DAY);
michael@0 1286 defineNow(gPolicy, now);
michael@0 1287 gManifestObject.experiments[0].frozen = true;
michael@0 1288 yield experiments.updateManifest();
michael@0 1289 Assert.equal(observerFireCount, expectedObserverFireCount,
michael@0 1290 "Experiments observer should have been called.");
michael@0 1291
michael@0 1292 list = yield experiments.getExperiments();
michael@0 1293 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1294 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1295 Assert.equal(list[0].active, true, "Experiment 1 should still be active.");
michael@0 1296
michael@0 1297 // Cleanup.
michael@0 1298
michael@0 1299 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 1300 yield testCleanup(experiments);
michael@0 1301 });
michael@0 1302
michael@0 1303 // Test that we correctly handle experiment start & install failures.
michael@0 1304
michael@0 1305 add_task(function* test_invalidUrl() {
michael@0 1306 const OBSERVER_TOPIC = "experiments-changed";
michael@0 1307 let observerFireCount = 0;
michael@0 1308 let expectedObserverFireCount = 0;
michael@0 1309 let observer = () => ++observerFireCount;
michael@0 1310 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 1311
michael@0 1312 // Dates the following tests are based on.
michael@0 1313
michael@0 1314 let baseDate = new Date(2014, 5, 1, 12);
michael@0 1315 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 1316 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 1317
michael@0 1318 // The manifest data we test with.
michael@0 1319
michael@0 1320 gManifestObject = {
michael@0 1321 "version": 1,
michael@0 1322 experiments: [
michael@0 1323 {
michael@0 1324 id: EXPERIMENT1_ID,
michael@0 1325 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME + ".invalid",
michael@0 1326 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1327 startTime: 0,
michael@0 1328 endTime: dateToSeconds(endDate),
michael@0 1329 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1330 appName: ["XPCShell"],
michael@0 1331 channel: ["nightly"],
michael@0 1332 },
michael@0 1333 ],
michael@0 1334 };
michael@0 1335
michael@0 1336 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1337
michael@0 1338 // Trigger update, clock set for the experiment to start.
michael@0 1339
michael@0 1340 let now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 1341 defineNow(gPolicy, now);
michael@0 1342 gTimerScheduleOffset = null;
michael@0 1343
michael@0 1344 yield experiments.updateManifest();
michael@0 1345 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1346 "Experiments observer should have been called.");
michael@0 1347 Assert.equal(gTimerScheduleOffset, null, "No new timer should have been scheduled.");
michael@0 1348
michael@0 1349 let list = yield experiments.getExperiments();
michael@0 1350 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 1351
michael@0 1352 // Cleanup.
michael@0 1353
michael@0 1354 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 1355 yield testCleanup(experiments);
michael@0 1356 });
michael@0 1357
michael@0 1358 // Test that we handle it properly when active experiment addons are being
michael@0 1359 // uninstalled.
michael@0 1360
michael@0 1361 add_task(function* test_unexpectedUninstall() {
michael@0 1362 const OBSERVER_TOPIC = "experiments-changed";
michael@0 1363 let observerFireCount = 0;
michael@0 1364 let expectedObserverFireCount = 0;
michael@0 1365 let observer = () => ++observerFireCount;
michael@0 1366 Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
michael@0 1367
michael@0 1368 // Dates the following tests are based on.
michael@0 1369
michael@0 1370 let baseDate = new Date(2014, 5, 1, 12);
michael@0 1371 let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
michael@0 1372 let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
michael@0 1373
michael@0 1374 // The manifest data we test with.
michael@0 1375
michael@0 1376 gManifestObject = {
michael@0 1377 "version": 1,
michael@0 1378 experiments: [
michael@0 1379 {
michael@0 1380 id: EXPERIMENT1_ID,
michael@0 1381 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1382 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1383 startTime: dateToSeconds(startDate),
michael@0 1384 endTime: dateToSeconds(endDate),
michael@0 1385 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1386 appName: ["XPCShell"],
michael@0 1387 channel: ["nightly"],
michael@0 1388 },
michael@0 1389 ],
michael@0 1390 };
michael@0 1391
michael@0 1392 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1393
michael@0 1394 // Trigger update, clock set to before any activation.
michael@0 1395
michael@0 1396 let now = baseDate;
michael@0 1397 defineNow(gPolicy, now);
michael@0 1398 yield experiments.updateManifest();
michael@0 1399 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1400 "Experiments observer should have been called.");
michael@0 1401 let list = yield experiments.getExperiments();
michael@0 1402 Assert.equal(list.length, 0, "Experiment list should be empty.");
michael@0 1403
michael@0 1404 // Trigger update, clock set for the experiment to start.
michael@0 1405
michael@0 1406 now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
michael@0 1407 defineNow(gPolicy, now);
michael@0 1408 yield experiments.updateManifest();
michael@0 1409 Assert.equal(observerFireCount, ++expectedObserverFireCount,
michael@0 1410 "Experiments observer should have been called.");
michael@0 1411
michael@0 1412 list = yield experiments.getExperiments();
michael@0 1413 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1414 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1415 Assert.equal(list[0].active, true, "Experiment 1 should be active.");
michael@0 1416
michael@0 1417 // Uninstall the addon through the addon manager instead of stopping it through
michael@0 1418 // the experiments API.
michael@0 1419
michael@0 1420 yield AddonTestUtils.uninstallAddonByID(EXPERIMENT1_ID);
michael@0 1421 yield experiments._mainTask;
michael@0 1422
michael@0 1423 yield experiments.notify();
michael@0 1424
michael@0 1425 list = yield experiments.getExperiments();
michael@0 1426 Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
michael@0 1427 Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1428 Assert.equal(list[0].active, false, "Experiment 1 should not be active anymore.");
michael@0 1429
michael@0 1430 // Cleanup.
michael@0 1431
michael@0 1432 Services.obs.removeObserver(observer, OBSERVER_TOPIC);
michael@0 1433 yield testCleanup(experiments);
michael@0 1434 });
michael@0 1435
michael@0 1436 // If the Addon Manager knows of an experiment that we don't, it should get
michael@0 1437 // uninstalled.
michael@0 1438 add_task(function* testUnknownExperimentsUninstalled() {
michael@0 1439 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1440
michael@0 1441 let addons = yield getExperimentAddons();
michael@0 1442 Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are present.");
michael@0 1443
michael@0 1444 // Simulate us not listening.
michael@0 1445 experiments._unregisterWithAddonManager();
michael@0 1446 yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1);
michael@0 1447 experiments._registerWithAddonManager();
michael@0 1448
michael@0 1449 addons = yield getExperimentAddons();
michael@0 1450 Assert.equal(addons.length, 1, "Experiment 1 installed via AddonManager");
michael@0 1451
michael@0 1452 // Simulate no known experiments.
michael@0 1453 gManifestObject = {
michael@0 1454 "version": 1,
michael@0 1455 experiments: [],
michael@0 1456 };
michael@0 1457
michael@0 1458 yield experiments.updateManifest();
michael@0 1459 let fromManifest = yield experiments.getExperiments();
michael@0 1460 Assert.equal(fromManifest.length, 0, "No experiments known in manifest.");
michael@0 1461
michael@0 1462 // And the unknown add-on should be gone.
michael@0 1463 addons = yield getExperimentAddons();
michael@0 1464 Assert.equal(addons.length, 0, "Experiment 1 was uninstalled.");
michael@0 1465
michael@0 1466 yield testCleanup(experiments);
michael@0 1467 });
michael@0 1468
michael@0 1469 // If someone else installs an experiment add-on, we detect and stop that.
michael@0 1470 add_task(function* testForeignExperimentInstall() {
michael@0 1471 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1472
michael@0 1473 gManifestObject = {
michael@0 1474 "version": 1,
michael@0 1475 experiments: [],
michael@0 1476 };
michael@0 1477
michael@0 1478 yield experiments.init();
michael@0 1479
michael@0 1480 let addons = yield getExperimentAddons();
michael@0 1481 Assert.equal(addons.length, 0, "Precondition: No experiment add-ons present.");
michael@0 1482
michael@0 1483 let failed = false;
michael@0 1484 try {
michael@0 1485 yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1);
michael@0 1486 } catch (ex) {
michael@0 1487 failed = true;
michael@0 1488 }
michael@0 1489 Assert.ok(failed, "Add-on install should not have completed successfully");
michael@0 1490 addons = yield getExperimentAddons();
michael@0 1491 Assert.equal(addons.length, 0, "Add-on install should have been cancelled.");
michael@0 1492
michael@0 1493 yield testCleanup(experiments);
michael@0 1494 });
michael@0 1495
michael@0 1496 // Experiment add-ons will be disabled after Addon Manager restarts. Ensure
michael@0 1497 // we enable them automatically.
michael@0 1498 add_task(function* testEnabledAfterRestart() {
michael@0 1499 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1500
michael@0 1501 gManifestObject = {
michael@0 1502 "version": 1,
michael@0 1503 experiments: [
michael@0 1504 {
michael@0 1505 id: EXPERIMENT1_ID,
michael@0 1506 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1507 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1508 startTime: gPolicy.now().getTime() / 1000 - 60,
michael@0 1509 endTime: gPolicy.now().getTime() / 1000 + 60,
michael@0 1510 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1511 appName: ["XPCShell"],
michael@0 1512 channel: ["nightly"],
michael@0 1513 },
michael@0 1514 ],
michael@0 1515 };
michael@0 1516
michael@0 1517 let addons = yield getExperimentAddons();
michael@0 1518 Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed.");
michael@0 1519
michael@0 1520 yield experiments.updateManifest();
michael@0 1521 let fromManifest = yield experiments.getExperiments();
michael@0 1522 Assert.equal(fromManifest.length, 1, "A single experiment is known.");
michael@0 1523
michael@0 1524 addons = yield getExperimentAddons();
michael@0 1525 Assert.equal(addons.length, 1, "A single experiment add-on is installed.");
michael@0 1526 Assert.ok(addons[0].isActive, "That experiment is active.");
michael@0 1527
michael@0 1528 dump("Restarting Addon Manager\n");
michael@0 1529 experiments._unregisterWithAddonManager();
michael@0 1530 restartManager();
michael@0 1531 experiments._registerWithAddonManager();
michael@0 1532
michael@0 1533 addons = yield getExperimentAddons();
michael@0 1534 Assert.equal(addons.length, 1, "The experiment is still there after restart.");
michael@0 1535 Assert.ok(addons[0].userDisabled, "But it is disabled.");
michael@0 1536 Assert.equal(addons[0].isActive, false, "And not active.");
michael@0 1537
michael@0 1538 yield experiments.updateManifest();
michael@0 1539 Assert.ok(addons[0].isActive, "It activates when the manifest is evaluated.");
michael@0 1540
michael@0 1541 yield testCleanup(experiments);
michael@0 1542 });
michael@0 1543
michael@0 1544 // Test coverage for an add-on uninstall disabling the experiment and that it stays
michael@0 1545 // disabled over restarts.
michael@0 1546 add_task(function* test_foreignUninstallAndRestart() {
michael@0 1547 let experiments = new Experiments.Experiments(gPolicy);
michael@0 1548
michael@0 1549 gManifestObject = {
michael@0 1550 "version": 1,
michael@0 1551 experiments: [
michael@0 1552 {
michael@0 1553 id: EXPERIMENT1_ID,
michael@0 1554 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
michael@0 1555 xpiHash: EXPERIMENT1_XPI_SHA1,
michael@0 1556 startTime: gPolicy.now().getTime() / 1000 - 60,
michael@0 1557 endTime: gPolicy.now().getTime() / 1000 + 60,
michael@0 1558 maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
michael@0 1559 appName: ["XPCShell"],
michael@0 1560 channel: ["nightly"],
michael@0 1561 },
michael@0 1562 ],
michael@0 1563 };
michael@0 1564
michael@0 1565 let addons = yield getExperimentAddons();
michael@0 1566 Assert.equal(addons.length, 0, "Precondition: No experiment add-ons installed.");
michael@0 1567
michael@0 1568 yield experiments.updateManifest();
michael@0 1569 let experimentList = yield experiments.getExperiments();
michael@0 1570 Assert.equal(experimentList.length, 1, "A single experiment is known.");
michael@0 1571
michael@0 1572 addons = yield getExperimentAddons();
michael@0 1573 Assert.equal(addons.length, 1, "A single experiment add-on is installed.");
michael@0 1574 Assert.ok(addons[0].isActive, "That experiment is active.");
michael@0 1575
michael@0 1576 yield AddonTestUtils.uninstallAddonByID(EXPERIMENT1_ID);
michael@0 1577 yield experiments._mainTask;
michael@0 1578
michael@0 1579 let addons = yield getExperimentAddons();
michael@0 1580 Assert.equal(addons.length, 0, "Experiment add-on should have been removed.");
michael@0 1581
michael@0 1582 experimentList = yield experiments.getExperiments();
michael@0 1583 Assert.equal(experimentList.length, 1, "A single experiment is known.");
michael@0 1584 Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1585 Assert.ok(!experimentList[0].active, "Experiment 1 should not be active anymore.");
michael@0 1586
michael@0 1587 // Fake restart behaviour.
michael@0 1588 experiments.uninit();
michael@0 1589 restartManager();
michael@0 1590 experiments = new Experiments.Experiments(gPolicy);
michael@0 1591 yield experiments.updateManifest();
michael@0 1592
michael@0 1593 let addons = yield getExperimentAddons();
michael@0 1594 Assert.equal(addons.length, 0, "No experiment add-ons installed.");
michael@0 1595
michael@0 1596 experimentList = yield experiments.getExperiments();
michael@0 1597 Assert.equal(experimentList.length, 1, "A single experiment is known.");
michael@0 1598 Assert.equal(experimentList[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
michael@0 1599 Assert.ok(!experimentList[0].active, "Experiment 1 should not be active.");
michael@0 1600
michael@0 1601 yield testCleanup(experiments);
michael@0 1602 });

mercurial