|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 "use strict"; |
|
5 |
|
6 const {classes: Cc, interfaces: Ci, utils: Cu} = Components; |
|
7 |
|
8 Cu.import("resource://services-common/observers.js"); |
|
9 Cu.import("resource://services-common/utils.js"); |
|
10 Cu.import("resource://gre/modules/Promise.jsm"); |
|
11 Cu.import("resource://gre/modules/Metrics.jsm"); |
|
12 Cu.import("resource://gre/modules/osfile.jsm"); |
|
13 Cu.import("resource://gre/modules/Preferences.jsm"); |
|
14 let bsp = Cu.import("resource://gre/modules/services/healthreport/healthreporter.jsm"); |
|
15 Cu.import("resource://gre/modules/services/healthreport/providers.jsm"); |
|
16 Cu.import("resource://gre/modules/services/datareporting/policy.jsm"); |
|
17 Cu.import("resource://gre/modules/Services.jsm"); |
|
18 Cu.import("resource://gre/modules/Task.jsm"); |
|
19 Cu.import("resource://testing-common/httpd.js"); |
|
20 Cu.import("resource://testing-common/services-common/bagheeraserver.js"); |
|
21 Cu.import("resource://testing-common/services/metrics/mocks.jsm"); |
|
22 Cu.import("resource://testing-common/services/healthreport/utils.jsm"); |
|
23 Cu.import("resource://testing-common/AppData.jsm"); |
|
24 |
|
25 |
|
26 const DUMMY_URI = "http://localhost:62013/"; |
|
27 const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000; |
|
28 |
|
29 const HealthReporterState = bsp.HealthReporterState; |
|
30 |
|
31 |
|
32 function defineNow(policy, now) { |
|
33 print("Adjusting fake system clock to " + now); |
|
34 Object.defineProperty(policy, "now", { |
|
35 value: function customNow() { |
|
36 return now; |
|
37 }, |
|
38 writable: true, |
|
39 }); |
|
40 } |
|
41 |
|
42 function getReporter(name, uri, inspected) { |
|
43 return Task.spawn(function init() { |
|
44 let reporter = getHealthReporter(name, uri, inspected); |
|
45 yield reporter.init(); |
|
46 |
|
47 yield reporter._providerManager.registerProviderFromType( |
|
48 HealthReportProvider); |
|
49 |
|
50 throw new Task.Result(reporter); |
|
51 }); |
|
52 } |
|
53 |
|
54 function getReporterAndServer(name, namespace="test") { |
|
55 return Task.spawn(function get() { |
|
56 let server = new BagheeraServer(); |
|
57 server.createNamespace(namespace); |
|
58 server.start(); |
|
59 |
|
60 let reporter = yield getReporter(name, server.serverURI); |
|
61 reporter.serverNamespace = namespace; |
|
62 |
|
63 throw new Task.Result([reporter, server]); |
|
64 }); |
|
65 } |
|
66 |
|
67 function shutdownServer(server) { |
|
68 let deferred = Promise.defer(); |
|
69 server.stop(deferred.resolve.bind(deferred)); |
|
70 |
|
71 return deferred.promise; |
|
72 } |
|
73 |
|
74 function getHealthReportProviderValues(reporter, day=null) { |
|
75 return Task.spawn(function getValues() { |
|
76 let p = reporter.getProvider("org.mozilla.healthreport"); |
|
77 do_check_neq(p, null); |
|
78 let m = p.getMeasurement("submissions", 2); |
|
79 do_check_neq(m, null); |
|
80 |
|
81 let data = yield reporter._storage.getMeasurementValues(m.id); |
|
82 if (!day) { |
|
83 throw new Task.Result(data); |
|
84 } |
|
85 |
|
86 do_check_true(data.days.hasDay(day)); |
|
87 let serializer = m.serializer(m.SERIALIZE_JSON) |
|
88 let json = serializer.daily(data.days.getDay(day)); |
|
89 do_check_eq(json._v, 2); |
|
90 |
|
91 throw new Task.Result(json); |
|
92 }); |
|
93 } |
|
94 |
|
95 function run_test() { |
|
96 run_next_test(); |
|
97 } |
|
98 |
|
99 // run_test() needs to finish synchronously, so we do async init here. |
|
100 add_task(function test_init() { |
|
101 yield makeFakeAppDir(); |
|
102 }); |
|
103 |
|
104 add_task(function test_constructor() { |
|
105 let reporter = yield getReporter("constructor"); |
|
106 |
|
107 try { |
|
108 do_check_eq(reporter.lastPingDate.getTime(), 0); |
|
109 do_check_null(reporter.lastSubmitID); |
|
110 do_check_eq(typeof(reporter._state), "object"); |
|
111 do_check_eq(reporter._state.lastPingDate.getTime(), 0); |
|
112 do_check_eq(reporter._state.remoteIDs.length, 0); |
|
113 do_check_eq(reporter._state.clientIDVersion, 1); |
|
114 do_check_neq(reporter._state.clientID, null); |
|
115 |
|
116 let failed = false; |
|
117 try { |
|
118 new HealthReporter("foo.bar"); |
|
119 } catch (ex) { |
|
120 failed = true; |
|
121 do_check_true(ex.message.startsWith("Branch must end")); |
|
122 } finally { |
|
123 do_check_true(failed); |
|
124 failed = false; |
|
125 } |
|
126 } finally { |
|
127 reporter._shutdown(); |
|
128 } |
|
129 }); |
|
130 |
|
131 add_task(function test_shutdown_normal() { |
|
132 let reporter = yield getReporter("shutdown_normal"); |
|
133 |
|
134 // We can't send "quit-application" notification because the xpcshell runner |
|
135 // will shut down! |
|
136 reporter._initiateShutdown(); |
|
137 reporter._waitForShutdown(); |
|
138 }); |
|
139 |
|
140 add_task(function test_shutdown_storage_in_progress() { |
|
141 let reporter = yield getHealthReporter("shutdown_storage_in_progress", DUMMY_URI, true); |
|
142 |
|
143 reporter.onStorageCreated = function () { |
|
144 print("Faking shutdown during storage initialization."); |
|
145 reporter._initiateShutdown(); |
|
146 }; |
|
147 |
|
148 reporter.init(); |
|
149 |
|
150 reporter._waitForShutdown(); |
|
151 do_check_eq(reporter.providerManagerShutdownCount, 0); |
|
152 do_check_eq(reporter.storageCloseCount, 1); |
|
153 }); |
|
154 |
|
155 // Ensure that a shutdown triggered while provider manager is initializing |
|
156 // results in shutdown and storage closure. |
|
157 add_task(function test_shutdown_provider_manager_in_progress() { |
|
158 let reporter = yield getHealthReporter("shutdown_provider_manager_in_progress", |
|
159 DUMMY_URI, true); |
|
160 |
|
161 reporter.onProviderManagerInitialized = function () { |
|
162 print("Faking shutdown during provider manager initialization."); |
|
163 reporter._initiateShutdown(); |
|
164 }; |
|
165 |
|
166 reporter.init(); |
|
167 |
|
168 // This will hang if shutdown logic is busted. |
|
169 reporter._waitForShutdown(); |
|
170 do_check_eq(reporter.providerManagerShutdownCount, 1); |
|
171 do_check_eq(reporter.storageCloseCount, 1); |
|
172 }); |
|
173 |
|
174 // Simulates an error during provider manager initialization and verifies we shut down. |
|
175 add_task(function test_shutdown_when_provider_manager_errors() { |
|
176 let reporter = yield getHealthReporter("shutdown_when_provider_manager_errors", |
|
177 DUMMY_URI, true); |
|
178 |
|
179 reporter.onInitializeProviderManagerFinished = function () { |
|
180 print("Throwing fake error."); |
|
181 throw new Error("Fake error during provider manager initialization."); |
|
182 }; |
|
183 |
|
184 reporter.init(); |
|
185 |
|
186 // This will hang if shutdown logic is busted. |
|
187 reporter._waitForShutdown(); |
|
188 do_check_eq(reporter.providerManagerShutdownCount, 1); |
|
189 do_check_eq(reporter.storageCloseCount, 1); |
|
190 }); |
|
191 |
|
192 // Pull-only providers are only initialized at collect time. |
|
193 add_task(function test_pull_only_providers() { |
|
194 const category = "healthreporter-constant-only"; |
|
195 |
|
196 let cm = Cc["@mozilla.org/categorymanager;1"] |
|
197 .getService(Ci.nsICategoryManager); |
|
198 cm.addCategoryEntry(category, "DummyProvider", |
|
199 "resource://testing-common/services/metrics/mocks.jsm", |
|
200 false, true); |
|
201 cm.addCategoryEntry(category, "DummyConstantProvider", |
|
202 "resource://testing-common/services/metrics/mocks.jsm", |
|
203 false, true); |
|
204 |
|
205 let reporter = yield getReporter("constant_only_providers"); |
|
206 try { |
|
207 let initCount = reporter._providerManager.providers.length; |
|
208 yield reporter._providerManager.registerProvidersFromCategoryManager(category); |
|
209 do_check_eq(reporter._providerManager._providers.size, initCount + 1); |
|
210 do_check_true(reporter._storage.hasProvider("DummyProvider")); |
|
211 do_check_false(reporter._storage.hasProvider("DummyConstantProvider")); |
|
212 do_check_neq(reporter.getProvider("DummyProvider"), null); |
|
213 do_check_null(reporter.getProvider("DummyConstantProvider")); |
|
214 |
|
215 yield reporter.collectMeasurements(); |
|
216 |
|
217 do_check_eq(reporter._providerManager._providers.size, initCount + 1); |
|
218 do_check_true(reporter._storage.hasProvider("DummyConstantProvider")); |
|
219 |
|
220 let mID = reporter._storage.measurementID("DummyConstantProvider", "DummyMeasurement", 1); |
|
221 let values = yield reporter._storage.getMeasurementValues(mID); |
|
222 do_check_true(values.singular.size > 0); |
|
223 } finally { |
|
224 reporter._shutdown(); |
|
225 } |
|
226 }); |
|
227 |
|
228 add_task(function test_collect_daily() { |
|
229 let reporter = yield getReporter("collect_daily"); |
|
230 |
|
231 try { |
|
232 let now = new Date(); |
|
233 let provider = new DummyProvider(); |
|
234 yield reporter._providerManager.registerProvider(provider); |
|
235 yield reporter.collectMeasurements(); |
|
236 |
|
237 do_check_eq(provider.collectConstantCount, 1); |
|
238 do_check_eq(provider.collectDailyCount, 1); |
|
239 |
|
240 yield reporter.collectMeasurements(); |
|
241 do_check_eq(provider.collectConstantCount, 1); |
|
242 do_check_eq(provider.collectDailyCount, 1); |
|
243 |
|
244 yield reporter.collectMeasurements(); |
|
245 do_check_eq(provider.collectDailyCount, 1); // Too soon. |
|
246 |
|
247 reporter._lastDailyDate = now.getTime() - MILLISECONDS_PER_DAY - 1; |
|
248 yield reporter.collectMeasurements(); |
|
249 do_check_eq(provider.collectDailyCount, 2); |
|
250 |
|
251 reporter._lastDailyDate = null; |
|
252 yield reporter.collectMeasurements(); |
|
253 do_check_eq(provider.collectDailyCount, 3); |
|
254 } finally { |
|
255 reporter._shutdown(); |
|
256 } |
|
257 }); |
|
258 |
|
259 add_task(function test_remove_old_lastpayload() { |
|
260 let reporter = getHealthReporter("remove-old-lastpayload"); |
|
261 let lastPayloadPath = reporter._state._lastPayloadPath; |
|
262 let paths = [lastPayloadPath, lastPayloadPath + ".tmp"]; |
|
263 let createFiles = function () { |
|
264 return Task.spawn(function createFiles() { |
|
265 for (let path of paths) { |
|
266 yield OS.File.writeAtomic(path, "delete-me", {tmpPath: path + ".tmp"}); |
|
267 do_check_true(yield OS.File.exists(path)); |
|
268 } |
|
269 }); |
|
270 }; |
|
271 try { |
|
272 do_check_true(!reporter._state.removedOutdatedLastpayload); |
|
273 yield createFiles(); |
|
274 yield reporter.init(); |
|
275 for (let path of paths) { |
|
276 do_check_false(yield OS.File.exists(path)); |
|
277 } |
|
278 yield reporter._state.save(); |
|
279 reporter._shutdown(); |
|
280 |
|
281 let o = yield CommonUtils.readJSON(reporter._state._filename); |
|
282 do_check_true(o.removedOutdatedLastpayload); |
|
283 |
|
284 yield createFiles(); |
|
285 reporter = getHealthReporter("remove-old-lastpayload"); |
|
286 yield reporter.init(); |
|
287 for (let path of paths) { |
|
288 do_check_true(yield OS.File.exists(path)); |
|
289 } |
|
290 } finally { |
|
291 reporter._shutdown(); |
|
292 } |
|
293 }); |
|
294 |
|
295 add_task(function test_json_payload_simple() { |
|
296 let reporter = yield getReporter("json_payload_simple"); |
|
297 |
|
298 let clientID = reporter._state.clientID; |
|
299 do_check_neq(clientID, null); |
|
300 |
|
301 try { |
|
302 let now = new Date(); |
|
303 let payload = yield reporter.getJSONPayload(); |
|
304 do_check_eq(typeof payload, "string"); |
|
305 let original = JSON.parse(payload); |
|
306 |
|
307 do_check_eq(original.version, 2); |
|
308 do_check_eq(original.thisPingDate, reporter._formatDate(now)); |
|
309 do_check_eq(original.clientID, clientID); |
|
310 do_check_eq(original.clientIDVersion, reporter._state.clientIDVersion); |
|
311 do_check_eq(original.clientIDVersion, 1); |
|
312 do_check_eq(Object.keys(original.data.last).length, 0); |
|
313 do_check_eq(Object.keys(original.data.days).length, 0); |
|
314 do_check_false("notInitialized" in original); |
|
315 |
|
316 yield reporter._state.setLastPingDate( |
|
317 new Date(now.getTime() - 24 * 60 * 60 * 1000 - 10)); |
|
318 |
|
319 original = JSON.parse(yield reporter.getJSONPayload()); |
|
320 do_check_eq(original.lastPingDate, reporter._formatDate(reporter.lastPingDate)); |
|
321 do_check_eq(original.clientID, clientID); |
|
322 |
|
323 // This could fail if we cross UTC day boundaries at the exact instance the |
|
324 // test is executed. Let's tempt fate. |
|
325 do_check_eq(original.thisPingDate, reporter._formatDate(now)); |
|
326 |
|
327 payload = yield reporter.getJSONPayload(true); |
|
328 do_check_eq(typeof payload, "object"); |
|
329 } finally { |
|
330 reporter._shutdown(); |
|
331 } |
|
332 }); |
|
333 |
|
334 add_task(function test_json_payload_dummy_provider() { |
|
335 let reporter = yield getReporter("json_payload_dummy_provider"); |
|
336 |
|
337 try { |
|
338 yield reporter._providerManager.registerProvider(new DummyProvider()); |
|
339 yield reporter.collectMeasurements(); |
|
340 let payload = yield reporter.getJSONPayload(); |
|
341 print(payload); |
|
342 let o = JSON.parse(payload); |
|
343 |
|
344 let name = "DummyProvider.DummyMeasurement"; |
|
345 do_check_eq(Object.keys(o.data.last).length, 1); |
|
346 do_check_true(name in o.data.last); |
|
347 do_check_eq(o.data.last[name]._v, 1); |
|
348 } finally { |
|
349 reporter._shutdown(); |
|
350 } |
|
351 }); |
|
352 |
|
353 add_task(function test_collect_and_obtain_json_payload() { |
|
354 let reporter = yield getReporter("collect_and_obtain_json_payload"); |
|
355 |
|
356 try { |
|
357 yield reporter._providerManager.registerProvider(new DummyProvider()); |
|
358 let payload = yield reporter.collectAndObtainJSONPayload(); |
|
359 do_check_eq(typeof payload, "string"); |
|
360 |
|
361 let o = JSON.parse(payload); |
|
362 do_check_true("DummyProvider.DummyMeasurement" in o.data.last); |
|
363 |
|
364 payload = yield reporter.collectAndObtainJSONPayload(true); |
|
365 do_check_eq(typeof payload, "object"); |
|
366 } finally { |
|
367 reporter._shutdown(); |
|
368 } |
|
369 }); |
|
370 |
|
371 // Ensure constant-only providers make their way into the JSON payload. |
|
372 add_task(function test_constant_only_providers_in_json_payload() { |
|
373 const category = "healthreporter-constant-only-in-payload"; |
|
374 |
|
375 let cm = Cc["@mozilla.org/categorymanager;1"] |
|
376 .getService(Ci.nsICategoryManager); |
|
377 cm.addCategoryEntry(category, "DummyProvider", |
|
378 "resource://testing-common/services/metrics/mocks.jsm", |
|
379 false, true); |
|
380 cm.addCategoryEntry(category, "DummyConstantProvider", |
|
381 "resource://testing-common/services/metrics/mocks.jsm", |
|
382 false, true); |
|
383 |
|
384 let reporter = yield getReporter("constant_only_providers_in_json_payload"); |
|
385 try { |
|
386 let initCount = reporter._providerManager.providers.length; |
|
387 yield reporter._providerManager.registerProvidersFromCategoryManager(category); |
|
388 |
|
389 let payload = yield reporter.collectAndObtainJSONPayload(); |
|
390 let o = JSON.parse(payload); |
|
391 do_check_true("DummyProvider.DummyMeasurement" in o.data.last); |
|
392 do_check_true("DummyConstantProvider.DummyMeasurement" in o.data.last); |
|
393 |
|
394 let providers = reporter._providerManager.providers; |
|
395 do_check_eq(providers.length, initCount + 1); |
|
396 |
|
397 // Do it again for good measure. |
|
398 payload = yield reporter.collectAndObtainJSONPayload(); |
|
399 o = JSON.parse(payload); |
|
400 do_check_true("DummyProvider.DummyMeasurement" in o.data.last); |
|
401 do_check_true("DummyConstantProvider.DummyMeasurement" in o.data.last); |
|
402 |
|
403 providers = reporter._providerManager.providers; |
|
404 do_check_eq(providers.length, initCount + 1); |
|
405 |
|
406 // Ensure throwing getJSONPayload is handled properly. |
|
407 Object.defineProperty(reporter, "_getJSONPayload", { |
|
408 value: function () { |
|
409 throw new Error("Silly error."); |
|
410 }, |
|
411 }); |
|
412 |
|
413 let deferred = Promise.defer(); |
|
414 |
|
415 reporter.collectAndObtainJSONPayload().then(do_throw, function onError() { |
|
416 providers = reporter._providerManager.providers; |
|
417 do_check_eq(providers.length, initCount + 1); |
|
418 deferred.resolve(); |
|
419 }); |
|
420 |
|
421 yield deferred.promise; |
|
422 } finally { |
|
423 reporter._shutdown(); |
|
424 } |
|
425 }); |
|
426 |
|
427 add_task(function test_json_payload_multiple_days() { |
|
428 let reporter = yield getReporter("json_payload_multiple_days"); |
|
429 |
|
430 try { |
|
431 let provider = new DummyProvider(); |
|
432 yield reporter._providerManager.registerProvider(provider); |
|
433 |
|
434 let now = new Date(); |
|
435 |
|
436 let m = provider.getMeasurement("DummyMeasurement", 1); |
|
437 for (let i = 0; i < 200; i++) { |
|
438 let date = new Date(now.getTime() - i * MILLISECONDS_PER_DAY); |
|
439 yield m.incrementDailyCounter("daily-counter", date); |
|
440 } |
|
441 |
|
442 // This test could fail if we cross a UTC day boundary when running. So, |
|
443 // we ensure this doesn't occur. |
|
444 Object.defineProperty(reporter, "_now", { |
|
445 value: function () { |
|
446 return now; |
|
447 }, |
|
448 }); |
|
449 |
|
450 let payload = yield reporter.getJSONPayload(); |
|
451 print(payload); |
|
452 let o = JSON.parse(payload); |
|
453 |
|
454 do_check_eq(Object.keys(o.data.days).length, 180); |
|
455 let today = reporter._formatDate(now); |
|
456 do_check_true(today in o.data.days); |
|
457 } finally { |
|
458 reporter._shutdown(); |
|
459 } |
|
460 }); |
|
461 |
|
462 add_task(function test_json_payload_newer_version_overwrites() { |
|
463 let reporter = yield getReporter("json_payload_newer_version_overwrites"); |
|
464 |
|
465 try { |
|
466 let now = new Date(); |
|
467 // Instead of hacking up the internals to ensure consistent order in Map |
|
468 // iteration (which would be difficult), we instead opt to generate a lot |
|
469 // of measurements of different versions and verify their iterable order |
|
470 // is not increasing. |
|
471 let versions = [1, 6, 3, 9, 2, 3, 7, 4, 10, 8]; |
|
472 let protos = []; |
|
473 for (let version of versions) { |
|
474 let m = function () { |
|
475 Metrics.Measurement.call(this); |
|
476 }; |
|
477 m.prototype = { |
|
478 __proto__: DummyMeasurement.prototype, |
|
479 name: "DummyMeasurement", |
|
480 version: version, |
|
481 }; |
|
482 |
|
483 protos.push(m); |
|
484 } |
|
485 |
|
486 let ctor = function () { |
|
487 Metrics.Provider.call(this); |
|
488 }; |
|
489 ctor.prototype = { |
|
490 __proto__: DummyProvider.prototype, |
|
491 |
|
492 name: "MultiMeasurementProvider", |
|
493 measurementTypes: protos, |
|
494 }; |
|
495 |
|
496 let provider = new ctor(); |
|
497 |
|
498 yield reporter._providerManager.registerProvider(provider); |
|
499 |
|
500 let haveUnordered = false; |
|
501 let last = -1; |
|
502 let highestVersion = -1; |
|
503 for (let [key, measurement] of provider.measurements) { |
|
504 yield measurement.setDailyLastNumeric("daily-last-numeric", |
|
505 measurement.version, now); |
|
506 yield measurement.setLastNumeric("last-numeric", |
|
507 measurement.version, now); |
|
508 |
|
509 if (measurement.version > highestVersion) { |
|
510 highestVersion = measurement.version; |
|
511 } |
|
512 |
|
513 if (measurement.version < last) { |
|
514 haveUnordered = true; |
|
515 } |
|
516 |
|
517 last = measurement.version; |
|
518 } |
|
519 |
|
520 // Ensure Map traversal isn't ordered. If this ever fails, then we'll need |
|
521 // to monkeypatch. |
|
522 do_check_true(haveUnordered); |
|
523 |
|
524 let payload = yield reporter.getJSONPayload(); |
|
525 let o = JSON.parse(payload); |
|
526 do_check_true("MultiMeasurementProvider.DummyMeasurement" in o.data.last); |
|
527 do_check_eq(o.data.last["MultiMeasurementProvider.DummyMeasurement"]._v, highestVersion); |
|
528 |
|
529 let day = reporter._formatDate(now); |
|
530 do_check_true(day in o.data.days); |
|
531 do_check_true("MultiMeasurementProvider.DummyMeasurement" in o.data.days[day]); |
|
532 do_check_eq(o.data.days[day]["MultiMeasurementProvider.DummyMeasurement"]._v, highestVersion); |
|
533 |
|
534 } finally { |
|
535 reporter._shutdown(); |
|
536 } |
|
537 }); |
|
538 |
|
539 add_task(function test_idle_daily() { |
|
540 let reporter = yield getReporter("idle_daily"); |
|
541 try { |
|
542 let provider = new DummyProvider(); |
|
543 yield reporter._providerManager.registerProvider(provider); |
|
544 |
|
545 let now = new Date(); |
|
546 let m = provider.getMeasurement("DummyMeasurement", 1); |
|
547 for (let i = 0; i < 200; i++) { |
|
548 let date = new Date(now.getTime() - i * MILLISECONDS_PER_DAY); |
|
549 yield m.incrementDailyCounter("daily-counter", date); |
|
550 } |
|
551 |
|
552 let values = yield m.getValues(); |
|
553 do_check_eq(values.days.size, 200); |
|
554 |
|
555 Services.obs.notifyObservers(null, "idle-daily", null); |
|
556 |
|
557 values = yield m.getValues(); |
|
558 do_check_eq(values.days.size, 180); |
|
559 } finally { |
|
560 reporter._shutdown(); |
|
561 } |
|
562 }); |
|
563 |
|
564 add_task(function test_data_submission_transport_failure() { |
|
565 let reporter = yield getReporter("data_submission_transport_failure"); |
|
566 try { |
|
567 reporter.serverURI = DUMMY_URI; |
|
568 reporter.serverNamespace = "test00"; |
|
569 |
|
570 let deferred = Promise.defer(); |
|
571 let request = new DataSubmissionRequest(deferred, new Date(Date.now + 30000)); |
|
572 reporter.requestDataUpload(request); |
|
573 |
|
574 yield deferred.promise; |
|
575 do_check_eq(request.state, request.SUBMISSION_FAILURE_SOFT); |
|
576 |
|
577 let data = yield getHealthReportProviderValues(reporter, new Date()); |
|
578 do_check_eq(data.firstDocumentUploadAttempt, 1); |
|
579 do_check_eq(data.uploadTransportFailure, 1); |
|
580 do_check_eq(Object.keys(data).length, 3); |
|
581 } finally { |
|
582 reporter._shutdown(); |
|
583 } |
|
584 }); |
|
585 |
|
586 add_task(function test_data_submission_server_failure() { |
|
587 let [reporter, server] = yield getReporterAndServer("data_submission_server_failure"); |
|
588 try { |
|
589 Object.defineProperty(server, "_handleNamespaceSubmitPost", { |
|
590 value: function (ns, id, request, response) { |
|
591 throw HTTP_500; |
|
592 }, |
|
593 writable: true, |
|
594 }); |
|
595 |
|
596 let deferred = Promise.defer(); |
|
597 let now = new Date(); |
|
598 let request = new DataSubmissionRequest(deferred, now); |
|
599 reporter.requestDataUpload(request); |
|
600 yield deferred.promise; |
|
601 do_check_eq(request.state, request.SUBMISSION_FAILURE_HARD); |
|
602 |
|
603 let data = yield getHealthReportProviderValues(reporter, now); |
|
604 do_check_eq(data.firstDocumentUploadAttempt, 1); |
|
605 do_check_eq(data.uploadServerFailure, 1); |
|
606 do_check_eq(Object.keys(data).length, 3); |
|
607 } finally { |
|
608 yield shutdownServer(server); |
|
609 reporter._shutdown(); |
|
610 } |
|
611 }); |
|
612 |
|
613 add_task(function test_data_submission_success() { |
|
614 let [reporter, server] = yield getReporterAndServer("data_submission_success"); |
|
615 try { |
|
616 yield reporter._providerManager.registerProviderFromType(DummyProvider); |
|
617 yield reporter._providerManager.registerProviderFromType(DummyConstantProvider); |
|
618 |
|
619 do_check_eq(reporter.lastPingDate.getTime(), 0); |
|
620 do_check_false(reporter.haveRemoteData()); |
|
621 |
|
622 let deferred = Promise.defer(); |
|
623 |
|
624 let now = new Date(); |
|
625 let request = new DataSubmissionRequest(deferred, now); |
|
626 reporter._state.addRemoteID("foo"); |
|
627 reporter.requestDataUpload(request); |
|
628 yield deferred.promise; |
|
629 do_check_eq(request.state, request.SUBMISSION_SUCCESS); |
|
630 do_check_true(reporter.lastPingDate.getTime() > 0); |
|
631 do_check_true(reporter.haveRemoteData()); |
|
632 for (let remoteID of reporter._state.remoteIDs) { |
|
633 do_check_neq(remoteID, "foo"); |
|
634 } |
|
635 |
|
636 // Ensure data from providers made it to payload. |
|
637 let o = yield reporter.getJSONPayload(true); |
|
638 do_check_true("DummyProvider.DummyMeasurement" in o.data.last); |
|
639 do_check_true("DummyConstantProvider.DummyMeasurement" in o.data.last); |
|
640 |
|
641 let data = yield getHealthReportProviderValues(reporter, now); |
|
642 do_check_eq(data.continuationUploadAttempt, 1); |
|
643 do_check_eq(data.uploadSuccess, 1); |
|
644 do_check_eq(Object.keys(data).length, 3); |
|
645 |
|
646 let d = reporter.lastPingDate; |
|
647 let id = reporter.lastSubmitID; |
|
648 let clientID = reporter._state.clientID; |
|
649 |
|
650 reporter._shutdown(); |
|
651 |
|
652 // Ensure reloading state works. |
|
653 reporter = yield getReporter("data_submission_success"); |
|
654 do_check_eq(reporter.lastSubmitID, id); |
|
655 do_check_eq(reporter.lastPingDate.getTime(), d.getTime()); |
|
656 do_check_eq(reporter._state.clientID, clientID); |
|
657 |
|
658 reporter._shutdown(); |
|
659 } finally { |
|
660 yield shutdownServer(server); |
|
661 } |
|
662 }); |
|
663 |
|
664 add_task(function test_recurring_daily_pings() { |
|
665 let [reporter, server] = yield getReporterAndServer("recurring_daily_pings"); |
|
666 try { |
|
667 reporter._providerManager.registerProvider(new DummyProvider()); |
|
668 |
|
669 let policy = reporter._policy; |
|
670 |
|
671 defineNow(policy, policy._futureDate(-24 * 60 * 68 * 1000)); |
|
672 policy.recordUserAcceptance(); |
|
673 defineNow(policy, policy.nextDataSubmissionDate); |
|
674 let promise = policy.checkStateAndTrigger(); |
|
675 do_check_neq(promise, null); |
|
676 yield promise; |
|
677 |
|
678 let lastID = reporter.lastSubmitID; |
|
679 do_check_neq(lastID, null); |
|
680 do_check_true(server.hasDocument(reporter.serverNamespace, lastID)); |
|
681 |
|
682 // Skip forward to next scheduled submission time. |
|
683 defineNow(policy, policy.nextDataSubmissionDate); |
|
684 promise = policy.checkStateAndTrigger(); |
|
685 do_check_neq(promise, null); |
|
686 yield promise; |
|
687 do_check_neq(reporter.lastSubmitID, lastID); |
|
688 do_check_true(server.hasDocument(reporter.serverNamespace, reporter.lastSubmitID)); |
|
689 do_check_false(server.hasDocument(reporter.serverNamespace, lastID)); |
|
690 |
|
691 // now() on the health reporter instance wasn't munged. So, we should see |
|
692 // both requests attributed to the same day. |
|
693 let data = yield getHealthReportProviderValues(reporter, new Date()); |
|
694 do_check_eq(data.firstDocumentUploadAttempt, 1); |
|
695 do_check_eq(data.continuationUploadAttempt, 1); |
|
696 do_check_eq(data.uploadSuccess, 2); |
|
697 do_check_eq(Object.keys(data).length, 4); |
|
698 } finally { |
|
699 reporter._shutdown(); |
|
700 yield shutdownServer(server); |
|
701 } |
|
702 }); |
|
703 |
|
704 add_task(function test_request_remote_data_deletion() { |
|
705 let [reporter, server] = yield getReporterAndServer("request_remote_data_deletion"); |
|
706 |
|
707 try { |
|
708 let policy = reporter._policy; |
|
709 defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000)); |
|
710 policy.recordUserAcceptance(); |
|
711 defineNow(policy, policy.nextDataSubmissionDate); |
|
712 yield policy.checkStateAndTrigger(); |
|
713 let id = reporter.lastSubmitID; |
|
714 do_check_neq(id, null); |
|
715 do_check_true(server.hasDocument(reporter.serverNamespace, id)); |
|
716 |
|
717 let clientID = reporter._state.clientID; |
|
718 do_check_neq(clientID, null); |
|
719 |
|
720 defineNow(policy, policy._futureDate(10 * 1000)); |
|
721 |
|
722 let promise = reporter.requestDeleteRemoteData(); |
|
723 do_check_neq(promise, null); |
|
724 yield promise; |
|
725 do_check_null(reporter.lastSubmitID); |
|
726 do_check_false(reporter.haveRemoteData()); |
|
727 do_check_false(server.hasDocument(reporter.serverNamespace, id)); |
|
728 |
|
729 // Client ID should be updated. |
|
730 do_check_neq(reporter._state.clientID, null); |
|
731 do_check_neq(reporter._state.clientID, clientID); |
|
732 do_check_eq(reporter._state.clientIDVersion, 1); |
|
733 |
|
734 // And it should be persisted to disk. |
|
735 let o = yield CommonUtils.readJSON(reporter._state._filename); |
|
736 do_check_eq(o.clientID, reporter._state.clientID); |
|
737 do_check_eq(o.clientIDVersion, 1); |
|
738 } finally { |
|
739 reporter._shutdown(); |
|
740 yield shutdownServer(server); |
|
741 } |
|
742 }); |
|
743 |
|
744 add_task(function test_multiple_simultaneous_uploads() { |
|
745 let [reporter, server] = yield getReporterAndServer("multiple_simultaneous_uploads"); |
|
746 |
|
747 try { |
|
748 let d1 = Promise.defer(); |
|
749 let d2 = Promise.defer(); |
|
750 let t1 = new Date(Date.now() - 1000); |
|
751 let t2 = new Date(t1.getTime() + 500); |
|
752 let r1 = new DataSubmissionRequest(d1, t1); |
|
753 let r2 = new DataSubmissionRequest(d2, t2); |
|
754 |
|
755 let getPayloadDeferred = Promise.defer(); |
|
756 |
|
757 Object.defineProperty(reporter, "getJSONPayload", { |
|
758 configurable: true, |
|
759 value: () => { |
|
760 getPayloadDeferred.resolve(); |
|
761 delete reporter["getJSONPayload"]; |
|
762 return reporter.getJSONPayload(); |
|
763 }, |
|
764 }); |
|
765 |
|
766 let p1 = reporter.requestDataUpload(r1); |
|
767 yield getPayloadDeferred.promise; |
|
768 do_check_true(reporter._uploadInProgress); |
|
769 let p2 = reporter.requestDataUpload(r2); |
|
770 |
|
771 yield p1; |
|
772 yield p2; |
|
773 |
|
774 do_check_eq(r1.state, r1.SUBMISSION_SUCCESS); |
|
775 do_check_eq(r2.state, r2.UPLOAD_IN_PROGRESS); |
|
776 |
|
777 // They should both be resolved already. |
|
778 yield d1; |
|
779 yield d2; |
|
780 |
|
781 let data = yield getHealthReportProviderValues(reporter, t1); |
|
782 do_check_eq(data.firstDocumentUploadAttempt, 1); |
|
783 do_check_false("continuationUploadAttempt" in data); |
|
784 do_check_eq(data.uploadSuccess, 1); |
|
785 do_check_eq(data.uploadAlreadyInProgress, 1); |
|
786 } finally { |
|
787 reporter._shutdown(); |
|
788 yield shutdownServer(server); |
|
789 } |
|
790 }); |
|
791 |
|
792 add_task(function test_policy_accept_reject() { |
|
793 let [reporter, server] = yield getReporterAndServer("policy_accept_reject"); |
|
794 |
|
795 try { |
|
796 let policy = reporter._policy; |
|
797 |
|
798 do_check_false(policy.dataSubmissionPolicyAccepted); |
|
799 do_check_false(reporter.willUploadData); |
|
800 |
|
801 policy.recordUserAcceptance(); |
|
802 do_check_true(policy.dataSubmissionPolicyAccepted); |
|
803 do_check_true(reporter.willUploadData); |
|
804 |
|
805 policy.recordUserRejection(); |
|
806 do_check_false(policy.dataSubmissionPolicyAccepted); |
|
807 do_check_false(reporter.willUploadData); |
|
808 } finally { |
|
809 reporter._shutdown(); |
|
810 yield shutdownServer(server); |
|
811 } |
|
812 }); |
|
813 |
|
814 add_task(function test_error_message_scrubbing() { |
|
815 let reporter = yield getReporter("error_message_scrubbing"); |
|
816 |
|
817 try { |
|
818 let profile = Services.dirsvc.get("ProfD", Ci.nsIFile).path; |
|
819 reporter._recordError("Foo " + profile); |
|
820 |
|
821 do_check_eq(reporter._errors.length, 1); |
|
822 do_check_eq(reporter._errors[0], "Foo <ProfilePath>"); |
|
823 |
|
824 reporter._errors = []; |
|
825 |
|
826 let appdata = Services.dirsvc.get("UAppData", Ci.nsIFile); |
|
827 let uri = Services.io.newFileURI(appdata); |
|
828 |
|
829 reporter._recordError("Foo " + uri.spec); |
|
830 do_check_eq(reporter._errors[0], "Foo <AppDataURI>"); |
|
831 } finally { |
|
832 reporter._shutdown(); |
|
833 } |
|
834 }); |
|
835 |
|
836 add_task(function test_basic_appinfo() { |
|
837 function verify(d) { |
|
838 do_check_eq(d["_v"], 1); |
|
839 do_check_eq(d._v, 1); |
|
840 do_check_eq(d.vendor, "Mozilla"); |
|
841 do_check_eq(d.name, "xpcshell"); |
|
842 do_check_eq(d.id, "xpcshell@tests.mozilla.org"); |
|
843 do_check_eq(d.version, "1"); |
|
844 do_check_eq(d.appBuildID, "20121107"); |
|
845 do_check_eq(d.platformVersion, "p-ver"); |
|
846 do_check_eq(d.platformBuildID, "20121106"); |
|
847 do_check_eq(d.os, "XPCShell"); |
|
848 do_check_eq(d.xpcomabi, "noarch-spidermonkey"); |
|
849 do_check_true("updateChannel" in d); |
|
850 } |
|
851 let reporter = yield getReporter("basic_appinfo"); |
|
852 try { |
|
853 verify(reporter.obtainAppInfo()); |
|
854 let payload = yield reporter.collectAndObtainJSONPayload(true); |
|
855 do_check_eq(payload["version"], 2); |
|
856 verify(payload["geckoAppInfo"]); |
|
857 } finally { |
|
858 reporter._shutdown(); |
|
859 } |
|
860 }); |
|
861 |
|
862 // Ensure collection occurs if upload is disabled. |
|
863 add_task(function test_collect_when_upload_disabled() { |
|
864 let reporter = getHealthReporter("collect_when_upload_disabled"); |
|
865 reporter._policy.recordHealthReportUploadEnabled(false, "testing-collect"); |
|
866 do_check_false(reporter._policy.healthReportUploadEnabled); |
|
867 |
|
868 let name = "healthreport-testing-collect_when_upload_disabled-healthreport-lastDailyCollection"; |
|
869 let pref = "app.update.lastUpdateTime." + name; |
|
870 do_check_false(Services.prefs.prefHasUserValue(pref)); |
|
871 |
|
872 try { |
|
873 yield reporter.init(); |
|
874 do_check_true(Services.prefs.prefHasUserValue(pref)); |
|
875 |
|
876 // We would ideally ensure the timer fires and does the right thing. |
|
877 // However, testing the update timer manager is quite involved. |
|
878 } finally { |
|
879 reporter._shutdown(); |
|
880 } |
|
881 }); |
|
882 |
|
883 add_task(function test_failure_if_not_initialized() { |
|
884 let reporter = yield getReporter("failure_if_not_initialized"); |
|
885 reporter._shutdown(); |
|
886 |
|
887 let error = false; |
|
888 try { |
|
889 yield reporter.requestDataUpload(); |
|
890 } catch (ex) { |
|
891 error = true; |
|
892 do_check_true(ex.message.contains("Not initialized.")); |
|
893 } finally { |
|
894 do_check_true(error); |
|
895 error = false; |
|
896 } |
|
897 |
|
898 try { |
|
899 yield reporter.collectMeasurements(); |
|
900 } catch (ex) { |
|
901 error = true; |
|
902 do_check_true(ex.message.contains("Not initialized.")); |
|
903 } finally { |
|
904 do_check_true(error); |
|
905 error = false; |
|
906 } |
|
907 |
|
908 // getJSONPayload always works (to facilitate error upload). |
|
909 yield reporter.getJSONPayload(); |
|
910 }); |
|
911 |
|
912 add_task(function test_upload_on_init_failure() { |
|
913 let server = new BagheeraServer(); |
|
914 server.start(); |
|
915 let reporter = yield getHealthReporter("upload_on_init_failure", server.serverURI, true); |
|
916 server.createNamespace(reporter.serverNamespace); |
|
917 |
|
918 reporter.onInitializeProviderManagerFinished = function () { |
|
919 throw new Error("Fake error during provider manager initialization."); |
|
920 }; |
|
921 |
|
922 let deferred = Promise.defer(); |
|
923 |
|
924 let oldOnResult = reporter._onBagheeraResult; |
|
925 Object.defineProperty(reporter, "_onBagheeraResult", { |
|
926 value: function (request, isDelete, date, result) { |
|
927 do_check_false(isDelete); |
|
928 do_check_true(result.transportSuccess); |
|
929 do_check_true(result.serverSuccess); |
|
930 |
|
931 oldOnResult.call(reporter, request, isDelete, new Date(), result); |
|
932 deferred.resolve(); |
|
933 }, |
|
934 }); |
|
935 |
|
936 reporter._policy.recordUserAcceptance(); |
|
937 let error = false; |
|
938 try { |
|
939 yield reporter.init(); |
|
940 } catch (ex) { |
|
941 error = true; |
|
942 } finally { |
|
943 do_check_true(error); |
|
944 } |
|
945 |
|
946 // At this point the emergency upload should have been initiated. We |
|
947 // wait for our monkeypatched response handler to signal request |
|
948 // completion. |
|
949 yield deferred.promise; |
|
950 |
|
951 do_check_true(server.hasDocument(reporter.serverNamespace, reporter.lastSubmitID)); |
|
952 let doc = server.getDocument(reporter.serverNamespace, reporter.lastSubmitID); |
|
953 do_check_true("notInitialized" in doc); |
|
954 do_check_eq(doc.notInitialized, 1); |
|
955 do_check_true("errors" in doc); |
|
956 do_check_eq(doc.errors.length, 1); |
|
957 do_check_true(doc.errors[0].contains("Fake error during provider manager initialization")); |
|
958 |
|
959 reporter._shutdown(); |
|
960 yield shutdownServer(server); |
|
961 }); |
|
962 |
|
963 add_task(function test_state_prefs_conversion_simple() { |
|
964 let reporter = getHealthReporter("state_prefs_conversion"); |
|
965 let prefs = reporter._prefs; |
|
966 |
|
967 let lastSubmit = new Date(); |
|
968 prefs.set("lastSubmitID", "lastID"); |
|
969 CommonUtils.setDatePref(prefs, "lastPingTime", lastSubmit); |
|
970 |
|
971 try { |
|
972 yield reporter.init(); |
|
973 |
|
974 do_check_eq(reporter._state.lastSubmitID, "lastID"); |
|
975 do_check_eq(reporter._state.remoteIDs.length, 1); |
|
976 do_check_eq(reporter._state.lastPingDate.getTime(), lastSubmit.getTime()); |
|
977 do_check_eq(reporter._state.lastPingDate.getTime(), reporter.lastPingDate.getTime()); |
|
978 do_check_eq(reporter._state.lastSubmitID, reporter.lastSubmitID); |
|
979 do_check_true(reporter.haveRemoteData()); |
|
980 |
|
981 // User set preferences should have been wiped out. |
|
982 do_check_false(prefs.isSet("lastSubmitID")); |
|
983 do_check_false(prefs.isSet("lastPingTime")); |
|
984 } finally { |
|
985 reporter._shutdown(); |
|
986 } |
|
987 }); |
|
988 |
|
989 // If the saved JSON file does not contain an object, we should reset |
|
990 // automatically. |
|
991 add_task(function test_state_no_json_object() { |
|
992 let reporter = getHealthReporter("state_shared"); |
|
993 yield CommonUtils.writeJSON("hello", reporter._state._filename); |
|
994 |
|
995 try { |
|
996 yield reporter.init(); |
|
997 |
|
998 do_check_eq(reporter.lastPingDate.getTime(), 0); |
|
999 do_check_null(reporter.lastSubmitID); |
|
1000 |
|
1001 let o = yield CommonUtils.readJSON(reporter._state._filename); |
|
1002 do_check_eq(typeof(o), "object"); |
|
1003 do_check_eq(o.v, 1); |
|
1004 do_check_eq(o.lastPingTime, 0); |
|
1005 do_check_eq(o.remoteIDs.length, 0); |
|
1006 } finally { |
|
1007 reporter._shutdown(); |
|
1008 } |
|
1009 }); |
|
1010 |
|
1011 // If we encounter a future version, we reset state to the current version. |
|
1012 add_task(function test_state_future_version() { |
|
1013 let reporter = getHealthReporter("state_shared"); |
|
1014 yield CommonUtils.writeJSON({v: 2, remoteIDs: ["foo"], lastPingTime: 2412}, |
|
1015 reporter._state._filename); |
|
1016 try { |
|
1017 yield reporter.init(); |
|
1018 |
|
1019 do_check_eq(reporter.lastPingDate.getTime(), 0); |
|
1020 do_check_null(reporter.lastSubmitID); |
|
1021 |
|
1022 // While the object is updated, we don't save the file. |
|
1023 let o = yield CommonUtils.readJSON(reporter._state._filename); |
|
1024 do_check_eq(o.v, 2); |
|
1025 do_check_eq(o.lastPingTime, 2412); |
|
1026 do_check_eq(o.remoteIDs.length, 1); |
|
1027 } finally { |
|
1028 reporter._shutdown(); |
|
1029 } |
|
1030 }); |
|
1031 |
|
1032 // Test recovery if the state file contains invalid JSON. |
|
1033 add_task(function test_state_invalid_json() { |
|
1034 let reporter = getHealthReporter("state_shared"); |
|
1035 |
|
1036 let encoder = new TextEncoder(); |
|
1037 let arr = encoder.encode("{foo: bad value, 'bad': as2,}"); |
|
1038 let path = reporter._state._filename; |
|
1039 yield OS.File.writeAtomic(path, arr, {tmpPath: path + ".tmp"}); |
|
1040 |
|
1041 try { |
|
1042 yield reporter.init(); |
|
1043 |
|
1044 do_check_eq(reporter.lastPingDate.getTime(), 0); |
|
1045 do_check_null(reporter.lastSubmitID); |
|
1046 } finally { |
|
1047 reporter._shutdown(); |
|
1048 } |
|
1049 }); |
|
1050 |
|
1051 add_task(function test_state_multiple_remote_ids() { |
|
1052 let [reporter, server] = yield getReporterAndServer("state_multiple_remote_ids"); |
|
1053 let documents = [ |
|
1054 [reporter.serverNamespace, "one", "{v:1}"], |
|
1055 [reporter.serverNamespace, "two", "{v:2}"], |
|
1056 ]; |
|
1057 let now = new Date(Date.now() - 5000); |
|
1058 |
|
1059 try { |
|
1060 for (let [ns, id, payload] of documents) { |
|
1061 server.setDocument(ns, id, payload); |
|
1062 do_check_true(server.hasDocument(ns, id)); |
|
1063 yield reporter._state.addRemoteID(id); |
|
1064 do_check_eq(reporter._state.remoteIDs.indexOf(id), reporter._state.remoteIDs.length - 1); |
|
1065 } |
|
1066 yield reporter._state.setLastPingDate(now); |
|
1067 do_check_eq(reporter._state.remoteIDs.length, 2); |
|
1068 do_check_eq(reporter.lastSubmitID, documents[0][1]); |
|
1069 |
|
1070 let deferred = Promise.defer(); |
|
1071 let request = new DataSubmissionRequest(deferred, now); |
|
1072 reporter.requestDataUpload(request); |
|
1073 yield deferred.promise; |
|
1074 |
|
1075 do_check_eq(reporter._state.remoteIDs.length, 1); |
|
1076 for (let [,id,] of documents) { |
|
1077 do_check_eq(reporter._state.remoteIDs.indexOf(id), -1); |
|
1078 do_check_false(server.hasDocument(reporter.serverNamespace, id)); |
|
1079 } |
|
1080 do_check_true(reporter.lastPingDate.getTime() > now.getTime()); |
|
1081 |
|
1082 let o = yield CommonUtils.readJSON(reporter._state._filename); |
|
1083 do_check_eq(o.remoteIDs.length, 1); |
|
1084 do_check_eq(o.remoteIDs[0], reporter._state.remoteIDs[0]); |
|
1085 do_check_eq(o.lastPingTime, reporter.lastPingDate.getTime()); |
|
1086 } finally { |
|
1087 yield shutdownServer(server); |
|
1088 reporter._shutdown(); |
|
1089 } |
|
1090 }); |
|
1091 |
|
1092 // If we have a state file then downgrade to prefs, the prefs should be |
|
1093 // reimported and should supplement existing state. |
|
1094 add_task(function test_state_downgrade_upgrade() { |
|
1095 let reporter = getHealthReporter("state_shared"); |
|
1096 |
|
1097 let now = new Date(); |
|
1098 |
|
1099 yield CommonUtils.writeJSON({v: 1, remoteIDs: ["id1", "id2"], lastPingTime: now.getTime()}, |
|
1100 reporter._state._filename); |
|
1101 |
|
1102 let prefs = reporter._prefs; |
|
1103 prefs.set("lastSubmitID", "prefID"); |
|
1104 prefs.set("lastPingTime", "" + (now.getTime() + 1000)); |
|
1105 |
|
1106 try { |
|
1107 yield reporter.init(); |
|
1108 |
|
1109 do_check_eq(reporter.lastSubmitID, "id1"); |
|
1110 do_check_eq(reporter._state.remoteIDs.length, 3); |
|
1111 do_check_eq(reporter._state.remoteIDs[2], "prefID"); |
|
1112 do_check_eq(reporter.lastPingDate.getTime(), now.getTime() + 1000); |
|
1113 do_check_false(prefs.isSet("lastSubmitID")); |
|
1114 do_check_false(prefs.isSet("lastPingTime")); |
|
1115 |
|
1116 let o = yield CommonUtils.readJSON(reporter._state._filename); |
|
1117 do_check_eq(o.remoteIDs.length, 3); |
|
1118 do_check_eq(o.lastPingTime, now.getTime() + 1000); |
|
1119 } finally { |
|
1120 reporter._shutdown(); |
|
1121 } |
|
1122 }); |
|
1123 |
|
1124 // Missing client ID in state should be created on state load. |
|
1125 add_task(function* test_state_create_client_id() { |
|
1126 let reporter = getHealthReporter("state_create_client_id"); |
|
1127 |
|
1128 yield CommonUtils.writeJSON({ |
|
1129 v: 1, |
|
1130 remoteIDs: ["id1", "id2"], |
|
1131 lastPingTime: Date.now(), |
|
1132 removeOutdatedLastPayload: true, |
|
1133 }, reporter._state._filename); |
|
1134 |
|
1135 try { |
|
1136 yield reporter.init(); |
|
1137 |
|
1138 do_check_eq(reporter.lastSubmitID, "id1"); |
|
1139 do_check_neq(reporter._state.clientID, null); |
|
1140 do_check_eq(reporter._state.clientID.length, 36); |
|
1141 do_check_eq(reporter._state.clientIDVersion, 1); |
|
1142 |
|
1143 let clientID = reporter._state.clientID; |
|
1144 |
|
1145 // The client ID should be persisted as soon as it is created. |
|
1146 reporter._shutdown(); |
|
1147 |
|
1148 reporter = getHealthReporter("state_create_client_id"); |
|
1149 yield reporter.init(); |
|
1150 do_check_eq(reporter._state.clientID, clientID); |
|
1151 } finally { |
|
1152 reporter._shutdown(); |
|
1153 } |
|
1154 }); |
|
1155 |
|
1156 // Invalid stored client ID is reset automatically. |
|
1157 add_task(function* test_empty_client_id() { |
|
1158 let reporter = getHealthReporter("state_empty_client_id"); |
|
1159 |
|
1160 yield CommonUtils.writeJSON({ |
|
1161 v: 1, |
|
1162 clientID: "", |
|
1163 remoteIDs: ["id1", "id2"], |
|
1164 lastPingTime: Date.now(), |
|
1165 removeOutdatedLastPayload: true, |
|
1166 }, reporter._state._filename); |
|
1167 |
|
1168 try { |
|
1169 yield reporter.init(); |
|
1170 |
|
1171 do_check_neq(reporter._state.clientID, null); |
|
1172 do_check_eq(reporter._state.clientID.length, 36); |
|
1173 } finally { |
|
1174 reporter._shutdown(); |
|
1175 } |
|
1176 }); |
|
1177 |
|
1178 add_task(function* test_nonstring_client_id() { |
|
1179 let reporter = getHealthReporter("state_nonstring_client_id"); |
|
1180 |
|
1181 yield CommonUtils.writeJSON({ |
|
1182 v: 1, |
|
1183 clientID: 42, |
|
1184 remoteIDs: ["id1", "id2"], |
|
1185 lastPingTime: Date.now(), |
|
1186 remoteOutdatedLastPayload: true, |
|
1187 }, reporter._state._filename); |
|
1188 |
|
1189 try { |
|
1190 yield reporter.init(); |
|
1191 |
|
1192 do_check_neq(reporter._state.clientID, null); |
|
1193 do_check_eq(reporter._state.clientID.length, 36); |
|
1194 } finally { |
|
1195 reporter._shutdown(); |
|
1196 } |
|
1197 }); |