Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
4 "use strict";
6 const {utils: Cu} = Components;
8 Cu.import("resource://gre/modules/Preferences.jsm");
9 Cu.import("resource://gre/modules/services/datareporting/policy.jsm");
10 Cu.import("resource://testing-common/services/datareporting/mocks.jsm");
11 Cu.import("resource://gre/modules/UpdateChannel.jsm");
13 function getPolicy(name,
14 aCurrentPolicyVersion = 1,
15 aMinimumPolicyVersion = 1,
16 aBranchMinimumVersionOverride) {
17 let branch = "testing.datareporting." + name;
19 // The version prefs should not be removed on reset, so set them in the
20 // default branch.
21 let defaultPolicyPrefs = new Preferences({ branch: branch + ".policy."
22 , defaultBranch: true });
23 defaultPolicyPrefs.set("currentPolicyVersion", aCurrentPolicyVersion);
24 defaultPolicyPrefs.set("minimumPolicyVersion", aMinimumPolicyVersion);
25 let branchOverridePrefName = "minimumPolicyVersion.channel-" + UpdateChannel.get(false);
26 if (aBranchMinimumVersionOverride !== undefined)
27 defaultPolicyPrefs.set(branchOverridePrefName, aBranchMinimumVersionOverride);
28 else
29 defaultPolicyPrefs.reset(branchOverridePrefName);
31 let policyPrefs = new Preferences(branch + ".policy.");
32 let healthReportPrefs = new Preferences(branch + ".healthreport.");
34 let listener = new MockPolicyListener();
35 let policy = new DataReportingPolicy(policyPrefs, healthReportPrefs, listener);
37 return [policy, policyPrefs, healthReportPrefs, listener];
38 }
40 function defineNow(policy, now) {
41 print("Adjusting fake system clock to " + now);
42 Object.defineProperty(policy, "now", {
43 value: function customNow() {
44 return now;
45 },
46 writable: true,
47 });
48 }
50 function run_test() {
51 run_next_test();
52 }
54 add_test(function test_constructor() {
55 let policyPrefs = new Preferences("foo.bar.policy.");
56 let hrPrefs = new Preferences("foo.bar.healthreport.");
57 let listener = {
58 onRequestDataUpload: function() {},
59 onRequestRemoteDelete: function() {},
60 onNotifyDataPolicy: function() {},
61 };
63 let policy = new DataReportingPolicy(policyPrefs, hrPrefs, listener);
64 do_check_true(Date.now() - policy.firstRunDate.getTime() < 1000);
66 let tomorrow = Date.now() + 24 * 60 * 60 * 1000;
67 do_check_true(tomorrow - policy.nextDataSubmissionDate.getTime() < 1000);
69 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_UNNOTIFIED);
71 run_next_test();
72 });
74 add_test(function test_prefs() {
75 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("prefs");
77 let now = new Date();
78 let nowT = now.getTime();
80 policy.firstRunDate = now;
81 do_check_eq(policyPrefs.get("firstRunTime"), nowT);
82 do_check_eq(policy.firstRunDate.getTime(), nowT);
84 policy.dataSubmissionPolicyNotifiedDate= now;
85 do_check_eq(policyPrefs.get("dataSubmissionPolicyNotifiedTime"), nowT);
86 do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), nowT);
88 policy.dataSubmissionPolicyResponseDate = now;
89 do_check_eq(policyPrefs.get("dataSubmissionPolicyResponseTime"), nowT);
90 do_check_eq(policy.dataSubmissionPolicyResponseDate.getTime(), nowT);
92 policy.dataSubmissionPolicyResponseType = "type-1";
93 do_check_eq(policyPrefs.get("dataSubmissionPolicyResponseType"), "type-1");
94 do_check_eq(policy.dataSubmissionPolicyResponseType, "type-1");
96 policy.dataSubmissionEnabled = false;
97 do_check_false(policyPrefs.get("dataSubmissionEnabled", true));
98 do_check_false(policy.dataSubmissionEnabled);
100 policy.dataSubmissionPolicyAccepted = false;
101 do_check_false(policyPrefs.get("dataSubmissionPolicyAccepted", true));
102 do_check_false(policy.dataSubmissionPolicyAccepted);
104 do_check_false(policy.dataSubmissionPolicyBypassAcceptance);
105 policyPrefs.set("dataSubmissionPolicyBypassAcceptance", true);
106 do_check_true(policy.dataSubmissionPolicyBypassAcceptance);
108 policy.lastDataSubmissionRequestedDate = now;
109 do_check_eq(hrPrefs.get("lastDataSubmissionRequestedTime"), nowT);
110 do_check_eq(policy.lastDataSubmissionRequestedDate.getTime(), nowT);
112 policy.lastDataSubmissionSuccessfulDate = now;
113 do_check_eq(hrPrefs.get("lastDataSubmissionSuccessfulTime"), nowT);
114 do_check_eq(policy.lastDataSubmissionSuccessfulDate.getTime(), nowT);
116 policy.lastDataSubmissionFailureDate = now;
117 do_check_eq(hrPrefs.get("lastDataSubmissionFailureTime"), nowT);
118 do_check_eq(policy.lastDataSubmissionFailureDate.getTime(), nowT);
120 policy.nextDataSubmissionDate = now;
121 do_check_eq(hrPrefs.get("nextDataSubmissionTime"), nowT);
122 do_check_eq(policy.nextDataSubmissionDate.getTime(), nowT);
124 policy.currentDaySubmissionFailureCount = 2;
125 do_check_eq(hrPrefs.get("currentDaySubmissionFailureCount", 0), 2);
126 do_check_eq(policy.currentDaySubmissionFailureCount, 2);
128 policy.pendingDeleteRemoteData = true;
129 do_check_true(hrPrefs.get("pendingDeleteRemoteData"));
130 do_check_true(policy.pendingDeleteRemoteData);
132 policy.healthReportUploadEnabled = false;
133 do_check_false(hrPrefs.get("uploadEnabled"));
134 do_check_false(policy.healthReportUploadEnabled);
136 do_check_false(policy.healthReportUploadLocked);
137 hrPrefs.lock("uploadEnabled");
138 do_check_true(policy.healthReportUploadLocked);
139 hrPrefs.unlock("uploadEnabled");
140 do_check_false(policy.healthReportUploadLocked);
142 run_next_test();
143 });
145 add_test(function test_notify_state_prefs() {
146 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notify_state_prefs");
148 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_UNNOTIFIED);
150 policy._dataSubmissionPolicyNotifiedDate = new Date();
151 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_WAIT);
153 policy.dataSubmissionPolicyResponseDate = new Date();
154 policy._dataSubmissionPolicyNotifiedDate = null;
155 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_COMPLETE);
157 run_next_test();
158 });
160 add_task(function test_initial_submission_notification() {
161 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("initial_submission_notification");
163 do_check_eq(listener.notifyUserCount, 0);
165 // Fresh instances should not do anything initially.
166 policy.checkStateAndTrigger();
167 do_check_eq(listener.notifyUserCount, 0);
169 // We still shouldn't notify up to the millisecond before the barrier.
170 defineNow(policy, new Date(policy.firstRunDate.getTime() +
171 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC - 1));
172 policy.checkStateAndTrigger();
173 do_check_eq(listener.notifyUserCount, 0);
174 do_check_null(policy._dataSubmissionPolicyNotifiedDate);
175 do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), 0);
177 // We have crossed the threshold. We should see notification.
178 defineNow(policy, new Date(policy.firstRunDate.getTime() +
179 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC));
180 policy.checkStateAndTrigger();
181 do_check_eq(listener.notifyUserCount, 1);
182 yield listener.lastNotifyRequest.onUserNotifyComplete();
183 do_check_true(policy._dataSubmissionPolicyNotifiedDate instanceof Date);
184 do_check_true(policy.dataSubmissionPolicyNotifiedDate.getTime() > 0);
185 do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(),
186 policy._dataSubmissionPolicyNotifiedDate.getTime());
187 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_WAIT);
188 });
190 add_test(function test_bypass_acceptance() {
191 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("bypass_acceptance");
193 policyPrefs.set("dataSubmissionPolicyBypassAcceptance", true);
194 do_check_false(policy.dataSubmissionPolicyAccepted);
195 do_check_true(policy.dataSubmissionPolicyBypassAcceptance);
196 defineNow(policy, new Date(policy.nextDataSubmissionDate.getTime()));
197 policy.checkStateAndTrigger();
198 do_check_eq(listener.requestDataUploadCount, 1);
200 run_next_test();
201 });
203 add_task(function test_notification_implicit_acceptance() {
204 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_implicit_acceptance");
206 let now = new Date(policy.nextDataSubmissionDate.getTime() -
207 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
208 defineNow(policy, now);
209 policy.checkStateAndTrigger();
210 do_check_eq(listener.notifyUserCount, 1);
211 yield listener.lastNotifyRequest.onUserNotifyComplete();
212 do_check_eq(policy.dataSubmissionPolicyResponseType, "none-recorded");
214 do_check_true(5000 < policy.IMPLICIT_ACCEPTANCE_INTERVAL_MSEC);
215 defineNow(policy, new Date(now.getTime() + 5000));
216 policy.checkStateAndTrigger();
217 do_check_eq(listener.notifyUserCount, 1);
218 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_WAIT);
219 do_check_eq(policy.dataSubmissionPolicyResponseDate.getTime(), 0);
220 do_check_eq(policy.dataSubmissionPolicyResponseType, "none-recorded");
222 defineNow(policy, new Date(now.getTime() + policy.IMPLICIT_ACCEPTANCE_INTERVAL_MSEC + 1));
223 policy.checkStateAndTrigger();
224 do_check_eq(listener.notifyUserCount, 1);
225 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_COMPLETE);
226 do_check_eq(policy.dataSubmissionPolicyResponseDate.getTime(), policy.now().getTime());
227 do_check_eq(policy.dataSubmissionPolicyResponseType, "accepted-implicit-time-elapsed");
228 });
230 add_task(function test_notification_rejected() {
231 // User notification failed. We should not record it as being presented.
232 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_failed");
234 let now = new Date(policy.nextDataSubmissionDate.getTime() -
235 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
236 defineNow(policy, now);
237 policy.checkStateAndTrigger();
238 do_check_eq(listener.notifyUserCount, 1);
239 yield listener.lastNotifyRequest.onUserNotifyFailed(new Error("testing failed."));
240 do_check_null(policy._dataSubmissionPolicyNotifiedDate);
241 do_check_eq(policy.dataSubmissionPolicyNotifiedDate.getTime(), 0);
242 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_UNNOTIFIED);
243 });
245 add_task(function test_notification_accepted() {
246 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_accepted");
248 let now = new Date(policy.nextDataSubmissionDate.getTime() -
249 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
250 defineNow(policy, now);
251 policy.checkStateAndTrigger();
252 yield listener.lastNotifyRequest.onUserNotifyComplete();
253 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_WAIT);
254 do_check_false(policy.dataSubmissionPolicyAccepted);
255 listener.lastNotifyRequest.onUserNotifyComplete();
256 listener.lastNotifyRequest.onUserAccept("foo-bar");
257 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_COMPLETE);
258 do_check_eq(policy.dataSubmissionPolicyResponseType, "accepted-foo-bar");
259 do_check_true(policy.dataSubmissionPolicyAccepted);
260 do_check_eq(policy.dataSubmissionPolicyResponseDate.getTime(), now.getTime());
261 });
263 add_task(function test_notification_rejected() {
264 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("notification_rejected");
266 let now = new Date(policy.nextDataSubmissionDate.getTime() -
267 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC + 1);
268 defineNow(policy, now);
269 policy.checkStateAndTrigger();
270 yield listener.lastNotifyRequest.onUserNotifyComplete();
271 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_WAIT);
272 do_check_false(policy.dataSubmissionPolicyAccepted);
273 listener.lastNotifyRequest.onUserReject();
274 do_check_eq(policy.notifyState, policy.STATE_NOTIFY_COMPLETE);
275 do_check_eq(policy.dataSubmissionPolicyResponseType, "rejected-no-reason");
276 do_check_false(policy.dataSubmissionPolicyAccepted);
278 // No requests for submission should occur if user has rejected.
279 defineNow(policy, new Date(policy.nextDataSubmissionDate.getTime() + 10000));
280 policy.checkStateAndTrigger();
281 do_check_eq(listener.requestDataUploadCount, 0);
282 });
284 add_test(function test_submission_kill_switch() {
285 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_kill_switch");
287 policy.firstRunDate = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
288 policy.nextDataSubmissionDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
289 policy.recordUserAcceptance("accept-old-ack");
290 do_check_true(policyPrefs.has("dataSubmissionPolicyAcceptedVersion"));
291 policy.checkStateAndTrigger();
292 do_check_eq(listener.requestDataUploadCount, 1);
294 defineNow(policy,
295 new Date(Date.now() + policy.SUBMISSION_REQUEST_EXPIRE_INTERVAL_MSEC + 100));
296 policy.dataSubmissionEnabled = false;
297 policy.checkStateAndTrigger();
298 do_check_eq(listener.requestDataUploadCount, 1);
300 run_next_test();
301 });
303 add_test(function test_upload_kill_switch() {
304 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("upload_kill_switch");
306 defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
307 policy.recordUserAcceptance();
308 defineNow(policy, policy.nextDataSubmissionDate);
310 // So that we don't trigger deletions, which cause uploads to be delayed.
311 hrPrefs.ignore("uploadEnabled", policy.uploadEnabledObserver);
313 policy.healthReportUploadEnabled = false;
314 policy.checkStateAndTrigger();
315 do_check_eq(listener.requestDataUploadCount, 0);
316 policy.healthReportUploadEnabled = true;
317 policy.checkStateAndTrigger();
318 do_check_eq(listener.requestDataUploadCount, 1);
320 run_next_test();
321 });
323 add_test(function test_data_submission_no_data() {
324 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_no_data");
326 policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
327 policy.dataSubmissionPolicyAccepted = true;
328 let now = new Date(policy.nextDataSubmissionDate.getTime() + 1);
329 defineNow(policy, now);
330 do_check_eq(listener.requestDataUploadCount, 0);
331 policy.checkStateAndTrigger();
332 do_check_eq(listener.requestDataUploadCount, 1);
333 listener.lastDataRequest.onNoDataAvailable();
335 // The next trigger should try again.
336 defineNow(policy, new Date(now.getTime() + 155 * 60 * 1000));
337 policy.checkStateAndTrigger();
338 do_check_eq(listener.requestDataUploadCount, 2);
340 run_next_test();
341 });
343 add_task(function test_data_submission_submit_failure_hard() {
344 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_submit_failure_hard");
346 policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
347 policy.dataSubmissionPolicyAccepted = true;
348 let nextDataSubmissionDate = policy.nextDataSubmissionDate;
349 let now = new Date(policy.nextDataSubmissionDate.getTime() + 1);
350 defineNow(policy, now);
352 policy.checkStateAndTrigger();
353 do_check_eq(listener.requestDataUploadCount, 1);
354 yield listener.lastDataRequest.onSubmissionFailureHard();
355 do_check_eq(listener.lastDataRequest.state,
356 listener.lastDataRequest.SUBMISSION_FAILURE_HARD);
358 let expected = new Date(now.getTime() + 24 * 60 * 60 * 1000);
359 do_check_eq(policy.nextDataSubmissionDate.getTime(), expected.getTime());
361 defineNow(policy, new Date(now.getTime() + 10));
362 policy.checkStateAndTrigger();
363 do_check_eq(listener.requestDataUploadCount, 1);
364 });
366 add_task(function test_data_submission_submit_try_again() {
367 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("data_submission_failure_soft");
369 policy.recordUserAcceptance();
370 let nextDataSubmissionDate = policy.nextDataSubmissionDate;
371 let now = new Date(policy.nextDataSubmissionDate.getTime());
372 defineNow(policy, now);
373 policy.checkStateAndTrigger();
374 yield listener.lastDataRequest.onSubmissionFailureSoft();
375 do_check_eq(policy.nextDataSubmissionDate.getTime(),
376 nextDataSubmissionDate.getTime() + 15 * 60 * 1000);
377 });
379 add_task(function test_submission_daily_scheduling() {
380 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_daily_scheduling");
382 policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
383 policy.dataSubmissionPolicyAccepted = true;
384 let nextDataSubmissionDate = policy.nextDataSubmissionDate;
386 // Skip ahead to next submission date. We should get a submission request.
387 let now = new Date(policy.nextDataSubmissionDate.getTime());
388 defineNow(policy, now);
389 policy.checkStateAndTrigger();
390 do_check_eq(listener.requestDataUploadCount, 1);
391 do_check_eq(policy.lastDataSubmissionRequestedDate.getTime(), now.getTime());
393 let finishedDate = new Date(now.getTime() + 250);
394 defineNow(policy, new Date(finishedDate.getTime() + 50));
395 yield listener.lastDataRequest.onSubmissionSuccess(finishedDate);
396 do_check_eq(policy.lastDataSubmissionSuccessfulDate.getTime(), finishedDate.getTime());
398 // Next scheduled submission should be exactly 1 day after the reported
399 // submission success.
401 let nextScheduled = new Date(finishedDate.getTime() + 24 * 60 * 60 * 1000);
402 do_check_eq(policy.nextDataSubmissionDate.getTime(), nextScheduled.getTime());
404 // Fast forward some arbitrary time. We shouldn't do any work yet.
405 defineNow(policy, new Date(now.getTime() + 40000));
406 policy.checkStateAndTrigger();
407 do_check_eq(listener.requestDataUploadCount, 1);
409 defineNow(policy, nextScheduled);
410 policy.checkStateAndTrigger();
411 do_check_eq(listener.requestDataUploadCount, 2);
412 yield listener.lastDataRequest.onSubmissionSuccess(new Date(nextScheduled.getTime() + 200));
413 do_check_eq(policy.nextDataSubmissionDate.getTime(),
414 new Date(nextScheduled.getTime() + 24 * 60 * 60 * 1000 + 200).getTime());
415 });
417 add_test(function test_submission_far_future_scheduling() {
418 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_far_future_scheduling");
420 let now = new Date(Date.now() - 24 * 60 * 60 * 1000);
421 defineNow(policy, now);
422 policy.recordUserAcceptance();
423 now = new Date();
424 defineNow(policy, now);
426 let nextDate = policy._futureDate(3 * 24 * 60 * 60 * 1000 - 1);
427 policy.nextDataSubmissionDate = nextDate;
428 policy.checkStateAndTrigger();
429 do_check_eq(listener.requestDataUploadCount, 0);
430 do_check_eq(policy.nextDataSubmissionDate.getTime(), nextDate.getTime());
432 policy.nextDataSubmissionDate = new Date(nextDate.getTime() + 1);
433 policy.checkStateAndTrigger();
434 do_check_eq(listener.requestDataUploadCount, 0);
435 do_check_eq(policy.nextDataSubmissionDate.getTime(),
436 policy._futureDate(24 * 60 * 60 * 1000).getTime());
438 run_next_test();
439 });
441 add_task(function test_submission_backoff() {
442 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_backoff");
444 do_check_eq(policy.FAILURE_BACKOFF_INTERVALS.length, 2);
446 policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
447 policy.dataSubmissionPolicyAccepted = true;
449 let now = new Date(policy.nextDataSubmissionDate.getTime());
450 defineNow(policy, now);
451 policy.checkStateAndTrigger();
452 do_check_eq(listener.requestDataUploadCount, 1);
453 do_check_eq(policy.currentDaySubmissionFailureCount, 0);
455 now = new Date(now.getTime() + 5000);
456 defineNow(policy, now);
458 // On first soft failure we should back off by scheduled interval.
459 yield listener.lastDataRequest.onSubmissionFailureSoft();
460 do_check_eq(policy.currentDaySubmissionFailureCount, 1);
461 do_check_eq(policy.nextDataSubmissionDate.getTime(),
462 new Date(now.getTime() + policy.FAILURE_BACKOFF_INTERVALS[0]).getTime());
463 do_check_eq(policy.lastDataSubmissionFailureDate.getTime(), now.getTime());
465 // Should not request submission until scheduled.
466 now = new Date(policy.nextDataSubmissionDate.getTime() - 1);
467 defineNow(policy, now);
468 policy.checkStateAndTrigger();
469 do_check_eq(listener.requestDataUploadCount, 1);
471 // 2nd request for submission.
472 now = new Date(policy.nextDataSubmissionDate.getTime());
473 defineNow(policy, now);
474 policy.checkStateAndTrigger();
475 do_check_eq(listener.requestDataUploadCount, 2);
477 now = new Date(now.getTime() + 5000);
478 defineNow(policy, now);
480 // On second failure we should back off by more.
481 yield listener.lastDataRequest.onSubmissionFailureSoft();
482 do_check_eq(policy.currentDaySubmissionFailureCount, 2);
483 do_check_eq(policy.nextDataSubmissionDate.getTime(),
484 new Date(now.getTime() + policy.FAILURE_BACKOFF_INTERVALS[1]).getTime());
486 now = new Date(policy.nextDataSubmissionDate.getTime());
487 defineNow(policy, now);
488 policy.checkStateAndTrigger();
489 do_check_eq(listener.requestDataUploadCount, 3);
491 now = new Date(now.getTime() + 5000);
492 defineNow(policy, now);
494 // On 3rd failure we should back off by a whole day.
495 yield listener.lastDataRequest.onSubmissionFailureSoft();
496 do_check_eq(policy.currentDaySubmissionFailureCount, 0);
497 do_check_eq(policy.nextDataSubmissionDate.getTime(),
498 new Date(now.getTime() + 24 * 60 * 60 * 1000).getTime());
499 });
501 // Ensure that only one submission request can be active at a time.
502 add_test(function test_submission_expiring() {
503 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("submission_expiring");
505 policy.dataSubmissionPolicyResponseDate = new Date(Date.now() - 24 * 60 * 60 * 1000);
506 policy.dataSubmissionPolicyAccepted = true;
507 let nextDataSubmission = policy.nextDataSubmissionDate;
508 let now = new Date(policy.nextDataSubmissionDate.getTime());
509 defineNow(policy, now);
510 policy.checkStateAndTrigger();
511 do_check_eq(listener.requestDataUploadCount, 1);
512 defineNow(policy, new Date(now.getTime() + 500));
513 policy.checkStateAndTrigger();
514 do_check_eq(listener.requestDataUploadCount, 1);
516 defineNow(policy, new Date(policy.now().getTime() +
517 policy.SUBMISSION_REQUEST_EXPIRE_INTERVAL_MSEC));
519 policy.checkStateAndTrigger();
520 do_check_eq(listener.requestDataUploadCount, 2);
522 run_next_test();
523 });
525 add_task(function test_delete_remote_data() {
526 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data");
528 do_check_false(policy.pendingDeleteRemoteData);
529 let nextSubmissionDate = policy.nextDataSubmissionDate;
531 let now = new Date();
532 defineNow(policy, now);
534 policy.deleteRemoteData();
535 do_check_true(policy.pendingDeleteRemoteData);
536 do_check_neq(nextSubmissionDate.getTime(),
537 policy.nextDataSubmissionDate.getTime());
538 do_check_eq(now.getTime(), policy.nextDataSubmissionDate.getTime());
540 do_check_eq(listener.requestRemoteDeleteCount, 1);
541 do_check_true(listener.lastRemoteDeleteRequest.isDelete);
542 defineNow(policy, policy._futureDate(1000));
544 yield listener.lastRemoteDeleteRequest.onSubmissionSuccess(policy.now());
545 do_check_false(policy.pendingDeleteRemoteData);
546 });
548 // Ensure that deletion requests take priority over regular data submission.
549 add_test(function test_delete_remote_data_priority() {
550 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_priority");
552 let now = new Date();
553 defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
554 policy.recordUserAcceptance();
555 defineNow(policy, new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000));
557 policy.checkStateAndTrigger();
558 do_check_eq(listener.requestDataUploadCount, 1);
559 policy._inProgressSubmissionRequest = null;
561 policy.deleteRemoteData();
562 policy.checkStateAndTrigger();
564 do_check_eq(listener.requestRemoteDeleteCount, 1);
565 do_check_eq(listener.requestDataUploadCount, 1);
567 run_next_test();
568 });
570 add_test(function test_delete_remote_data_backoff() {
571 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_backoff");
573 let now = new Date();
574 defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
575 policy.recordUserAcceptance();
576 defineNow(policy, now);
577 policy.nextDataSubmissionDate = now;
578 policy.deleteRemoteData();
580 policy.checkStateAndTrigger();
581 do_check_eq(listener.requestRemoteDeleteCount, 1);
582 defineNow(policy, policy._futureDate(1000));
583 policy.checkStateAndTrigger();
584 do_check_eq(listener.requestDataUploadCount, 0);
585 do_check_eq(listener.requestRemoteDeleteCount, 1);
587 defineNow(policy, policy._futureDate(500));
588 listener.lastRemoteDeleteRequest.onSubmissionFailureSoft();
589 defineNow(policy, policy._futureDate(50));
591 policy.checkStateAndTrigger();
592 do_check_eq(listener.requestRemoteDeleteCount, 1);
594 defineNow(policy, policy._futureDate(policy.FAILURE_BACKOFF_INTERVALS[0] - 50));
595 policy.checkStateAndTrigger();
596 do_check_eq(listener.requestRemoteDeleteCount, 2);
598 run_next_test();
599 });
601 // If we request delete while an upload is in progress, delete should be
602 // scheduled immediately after upload.
603 add_task(function test_delete_remote_data_in_progress_upload() {
604 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("delete_remote_data_in_progress_upload");
606 let now = new Date();
607 defineNow(policy, policy._futureDate(-24 * 60 * 60 * 1000));
608 policy.recordUserAcceptance();
609 defineNow(policy, policy.nextDataSubmissionDate);
611 policy.checkStateAndTrigger();
612 do_check_eq(listener.requestDataUploadCount, 1);
613 defineNow(policy, policy._futureDate(50 * 1000));
615 // If we request a delete during a pending request, nothing should be done.
616 policy.deleteRemoteData();
617 policy.checkStateAndTrigger();
618 do_check_eq(listener.requestDataUploadCount, 1);
619 do_check_eq(listener.requestRemoteDeleteCount, 0);
621 // Now wait a little bit and finish the request.
622 defineNow(policy, policy._futureDate(10 * 1000));
623 yield listener.lastDataRequest.onSubmissionSuccess(policy._futureDate(1000));
624 defineNow(policy, policy._futureDate(5000));
626 policy.checkStateAndTrigger();
627 do_check_eq(listener.requestDataUploadCount, 1);
628 do_check_eq(listener.requestRemoteDeleteCount, 1);
629 });
631 add_test(function test_polling() {
632 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("polling");
633 let intended = 500;
634 let acceptable = 250; // Because nsITimer doesn't guarantee times.
636 // Ensure checkStateAndTrigger is called at a regular interval.
637 let then = Date.now();
638 print("Starting run: " + then);
639 Object.defineProperty(policy, "POLL_INTERVAL_MSEC", {
640 value: intended,
641 });
642 let count = 0;
644 Object.defineProperty(policy, "checkStateAndTrigger", {
645 value: function fakeCheckStateAndTrigger() {
646 let now = Date.now();
647 let after = now - then;
648 count++;
650 print("Polled at " + now + " after " + after + "ms, intended " + intended);
651 do_check_true(after >= acceptable);
652 DataReportingPolicy.prototype.checkStateAndTrigger.call(policy);
654 if (count >= 2) {
655 policy.stopPolling();
657 do_check_eq(listener.notifyUserCount, 0);
658 do_check_eq(listener.requestDataUploadCount, 0);
660 run_next_test();
661 }
663 // "Specified timer period will be at least the time between when
664 // processing for last firing the callback completes and when the next
665 // firing occurs."
666 //
667 // That means we should set 'then' at the *end* of our handler, not
668 // earlier.
669 then = Date.now();
670 }
671 });
672 policy.startPolling();
673 });
675 // Ensure that implicit acceptance of policy is resolved through polling.
676 //
677 // This is probably covered by other tests. But, it's best to have explicit
678 // coverage from a higher-level.
679 add_test(function test_polling_implicit_acceptance() {
680 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("polling_implicit_acceptance");
682 // Redefine intervals with shorter, test-friendly values.
683 Object.defineProperty(policy, "POLL_INTERVAL_MSEC", {
684 value: 250,
685 });
687 Object.defineProperty(policy, "IMPLICIT_ACCEPTANCE_INTERVAL_MSEC", {
688 value: 700,
689 });
691 let count = 0;
693 // Track JS elapsed time, so we can decide if we've waited for enough ticks.
694 let start;
695 Object.defineProperty(policy, "checkStateAndTrigger", {
696 value: function CheckStateAndTriggerProxy() {
697 count++;
698 let now = Date.now();
699 let delta = now - start;
700 print("checkStateAndTrigger count: " + count + ", now " + now +
701 ", delta " + delta);
703 // Account for some slack.
704 DataReportingPolicy.prototype.checkStateAndTrigger.call(policy);
706 // What should happen on different invocations:
707 //
708 // 1) We are inside the prompt interval so user gets prompted.
709 // 2) still ~300ms away from implicit acceptance
710 // 3) still ~50ms away from implicit acceptance
711 // 4) Implicit acceptance recorded. Data submission requested.
712 // 5) Request still pending. No new submission requested.
713 //
714 // Note that, due to the inaccuracy of timers, 4 might not happen until 5
715 // firings have occurred. Yay. So we watch times, not just counts.
717 do_check_eq(listener.notifyUserCount, 1);
719 if (count == 1) {
720 listener.lastNotifyRequest.onUserNotifyComplete();
721 }
723 if (delta <= (policy.IMPLICIT_ACCEPTANCE_INTERVAL_MSEC + policy.POLL_INTERVAL_MSEC)) {
724 do_check_false(policy.dataSubmissionPolicyAccepted);
725 do_check_eq(listener.requestDataUploadCount, 0);
726 } else if (count > 3) {
727 do_check_true(policy.dataSubmissionPolicyAccepted);
728 do_check_eq(policy.dataSubmissionPolicyResponseType,
729 "accepted-implicit-time-elapsed");
730 do_check_eq(listener.requestDataUploadCount, 1);
731 }
733 if ((count > 4) && policy.dataSubmissionPolicyAccepted) {
734 do_check_eq(listener.requestDataUploadCount, 1);
735 policy.stopPolling();
736 run_next_test();
737 }
738 }
739 });
741 policy.firstRunDate = new Date(Date.now() - 4 * 24 * 60 * 60 * 1000);
742 policy.nextDataSubmissionDate = new Date(Date.now());
743 start = Date.now();
744 policy.startPolling();
745 });
747 add_task(function test_record_health_report_upload_enabled() {
748 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("record_health_report_upload_enabled");
750 // Preconditions.
751 do_check_false(policy.pendingDeleteRemoteData);
752 do_check_true(policy.healthReportUploadEnabled);
753 do_check_eq(listener.requestRemoteDeleteCount, 0);
755 // User intent to disable should immediately result in a pending
756 // delete request.
757 policy.recordHealthReportUploadEnabled(false, "testing 1 2 3");
758 do_check_false(policy.healthReportUploadEnabled);
759 do_check_true(policy.pendingDeleteRemoteData);
760 do_check_eq(listener.requestRemoteDeleteCount, 1);
762 // Fulfilling it should make it go away.
763 yield listener.lastRemoteDeleteRequest.onNoDataAvailable();
764 do_check_false(policy.pendingDeleteRemoteData);
766 // User intent to enable should get us back to default state.
767 policy.recordHealthReportUploadEnabled(true, "testing 1 2 3");
768 do_check_false(policy.pendingDeleteRemoteData);
769 do_check_true(policy.healthReportUploadEnabled);
770 });
772 add_test(function test_pref_change_initiates_deletion() {
773 let [policy, policyPrefs, hrPrefs, listener] = getPolicy("record_health_report_upload_enabled");
775 // Preconditions.
776 do_check_false(policy.pendingDeleteRemoteData);
777 do_check_true(policy.healthReportUploadEnabled);
778 do_check_eq(listener.requestRemoteDeleteCount, 0);
780 // User intent to disable should indirectly result in a pending
781 // delete request, because the policy is watching for the pref
782 // to change.
783 Object.defineProperty(policy, "deleteRemoteData", {
784 value: function deleteRemoteDataProxy() {
785 do_check_false(policy.healthReportUploadEnabled);
786 do_check_false(policy.pendingDeleteRemoteData); // Just called.
788 run_next_test();
789 },
790 });
792 hrPrefs.set("uploadEnabled", false);
793 });
795 add_task(function* test_policy_version() {
796 let policy, policyPrefs, hrPrefs, listener, now, firstRunTime;
797 function createPolicy(shouldBeAccepted = false,
798 currentPolicyVersion = 1, minimumPolicyVersion = 1,
799 branchMinimumVersionOverride) {
800 [policy, policyPrefs, hrPrefs, listener] =
801 getPolicy("policy_version_test", currentPolicyVersion,
802 minimumPolicyVersion, branchMinimumVersionOverride);
803 let firstRun = now === undefined;
804 if (firstRun) {
805 firstRunTime = policy.firstRunDate.getTime();
806 do_check_true(firstRunTime > 0);
807 now = new Date(policy.firstRunDate.getTime() +
808 policy.SUBMISSION_NOTIFY_INTERVAL_MSEC);
809 }
810 else {
811 // The first-run time should not be reset even after policy-version
812 // upgrades.
813 do_check_eq(policy.firstRunDate.getTime(), firstRunTime);
814 }
815 defineNow(policy, now);
816 do_check_eq(policy.dataSubmissionPolicyAccepted, shouldBeAccepted);
817 }
819 function* triggerPolicyCheckAndEnsureNotified(notified = true, accept = true) {
820 policy.checkStateAndTrigger();
821 do_check_eq(listener.notifyUserCount, Number(notified));
822 if (notified) {
823 yield listener.lastNotifyRequest.onUserNotifyComplete();
824 if (accept) {
825 listener.lastNotifyRequest.onUserAccept("because,");
826 do_check_true(policy.dataSubmissionPolicyAccepted);
827 do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"),
828 policyPrefs.get("currentPolicyVersion"));
829 }
830 else {
831 do_check_false(policyPrefs.has("dataSubmissionPolicyAcceptedVersion"));
832 }
833 }
834 }
836 createPolicy();
837 yield triggerPolicyCheckAndEnsureNotified();
839 // We shouldn't be notified again if the current version is still valid;
840 createPolicy(true);
841 yield triggerPolicyCheckAndEnsureNotified(false);
843 // Just increasing the current version isn't enough. The minimum
844 // version must be changed.
845 let currentPolicyVersion = policyPrefs.get("currentPolicyVersion");
846 let minimumPolicyVersion = policyPrefs.get("minimumPolicyVersion");
847 createPolicy(true, ++currentPolicyVersion, minimumPolicyVersion);
848 yield triggerPolicyCheckAndEnsureNotified(false);
849 do_check_true(policy.dataSubmissionPolicyAccepted);
850 do_check_eq(policyPrefs.get("dataSubmissionPolicyAcceptedVersion"),
851 minimumPolicyVersion);
853 // Increase the minimum policy version and check if we're notified.
854 createPolicy(false, currentPolicyVersion, ++minimumPolicyVersion);
855 do_check_false(policyPrefs.has("dataSubmissionPolicyAcceptedVersion"));
856 yield triggerPolicyCheckAndEnsureNotified();
858 // Test increasing the minimum version just on the current channel.
859 createPolicy(true, currentPolicyVersion, minimumPolicyVersion);
860 yield triggerPolicyCheckAndEnsureNotified(false);
861 createPolicy(false, ++currentPolicyVersion, minimumPolicyVersion, minimumPolicyVersion + 1);
862 yield triggerPolicyCheckAndEnsureNotified(true);
863 });