|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 "use strict"; |
|
5 |
|
6 Cu.import("resource://testing-common/httpd.js"); |
|
7 Cu.import("resource://testing-common/AddonManagerTesting.jsm"); |
|
8 |
|
9 XPCOMUtils.defineLazyModuleGetter(this, "Experiments", |
|
10 "resource:///modules/experiments/Experiments.jsm"); |
|
11 |
|
12 const FILE_MANIFEST = "experiments.manifest"; |
|
13 const MANIFEST_HANDLER = "manifests/handler"; |
|
14 |
|
15 const SEC_IN_ONE_DAY = 24 * 60 * 60; |
|
16 const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000; |
|
17 |
|
18 let gProfileDir = null; |
|
19 let gHttpServer = null; |
|
20 let gHttpRoot = null; |
|
21 let gDataRoot = null; |
|
22 let gReporter = null; |
|
23 let gPolicy = null; |
|
24 let gManifestObject = null; |
|
25 let gManifestHandlerURI = null; |
|
26 |
|
27 function run_test() { |
|
28 run_next_test(); |
|
29 } |
|
30 |
|
31 add_task(function* test_setup() { |
|
32 loadAddonManager(); |
|
33 gProfileDir = do_get_profile(); |
|
34 |
|
35 gHttpServer = new HttpServer(); |
|
36 gHttpServer.start(-1); |
|
37 let port = gHttpServer.identity.primaryPort; |
|
38 gHttpRoot = "http://localhost:" + port + "/"; |
|
39 gDataRoot = gHttpRoot + "data/"; |
|
40 gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER; |
|
41 gHttpServer.registerDirectory("/data/", do_get_cwd()); |
|
42 gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => { |
|
43 response.setStatusLine(null, 200, "OK"); |
|
44 response.write(JSON.stringify(gManifestObject)); |
|
45 response.processAsync(); |
|
46 response.finish(); |
|
47 }); |
|
48 do_register_cleanup(() => gHttpServer.stop(() => {})); |
|
49 |
|
50 disableCertificateChecks(); |
|
51 |
|
52 Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true); |
|
53 Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0); |
|
54 Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true); |
|
55 Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI); |
|
56 Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0); |
|
57 |
|
58 gReporter = yield getReporter("json_payload_simple"); |
|
59 yield gReporter.collectMeasurements(); |
|
60 let payload = yield gReporter.getJSONPayload(true); |
|
61 do_register_cleanup(() => gReporter._shutdown()); |
|
62 |
|
63 gPolicy = new Experiments.Policy(); |
|
64 patchPolicy(gPolicy, { |
|
65 updatechannel: () => "nightly", |
|
66 healthReportPayload: () => Promise.resolve(payload), |
|
67 oneshotTimer: (callback, timeout, thisObj, name) => {}, |
|
68 }); |
|
69 }); |
|
70 |
|
71 // Test disabling the feature stops current and future experiments. |
|
72 |
|
73 add_task(function* test_disableExperiments() { |
|
74 const OBSERVER_TOPIC = "experiments-changed"; |
|
75 let observerFireCount = 0; |
|
76 let expectedObserverFireCount = 0; |
|
77 let observer = () => ++observerFireCount; |
|
78 Services.obs.addObserver(observer, OBSERVER_TOPIC, false); |
|
79 |
|
80 // Dates the following tests are based on. |
|
81 |
|
82 let baseDate = new Date(2014, 5, 1, 12); |
|
83 let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY); |
|
84 let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY); |
|
85 let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY); |
|
86 let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY); |
|
87 |
|
88 // The manifest data we test with. |
|
89 |
|
90 gManifestObject = { |
|
91 "version": 1, |
|
92 experiments: [ |
|
93 { |
|
94 id: EXPERIMENT2_ID, |
|
95 xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME, |
|
96 xpiHash: EXPERIMENT2_XPI_SHA1, |
|
97 startTime: dateToSeconds(startDate2), |
|
98 endTime: dateToSeconds(endDate2), |
|
99 maxActiveSeconds: 10 * SEC_IN_ONE_DAY, |
|
100 appName: ["XPCShell"], |
|
101 channel: ["nightly"], |
|
102 }, |
|
103 { |
|
104 id: EXPERIMENT1_ID, |
|
105 xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME, |
|
106 xpiHash: EXPERIMENT1_XPI_SHA1, |
|
107 startTime: dateToSeconds(startDate1), |
|
108 endTime: dateToSeconds(endDate1), |
|
109 maxActiveSeconds: 10 * SEC_IN_ONE_DAY, |
|
110 appName: ["XPCShell"], |
|
111 channel: ["nightly"], |
|
112 }, |
|
113 ], |
|
114 }; |
|
115 |
|
116 let experiments = new Experiments.Experiments(gPolicy); |
|
117 |
|
118 // Trigger update, clock set to before any activation. |
|
119 // Use updateManifest() to provide for coverage of that path. |
|
120 |
|
121 let now = baseDate; |
|
122 defineNow(gPolicy, now); |
|
123 |
|
124 yield experiments.updateManifest(); |
|
125 Assert.equal(observerFireCount, ++expectedObserverFireCount, |
|
126 "Experiments observer should have been called."); |
|
127 let list = yield experiments.getExperiments(); |
|
128 Assert.equal(list.length, 0, "Experiment list should be empty."); |
|
129 let addons = yield getExperimentAddons(); |
|
130 Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed."); |
|
131 |
|
132 // Trigger update, clock set for experiment 1 to start. |
|
133 |
|
134 now = futureDate(startDate1, 5 * MS_IN_ONE_DAY); |
|
135 defineNow(gPolicy, now); |
|
136 |
|
137 yield experiments.updateManifest(); |
|
138 Assert.equal(observerFireCount, ++expectedObserverFireCount, |
|
139 "Experiments observer should have been called."); |
|
140 |
|
141 list = yield experiments.getExperiments(); |
|
142 Assert.equal(list.length, 1, "Experiment list should have 1 entry now."); |
|
143 Assert.equal(list[0].active, true, "Experiment should be active."); |
|
144 addons = yield getExperimentAddons(); |
|
145 Assert.equal(addons.length, 1, "An experiment add-on was installed."); |
|
146 |
|
147 // Disable the experiments feature. Check that we stop the running experiment. |
|
148 |
|
149 Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, false); |
|
150 yield experiments._mainTask; |
|
151 |
|
152 Assert.equal(observerFireCount, ++expectedObserverFireCount, |
|
153 "Experiments observer should have been called."); |
|
154 |
|
155 list = yield experiments.getExperiments(); |
|
156 Assert.equal(list.length, 1, "Experiment list should have 1 entry."); |
|
157 Assert.equal(list[0].active, false, "Experiment entry should not be active."); |
|
158 addons = yield getExperimentAddons(); |
|
159 Assert.equal(addons.length, 0, "The experiment add-on should be uninstalled."); |
|
160 |
|
161 // Trigger update, clock set for experiment 2 to start. Verify we don't start it. |
|
162 |
|
163 now = startDate2; |
|
164 defineNow(gPolicy, now); |
|
165 |
|
166 try { |
|
167 yield experiments.updateManifest(); |
|
168 } catch (e if e.message == "experiments are disabled") { |
|
169 // This exception is expected. |
|
170 } |
|
171 |
|
172 experiments.notify(); |
|
173 yield experiments._mainTask; |
|
174 |
|
175 Assert.equal(observerFireCount, expectedObserverFireCount, |
|
176 "Experiments observer should not have been called."); |
|
177 |
|
178 list = yield experiments.getExperiments(); |
|
179 Assert.equal(list.length, 1, "Experiment list should still have 1 entry."); |
|
180 Assert.equal(list[0].active, false, "Experiment entry should not be active."); |
|
181 addons = yield getExperimentAddons(); |
|
182 Assert.equal(addons.length, 0, "There should still be no experiment add-on installed."); |
|
183 |
|
184 // Cleanup. |
|
185 |
|
186 Services.obs.removeObserver(observer, OBSERVER_TOPIC); |
|
187 yield experiments.uninit(); |
|
188 yield removeCacheFile(); |
|
189 }); |