browser/experiments/test/xpcshell/test_conditions.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:0707864a832d
1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
3
4 "use strict";
5
6
7 Cu.import("resource:///modules/experiments/Experiments.jsm");
8
9 const FILE_MANIFEST = "experiments.manifest";
10 const SEC_IN_ONE_DAY = 24 * 60 * 60;
11 const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
12
13 let gProfileDir = null;
14 let gHttpServer = null;
15 let gHttpRoot = null;
16 let gReporter = null;
17 let gPolicy = null;
18
19
20 function ManifestEntry(data) {
21 this.id = EXPERIMENT1_ID;
22 this.xpiURL = "http://localhost:1/dummy.xpi";
23 this.xpiHash = EXPERIMENT1_XPI_SHA1;
24 this.startTime = new Date(2010, 0, 1, 12).getTime() / 1000;
25 this.endTime = new Date(9001, 0, 1, 12).getTime() / 1000;
26 this.maxActiveSeconds = SEC_IN_ONE_DAY;
27 this.appName = ["XPCShell"];
28 this.channel = ["nightly"];
29
30 data = data || {};
31 for (let k of Object.keys(data)) {
32 this[k] = data[k];
33 }
34
35 if (!this.endTime) {
36 this.endTime = this.startTime + 5 * SEC_IN_ONE_DAY;
37 }
38 }
39
40 function applicableFromManifestData(data, policy) {
41 let manifestData = new ManifestEntry(data);
42 let entry = new Experiments.ExperimentEntry(policy);
43 entry.initFromManifestData(manifestData);
44 return entry.isApplicable();
45 }
46
47 function run_test() {
48 run_next_test();
49 }
50
51 add_task(function* test_setup() {
52 createAppInfo();
53 gProfileDir = do_get_profile();
54 gPolicy = new Experiments.Policy();
55
56 gReporter = yield getReporter("json_payload_simple");
57 yield gReporter.collectMeasurements();
58 let payload = yield gReporter.getJSONPayload(true);
59 do_register_cleanup(() => gReporter._shutdown());
60
61 patchPolicy(gPolicy, {
62 updatechannel: () => "nightly",
63 locale: () => "en-US",
64 healthReportPayload: () => Promise.resolve(payload),
65 random: () => 0.5,
66 });
67
68 Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
69 Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
70 Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
71
72 let experiments = new Experiments.Experiments();
73 });
74
75 function arraysEqual(a, b) {
76 if (a.length !== b.length) {
77 return false;
78 }
79
80 for (let i=0; i<a.length; ++i) {
81 if (a[i] !== b[i]) {
82 return false;
83 }
84 }
85
86 return true;
87 }
88
89 // This function exists solely to be .toSource()d
90 const sanityFilter = function filter(c) {
91 if (c.telemetryPayload === undefined) {
92 throw Error("No .telemetryPayload");
93 }
94 if (c.telemetryPayload.simpleMeasurements === undefined) {
95 throw Error("No .simpleMeasurements");
96 }
97 if (c.healthReportPayload === undefined) {
98 throw Error("No .healthReportPayload");
99 }
100 if (c.healthReportPayload.geckoAppInfo == undefined) {
101 throw Error("No .geckoAppInfo");
102 }
103 return true;
104 }
105
106 add_task(function* test_simpleFields() {
107 let testData = [
108 // "expected applicable?", failure reason or null, manifest data
109
110 // misc. environment
111
112 [false, ["appName"], {appName: []}],
113 [false, ["appName"], {appName: ["foo", gAppInfo.name + "-invalid"]}],
114 [true, null, {appName: ["not-an-app-name", gAppInfo.name]}],
115
116 [false, ["os"], {os: []}],
117 [false, ["os"], {os: ["42", "abcdef"]}],
118 [true, null, {os: [gAppInfo.OS, "plan9"]}],
119
120 [false, ["channel"], {channel: []}],
121 [false, ["channel"], {channel: ["foo", gPolicy.updatechannel() + "-invalid"]}],
122 [true, null, {channel: ["not-a-channel", gPolicy.updatechannel()]}],
123
124 [false, ["locale"], {locale: []}],
125 [false, ["locale"], {locale: ["foo", gPolicy.locale + "-invalid"]}],
126 [true, null, {locale: ["not-a-locale", gPolicy.locale()]}],
127
128 // version
129
130 [false, ["version"], {version: []}],
131 [false, ["version"], {version: ["-1", gAppInfo.version + "-invalid", "asdf", "0,4", "99.99", "0.1.1.1"]}],
132 [true, null, {version: ["99999999.999", "-1", gAppInfo.version]}],
133
134 [false, ["minVersion"], {minVersion: "1.0.1"}],
135 [true, null, {minVersion: "1.0b1"}],
136 [true, null, {minVersion: "1.0"}],
137 [true, null, {minVersion: "0.9"}],
138
139 [false, ["maxVersion"], {maxVersion: "0.1"}],
140 [false, ["maxVersion"], {maxVersion: "0.9.9"}],
141 [false, ["maxVersion"], {maxVersion: "1.0b1"}],
142 [true, ["maxVersion"], {maxVersion: "1.0"}],
143 [true, ["maxVersion"], {maxVersion: "1.7pre"}],
144
145 // build id
146
147 [false, ["buildIDs"], {buildIDs: []}],
148 [false, ["buildIDs"], {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID + "-invalid"]}],
149 [true, null, {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}],
150
151 [true, null, {minBuildID: "2014060501"}],
152 [true, null, {minBuildID: "2014060601"}],
153 [false, ["minBuildID"], {minBuildID: "2014060701"}],
154
155 [false, ["maxBuildID"], {maxBuildID: "2014010101"}],
156 [true, null, {maxBuildID: "2014060601"}],
157 [true, null, {maxBuildID: "2014060901"}],
158
159 // sample
160
161 [false, ["sample"], {sample: -1 }],
162 [false, ["sample"], {sample: 0.0}],
163 [false, ["sample"], {sample: 0.1}],
164 [true, null, {sample: 0.5}],
165 [true, null, {sample: 0.6}],
166 [true, null, {sample: 1.0}],
167 [true, null, {sample: 0.5}],
168
169 // experiment control
170
171 [false, ["disabled"], {disabled: true}],
172 [true, null, {disabled: false}],
173
174 [false, ["frozen"], {frozen: true}],
175 [true, null, {frozen: false}],
176
177 [false, null, {frozen: true, disabled: true}],
178 [false, null, {frozen: true, disabled: false}],
179 [false, null, {frozen: false, disabled: true}],
180 [true, null, {frozen: false, disabled: false}],
181
182 // jsfilter
183
184 [true, null, {jsfilter: "function filter(c) { return true; }"}],
185 [false, ["jsfilter-false"], {jsfilter: "function filter(c) { return false; }"}],
186 [true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy
187 [false, ["jsfilter-false"], {jsfilter: "function filter(c) { return ''; }"}], // falsy
188 [false, ["jsfilter-false"], {jsfilter: "function filter(c) { var a = []; }"}], // undefined
189 [false, ["jsfilter-threw", "some error"], {jsfilter: "function filter(c) { throw new Error('some error'); }"}],
190 [false, ["jsfilter-evalfailed"], {jsfilter: "123, this won't work"}],
191 [true, null, {jsfilter: "var filter = " + sanityFilter.toSource()}],
192 ];
193
194 for (let i=0; i<testData.length; ++i) {
195 let entry = testData[i];
196 let applicable;
197 let reason = null;
198
199 yield applicableFromManifestData(entry[2], gPolicy).then(
200 value => applicable = value,
201 value => {
202 applicable = false;
203 reason = value;
204 }
205 );
206
207 Assert.equal(applicable, entry[0],
208 "Experiment entry applicability should match for test "
209 + i + ": " + JSON.stringify(entry[2]));
210
211 let expectedReason = entry[1];
212 if (!applicable && expectedReason) {
213 Assert.ok(arraysEqual(reason, expectedReason),
214 "Experiment rejection reasons should match for test " + i + ". "
215 + "Got " + JSON.stringify(reason) + ", expected "
216 + JSON.stringify(expectedReason));
217 }
218 }
219 });
220
221 add_task(function* test_times() {
222 let now = new Date(2014, 5, 6, 12);
223 let nowSec = now.getTime() / 1000;
224 let testData = [
225 // "expected applicable?", rejection reason or null, fake now date, manifest data
226
227 // start time
228
229 [true, null, now,
230 {startTime: nowSec - 5 * SEC_IN_ONE_DAY,
231 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
232 [true, null, now,
233 {startTime: nowSec ,
234 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
235 [false, "startTime", now,
236 {startTime: nowSec + 5 * SEC_IN_ONE_DAY,
237 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
238
239 // end time
240
241 [false, "endTime", now,
242 {startTime: nowSec - 5 * SEC_IN_ONE_DAY,
243 endTime: nowSec - 10 * SEC_IN_ONE_DAY}],
244 [false, "endTime", now,
245 {startTime: nowSec - 5 * SEC_IN_ONE_DAY,
246 endTime: nowSec - 5 * SEC_IN_ONE_DAY}],
247
248 // max start time
249
250 [false, "maxStartTime", now,
251 {maxStartTime: nowSec - 15 * SEC_IN_ONE_DAY,
252 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
253 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
254 [false, "maxStartTime", now,
255 {maxStartTime: nowSec - 1 * SEC_IN_ONE_DAY,
256 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
257 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
258 [false, "maxStartTime", now,
259 {maxStartTime: nowSec - 10 * SEC_IN_ONE_DAY,
260 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
261 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
262 [true, null, now,
263 {maxStartTime: nowSec,
264 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
265 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
266 [true, null, now,
267 {maxStartTime: nowSec + 1 * SEC_IN_ONE_DAY,
268 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
269 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
270
271 // max active seconds
272
273 [true, null, now,
274 {maxActiveSeconds: 5 * SEC_IN_ONE_DAY,
275 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
276 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
277 [true, null, now,
278 {maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
279 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
280 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
281 [true, null, now,
282 {maxActiveSeconds: 15 * SEC_IN_ONE_DAY,
283 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
284 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
285 [true, null, now,
286 {maxActiveSeconds: 20 * SEC_IN_ONE_DAY,
287 startTime: nowSec - 10 * SEC_IN_ONE_DAY,
288 endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
289 ];
290
291 for (let i=0; i<testData.length; ++i) {
292 let entry = testData[i];
293 let applicable;
294 let reason = null;
295 defineNow(gPolicy, entry[2]);
296
297 yield applicableFromManifestData(entry[3], gPolicy).then(
298 value => applicable = value,
299 value => {
300 applicable = false;
301 reason = value;
302 }
303 );
304
305 Assert.equal(applicable, entry[0],
306 "Experiment entry applicability should match for test "
307 + i + ": " + JSON.stringify([entry[2], entry[3]]));
308 if (!applicable && entry[1]) {
309 Assert.equal(reason, entry[1], "Experiment rejection reason should match for test " + i);
310 }
311 }
312 });

mercurial