Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / google_now / background_unittest.gtestjs
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // TODO(robliao,vadimt): Determine the granularity of testing to perform.
6
7 /**
8  * Test fixture for background.js.
9  * @constructor
10  * @extends {testing.Test}
11  */
12 function GoogleNowBackgroundUnitTest () {
13   testing.Test.call(this);
14 }
15
16 GoogleNowBackgroundUnitTest.prototype = {
17   __proto__: testing.Test.prototype,
18
19   /** @override */
20   extraLibraries: [
21     'common_test_util.js',
22     'background_test_util.js',
23     'background.js'
24   ]
25 };
26
27 var TEST_NAME = 'GoogleNowBackgroundUnitTest';
28
29 /**
30  * Tasks Conflict Test
31  */
32 TEST_F(TEST_NAME, 'AreTasksConflicting', function() {
33   function testTaskPair(newTaskName, scheduledTaskName, expected) {
34     assertTrue(areTasksConflicting(newTaskName, scheduledTaskName) == expected,
35                '(' + newTaskName + ', ' + scheduledTaskName + ')');
36   }
37
38   testTaskPair(UPDATE_CARDS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
39   testTaskPair(UPDATE_CARDS_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
40   testTaskPair(UPDATE_CARDS_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
41   testTaskPair(UPDATE_CARDS_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
42
43   testTaskPair(DISMISS_CARD_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
44   testTaskPair(DISMISS_CARD_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
45   testTaskPair(DISMISS_CARD_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
46   testTaskPair(DISMISS_CARD_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
47
48   testTaskPair(RETRY_DISMISS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
49   testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true);
50   testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true);
51   testTaskPair(RETRY_DISMISS_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
52
53   testTaskPair(STATE_CHANGED_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
54   testTaskPair(STATE_CHANGED_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
55   testTaskPair(STATE_CHANGED_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
56   testTaskPair(STATE_CHANGED_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
57 });
58
59 /**
60  * Server Request Tests
61  */
62 TEST_F(TEST_NAME, 'AuthServerRequestSuccess', function() {
63   expectServerRequests(this, 200, '{}');
64   var callbackCalled = false;
65   requestFromServer('GET', 'test/target').then(function(request) {
66     callbackCalled = true;
67     assertTrue(request.status === 200);
68     assertTrue(request.responseText === '{}');
69   });
70   assertTrue(callbackCalled);
71 });
72
73 TEST_F(TEST_NAME, 'AuthServerRequestForbidden', function() {
74   this.makeAndRegisterMockApis(['authenticationManager.removeToken']);
75   this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING);
76
77   expectServerRequests(this, 403, '');
78
79   var thenCalled = false;
80   var catchCalled = false;
81   requestFromServer('GET', 'test/target').then(function(request) {
82     thenCalled = true;
83   }).catch(function(request) {
84     // The promise is rejected on HTTP failures.
85     catchCalled = true;
86     assertTrue(request.status === 403);
87   });
88   assertFalse(thenCalled);
89   assertTrue(catchCalled);
90 });
91
92 TEST_F(TEST_NAME, 'AuthServerRequestNoAuth', function() {
93   this.makeAndRegisterMockApis(['authenticationManager.removeToken']);
94   this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING);
95
96   expectServerRequests(this, 401, '');
97
98   var thenCalled = false;
99   var catchCalled = false;
100   requestFromServer('GET', 'test/target').then(function(request) {
101     thenCalled = true;
102   }).catch(function(request) {
103     // The promise is rejected on HTTP failures.
104     catchCalled = true;
105     assertTrue(request.status === 401);
106   });
107   assertFalse(thenCalled);
108   assertTrue(catchCalled);
109 });
110
111 function expectServerRequests(fixture, httpStatus, responseText) {
112   fixture.makeAndRegisterMockApis([
113     'authenticationManager.getAuthToken',
114     'buildServerRequest'
115   ]);
116
117   function XMLHttpRequest() {}
118
119   XMLHttpRequest.prototype = {
120     addEventListener: function(type, listener, wantsUntrusted) {},
121     setRequestHeader: function(header, value) {},
122     send: function() {}
123   }
124
125   fixture.mockApis.expects(once()).authenticationManager_getAuthToken()
126       .will(returnValue(Promise.resolve('token')));
127
128   var mockXMLHttpRequest = mock(XMLHttpRequest);
129   var mockXMLHttpRequestProxy = mockXMLHttpRequest.proxy();
130   fixture.mockApis.expects(once())
131       .buildServerRequest(ANYTHING, ANYTHING, ANYTHING)
132       .will(returnValue(mockXMLHttpRequestProxy));
133
134   mockXMLHttpRequest.expects(once())
135       .setRequestHeader('Authorization', 'Bearer token');
136
137   var loadEndSavedArgs = new SaveMockArguments();
138   mockXMLHttpRequest.expects(once())
139       .addEventListener(
140           loadEndSavedArgs.match(eq('loadend')),
141           loadEndSavedArgs.match(ANYTHING),
142           loadEndSavedArgs.match(eq(false)));
143
144   mockXMLHttpRequestProxy.status = httpStatus;
145   mockXMLHttpRequestProxy.response = responseText;
146   mockXMLHttpRequestProxy.responseText = responseText;
147
148   mockXMLHttpRequest.expects(once()).send()
149       .will(invokeCallback(loadEndSavedArgs, 1, mockXMLHttpRequestProxy));
150 }
151
152 TEST_F(TEST_NAME, 'AuthServerRequestNoToken', function() {
153   this.makeAndRegisterMockApis([
154     'authenticationManager.getAuthToken',
155     'buildServerRequest'
156   ]);
157
158   this.mockApis.expects(once()).authenticationManager_getAuthToken()
159       .will(returnValue(Promise.reject()));
160   this.mockApis.expects(never()).buildServerRequest()
161
162   var thenCalled = false;
163   var catchCalled = false;
164   requestFromServer('GET', 'test/target').then(function(request) {
165     thenCalled = true;
166   }).catch(function() {
167     catchCalled = true;
168   });
169   assertFalse(thenCalled);
170   assertTrue(catchCalled);
171 })
172
173 /**
174  * requestNotificationGroupsFromServer Tests
175  */
176 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerEmpty', function() {
177   this.makeAndRegisterMockGlobals([
178     'shouldShowExplanatoryCard',
179     'recordEvent',
180     'requestFromServer'
181   ]);
182
183   this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
184       .will(returnValue(false));
185
186   this.mockGlobals.expects(once()).recordEvent(
187       GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
188
189   this.mockGlobals.expects(once()).recordEvent(
190       GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
191
192   var requestFromServerArgs = new SaveMockArguments();
193   this.mockGlobals.expects(once()).requestFromServer(
194       requestFromServerArgs.match(eq('GET')),
195       requestFromServerArgs.match(ANYTHING))
196       .will(returnValue(
197           Promise.resolve({status: 200, responseText: "{}"})));
198
199   var thenCalled = false;
200   var catchCalled = false;
201   requestNotificationGroupsFromServer([]).then(function() {
202     thenCalled = true;
203   }).catch(function() {
204     catchCalled = true;
205   });
206   assertTrue(thenCalled);
207   assertFalse(catchCalled);
208
209   var pathAndQuery = requestFromServerArgs.arguments[1];
210   var query = pathAndQuery.split('?')[1];
211   assertTrue(query.search('timeZoneOffsetMs') >= 0);
212   assertTrue(query.search('uiLocale') >= 0);
213   assertFalse(query.search('cardExplanation') >= 0);
214 });
215
216 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerWithGroups', function() {
217   this.makeAndRegisterMockGlobals([
218     'shouldShowExplanatoryCard',
219     'recordEvent',
220     'requestFromServer'
221   ]);
222
223   this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
224       .will(returnValue(false));
225
226   this.mockGlobals.expects(once()).recordEvent(
227       GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
228
229   this.mockGlobals.expects(once()).recordEvent(
230       GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
231
232   var requestFromServerArgs = new SaveMockArguments();
233   this.mockGlobals.expects(once()).requestFromServer(
234       requestFromServerArgs.match(eq('GET')),
235       requestFromServerArgs.match(ANYTHING))
236       .will(returnValue(
237           Promise.resolve({status: 200, responseText: "{}"})));
238
239   var thenCalled = false;
240   var catchCalled = false;
241   requestNotificationGroupsFromServer(['A', 'B', 'C']).then(function() {
242     thenCalled = true;
243   }).catch(function() {
244     catchCalled = true;
245   });
246   assertTrue(thenCalled);
247   assertFalse(catchCalled);
248
249   var pathAndQuery = requestFromServerArgs.arguments[1];
250   var query = pathAndQuery.split('?')[1];
251   assertTrue(query.search('timeZoneOffsetMs') >= 0);
252   assertTrue(query.search('uiLocale') >= 0);
253   assertFalse(query.search('cardExplanation') >= 0);
254   assertTrue(query.search('requestTypes=A') >= 0);
255   assertTrue(query.search('requestTypes=B') >= 0);
256   assertTrue(query.search('requestTypes=C') >= 0);
257 });
258
259 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerExplanatory', function() {
260   this.makeAndRegisterMockGlobals([
261     'shouldShowExplanatoryCard',
262     'recordEvent',
263     'requestFromServer'
264   ]);
265
266   this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
267       .will(returnValue(true));
268
269   this.mockGlobals.expects(once()).recordEvent(
270       GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
271
272   this.mockGlobals.expects(once()).recordEvent(
273       GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
274
275   var requestFromServerArgs = new SaveMockArguments();
276   this.mockGlobals.expects(once()).requestFromServer(
277       requestFromServerArgs.match(eq('GET')),
278       requestFromServerArgs.match(ANYTHING))
279       .will(returnValue(
280           Promise.resolve({status: 200, responseText: "{}"})));
281
282   var thenCalled = false;
283   var catchCalled = false;
284   requestNotificationGroupsFromServer([]).then(function() {
285     thenCalled = true;
286   }).catch(function() {
287     catchCalled = true;
288   });
289   assertTrue(thenCalled);
290   assertFalse(catchCalled);
291
292   var pathAndQuery = requestFromServerArgs.arguments[1];
293   var query = pathAndQuery.split('?')[1];
294   assertTrue(query.search('timeZoneOffsetMs') >= 0);
295   assertTrue(query.search('uiLocale') >= 0);
296   assertTrue(query.search('cardExplanation=true') >= 0);
297 });
298
299 TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerFailure', function() {
300   this.makeAndRegisterMockGlobals([
301     'shouldShowExplanatoryCard',
302     'recordEvent',
303     'requestFromServer'
304   ]);
305
306   this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
307       .will(returnValue(false));
308
309   this.mockGlobals.expects(once()).recordEvent(
310       GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
311
312   this.mockGlobals.expects(never()).recordEvent(
313       GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
314
315   var requestFromServerArgs = new SaveMockArguments();
316   this.mockGlobals.expects(once()).requestFromServer(
317       requestFromServerArgs.match(eq('GET')),
318       requestFromServerArgs.match(ANYTHING))
319       .will(returnValue(
320           Promise.reject({status: 401})));
321
322   var thenCalled = false;
323   var catchCalled = false;
324   requestNotificationGroupsFromServer([]).then(function() {
325     thenCalled = true;
326   }).catch(function() {
327     catchCalled = true;
328   });
329   assertFalse(thenCalled);
330   assertTrue(catchCalled);
331 });
332
333 /**
334  * shouldScheduleRetryFromGroupList Tests
335  */
336 TEST_F(TEST_NAME, 'ShouldScheduleRetryEmptyGroupList', function() {
337   assertTrue(shouldScheduleRetryFromGroupList([]));
338 });
339
340 TEST_F(TEST_NAME, 'ShouldScheduleRetryNorOnlyGroupList', function() {
341   assertFalse(shouldScheduleRetryFromGroupList(['NOR']));
342 });
343
344 TEST_F(TEST_NAME, 'ShouldScheduleRetryNotOnlyGroupList', function() {
345   assertTrue(shouldScheduleRetryFromGroupList(['NOT']));
346 });
347
348 TEST_F(TEST_NAME, 'ShouldScheduleRetryMultipleGroupsList', function() {
349   assertTrue(shouldScheduleRetryFromGroupList(['NOR', 'NOT']));
350 });
351
352 /**
353  * requestAndUpdateOptIn Tests
354  */
355 TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedIn', function() {
356   this.makeAndRegisterMockApis([
357     'chrome.storage.local.set',
358     'requestFromServer'
359   ]);
360
361   this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
362       .will(returnValue(Promise.resolve({
363         status: 200,
364         responseText: '{"value": true}'})));
365
366   this.mockApis.expects(once())
367       .chrome_storage_local_set(eqJSON({googleNowEnabled: true}));
368
369   var thenCalled = false;
370   var catchCalled = false;
371   requestAndUpdateOptedIn().then(function(optedIn) {
372     thenCalled = true;
373     assertTrue(optedIn);
374   }).catch(function() {
375     catchCalled = true;
376   });
377   assertTrue(thenCalled);
378   assertFalse(catchCalled);
379 });
380
381 TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedOut', function() {
382   this.makeAndRegisterMockApis([
383     'chrome.storage.local.set',
384     'requestFromServer'
385   ]);
386
387   this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
388       .will(returnValue(Promise.resolve({
389         status: 200,
390         responseText: '{"value": false}'})));
391
392   this.mockApis.expects(once())
393       .chrome_storage_local_set(eqJSON({googleNowEnabled: false}));
394
395   var thenCalled = false;
396   var catchCalled = false;
397   requestAndUpdateOptedIn().then(function(optedIn) {
398     thenCalled = true;
399     assertFalse(optedIn);
400   }).catch(function() {
401     catchCalled = true;
402   });
403   assertTrue(thenCalled);
404   assertFalse(catchCalled);
405 });
406
407 TEST_F(TEST_NAME, 'RequestAndUpdateOptInFailure', function() {
408   this.makeAndRegisterMockApis([
409     'chrome.storage.local.set',
410     'requestFromServer'
411   ]);
412
413   this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
414       .will(returnValue(Promise.reject({status: 404})));
415
416   this.mockApis.expects(never()).chrome_storage_local_set();
417
418   var thenCalled = false;
419   var catchCalled = false;
420   requestAndUpdateOptedIn().then(function() {
421     thenCalled = true;
422   }).catch(function() {
423     catchCalled = true;
424   });
425   assertFalse(thenCalled);
426   assertTrue(catchCalled);
427 });
428
429 /**
430  * pollOptedInNoImmediateRecheck Tests
431  */
432 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedIn', function() {
433   this.makeAndRegisterMockApis([
434     'requestAndUpdateOptedIn',
435     'instrumented.metricsPrivate.getVariationParams',
436     'optInPollAttempts.start'
437   ]);
438
439   this.mockApis.expects(once()).requestAndUpdateOptedIn()
440       .will(returnValue(Promise.resolve(true)));
441
442   this.mockApis.expects(never())
443       .instrumented_metricsPrivate_getVariationParams();
444
445   this.mockApis.expects(never()).optInPollAttempts_start();
446
447   pollOptedInNoImmediateRecheck();
448 });
449
450 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedOut', function() {
451   this.makeAndRegisterMockApis([
452     'requestAndUpdateOptedIn',
453     'instrumented.metricsPrivate.getVariationParams',
454     'optInPollAttempts.start'
455   ]);
456
457   this.mockApis.expects(once()).requestAndUpdateOptedIn()
458       .will(returnValue(Promise.resolve(false)));
459
460   var getVariationParamsSavedArgs = new SaveMockArguments();
461   this.mockApis.expects(once())
462       .instrumented_metricsPrivate_getVariationParams(
463           getVariationParamsSavedArgs.match(eq('GoogleNow')),
464           getVariationParamsSavedArgs.match(ANYTHING))
465       .will(invokeCallback(getVariationParamsSavedArgs, 1, {}));
466
467   this.mockApis.expects(once())
468       .optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS);
469
470   pollOptedInNoImmediateRecheck();
471 });
472
473 TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckFailure', function() {
474   this.makeAndRegisterMockApis([
475     'requestAndUpdateOptedIn',
476     'instrumented.metricsPrivate.getVariationParams',
477     'optInPollAttempts.start'
478   ]);
479
480   this.mockApis.expects(once()).requestAndUpdateOptedIn()
481       .will(returnValue(Promise.reject()));
482
483   var getVariationParamsSavedArgs = new SaveMockArguments();
484   this.mockApis.expects(once())
485       .instrumented_metricsPrivate_getVariationParams(
486           getVariationParamsSavedArgs.match(eq('GoogleNow')),
487           getVariationParamsSavedArgs.match(ANYTHING))
488       .will(invokeCallback(getVariationParamsSavedArgs, 1, {}));
489
490   this.mockApis.expects(once())
491       .optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS);
492
493   pollOptedInNoImmediateRecheck();
494 });
495
496 /**
497  * getGroupsToRequest Tests
498  */
499 TEST_F(TEST_NAME, 'GetGroupsToRequestNone', function() {
500   this.makeAndRegisterMockApis([
501     'fillFromChromeLocalStorage',
502     'Date.now'
503   ]);
504
505   this.mockApis.expects(once())
506       .fillFromChromeLocalStorage(eqJSON({notificationGroups: {}}))
507       .will(returnValue(Promise.resolve({notificationGroups: {}})));
508
509   this.mockApis.expects(once()).Date_now().will(returnValue(20));
510
511   getGroupsToRequest().then(function(groupsToRequest) {
512     assertTrue(JSON.stringify(groupsToRequest) === '[]');
513   });
514 });
515
516 TEST_F(TEST_NAME, 'GetGroupsToRequestWithGroups', function() {
517   this.makeAndRegisterMockApis([
518     'fillFromChromeLocalStorage',
519     'Date.now'
520   ]);
521
522   this.mockApis.expects(once())
523       .fillFromChromeLocalStorage(eqJSON({notificationGroups: {}}))
524       .will(returnValue(Promise.resolve({notificationGroups: {
525         TIME18: {nextPollTime: 18},
526         TIME19: {nextPollTime: 19},
527         TIME20: {nextPollTime: 20},
528         TIME21: {nextPollTime: 21},
529         TIME22: {nextPollTime: 22},
530         TIMEUNDEF: {}
531       }})));
532
533   this.mockApis.expects(once()).Date_now().will(returnValue(20));
534
535   getGroupsToRequest().then(function(groupsToRequest) {
536     assertTrue(groupsToRequest.length == 3);
537     assertTrue(groupsToRequest.indexOf('TIME18') >= 0);
538     assertTrue(groupsToRequest.indexOf('TIME19') >= 0);
539     assertTrue(groupsToRequest.indexOf('TIME20') >= 0);
540   });
541 });
542
543 /**
544  * combineGroup Tests
545  */
546 TEST_F(TEST_NAME, 'CombineGroup', function() {
547   // Tests combineGroup function. Verifies that both notifications with and
548   // without show time are handled correctly and that cards are correctly
549   // added to existing cards with same ID or start a new combined card.
550
551   // Setup and expectations.
552   var combinedCards = {
553     'EXISTING CARD': [1]
554   };
555
556   var receivedNotificationNoShowTime = {
557     chromeNotificationId: 'EXISTING CARD',
558     trigger: {hideTimeSec: 1}
559   };
560   var receivedNotificationWithShowTime = {
561     chromeNotificationId: 'NEW CARD',
562     trigger: {showTimeSec: 2, hideTimeSec: 3}
563   }
564
565   var storedGroup = {
566     cardsTimestamp: 10000,
567     cards: [
568       receivedNotificationNoShowTime,
569       receivedNotificationWithShowTime
570     ]
571   };
572
573   // Invoking the tested function.
574   combineGroup(combinedCards, storedGroup);
575
576   // Check the output value.
577   var expectedCombinedCards = {
578     'EXISTING CARD': [
579       1,
580       {
581         receivedNotification: receivedNotificationNoShowTime,
582         hideTime: 11000
583       }
584     ],
585     'NEW CARD': [
586       {
587         receivedNotification: receivedNotificationWithShowTime,
588         showTime: 12000,
589         hideTime: 13000
590       }
591     ]
592   };
593
594   assertEquals(
595       JSON.stringify(expectedCombinedCards),
596       JSON.stringify(combinedCards));
597 });
598
599 /**
600  * Mocks global functions and APIs that initialize() depends upon.
601  * @param {Test} fixture Test fixture.
602  */
603 function mockInitializeDependencies(fixture) {
604   fixture.makeAndRegisterMockGlobals([
605     'pollOptedInNoImmediateRecheck',
606     'recordEvent',
607     'removeAllCards',
608     'setBackgroundEnable',
609     'startPollingCards',
610     'stopPollingCards'
611   ]);
612   fixture.makeAndRegisterMockApis([
613     'authenticationManager.isSignedIn',
614     'chrome.storage.local.remove',
615     'fillFromChromeLocalStorage',
616     'instrumented.metricsPrivate.getVariationParams',
617     'instrumented.notifications.getAll',
618     'instrumented.notifications.getPermissionLevel',
619     'instrumented.webstorePrivate.getBrowserLogin',
620     'optInPollAttempts.isRunning',
621     'optInPollAttempts.stop',
622     'tasks.add',
623     'updateCardsAttempts.isRunning',
624     'updateCardsAttempts.stop'
625   ]);
626 }
627
628 /**
629  * Sets up the test to expect the state machine calls and send
630  * the specified state machine state. Currently used to test initialize().
631  * Note that this CAN NOT be used if any of the methods below are called
632  * outside of this context with the same argument matchers.
633  * expects() calls cannot be chained with the same argument matchers.
634  * @param {object} fixture Test fixture.
635  * @param {string} testIdentityToken getAuthToken callback token.
636  * @param {object} testExperimentVariationParams Response of
637  *     metricsPrivate.getVariationParams.
638  * @param {string} testExperimentVariationParams Response of
639  *     notifications.getPermissionLevel.
640  * @param {boolean} testGoogleNowEnabled True if the user is opted in to Google
641  *     Now.
642  */
643 function expectStateMachineCalls(
644     fixture,
645     testIdentityToken,
646     testExperimentVariationParams,
647     testNotificationPermissionLevel,
648     testGoogleNowEnabled) {
649   fixture.mockApis.expects(once()).
650       authenticationManager_isSignedIn().
651       will(returnValue(new Promise(function(resolve) {
652         resolve(!!testIdentityToken);
653       })));
654
655   var getVariationParamsSavedArgs = new SaveMockArguments();
656   fixture.mockApis.expects(once()).
657       instrumented_metricsPrivate_getVariationParams(
658           getVariationParamsSavedArgs.match(ANYTHING),
659           getVariationParamsSavedArgs.match(ANYTHING)).
660       will(invokeCallback(
661           getVariationParamsSavedArgs, 1, testExperimentVariationParams));
662
663   var notificationGetPermissionLevelSavedArgs = new SaveMockArguments();
664   fixture.mockApis.expects(once()).
665       instrumented_notifications_getPermissionLevel(
666           notificationGetPermissionLevelSavedArgs.match(ANYTHING)).
667       will(invokeCallback(
668           notificationGetPermissionLevelSavedArgs,
669           0,
670           testNotificationPermissionLevel))
671
672   expectChromeLocalStorageGet(
673       fixture,
674       {googleNowEnabled: false},
675       {googleNowEnabled: testGoogleNowEnabled});
676
677   var updateCardsAttemptsIsRunningSavedArgs = new SaveMockArguments();
678   fixture.mockApis.expects(once()).
679       updateCardsAttempts_isRunning(
680           updateCardsAttemptsIsRunningSavedArgs.match(ANYTHING)).
681       will(
682           invokeCallback(
683               updateCardsAttemptsIsRunningSavedArgs, 0, undefined));
684
685   var optInPollAttemptsIsRunningSavedArgs = new SaveMockArguments();
686   fixture.mockApis.expects(once()).
687       optInPollAttempts_isRunning(
688           optInPollAttemptsIsRunningSavedArgs.match(ANYTHING)).
689       will(
690           invokeCallback(
691               optInPollAttemptsIsRunningSavedArgs, 0, undefined));
692 }
693
694 /**
695  * Sets up the test to expect the initialization calls that
696  * initialize() invokes.
697  * Note that this CAN NOT be used if any of the methods below are called
698  * outside of this context with the same argument matchers.
699  * expects() calls cannot be chained with the same argument matchers.
700  */
701 function expectInitialization(fixture) {
702   var tasksAddSavedArgs = new SaveMockArguments();
703   fixture.mockApis.expects(once()).
704       tasks_add(
705           tasksAddSavedArgs.match(ANYTHING),
706           tasksAddSavedArgs.match(ANYTHING)).
707       will(invokeCallback(tasksAddSavedArgs, 1, function() {}));
708
709   // The ordering here between stubs and expects is important.
710   // We only care about the EXTENSION_START event. The other events are covered
711   // by the NoCards tests below. Reversing the calls will cause all recordEvent
712   // calls to be unexpected.
713   fixture.mockGlobals.stubs().recordEvent(ANYTHING);
714   fixture.mockGlobals.
715       expects(once()).recordEvent(GoogleNowEvent.EXTENSION_START);
716 }
717
718 TEST_F(TEST_NAME,'Initialize_SignedOut', function() {
719   // Tests the case when getAuthToken fails most likely because the user is
720   // not signed in. In this case, the function should quietly exit after
721   // finding out that getAuthToken fails.
722
723   // Setup and expectations.
724   var testIdentityToken = undefined;
725   var testExperimentVariationParams = {};
726   var testNotificationPermissionLevel = 'denied';
727   var testGoogleNowEnabled = undefined;
728
729   mockInitializeDependencies(this);
730
731   expectInitialization(this);
732
733   expectStateMachineCalls(
734       this,
735       testIdentityToken,
736       testExperimentVariationParams,
737       testNotificationPermissionLevel,
738       testGoogleNowEnabled);
739
740   this.mockGlobals.expects(once()).setBackgroundEnable(false);
741   this.mockGlobals.expects(never()).startPollingCards();
742   this.mockGlobals.expects(once()).stopPollingCards();
743   this.mockGlobals.expects(once()).removeAllCards();
744   this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
745   this.mockApis.expects(once()).optInPollAttempts_stop();
746
747   // Invoking the tested function.
748   initialize();
749 });
750
751 TEST_F(TEST_NAME,'Initialize_NotificationDisabled', function() {
752   // Tests the case when Google Now is disabled in the notifications center.
753
754   // Setup and expectations.
755   var testIdentityToken = 'some identity token';
756   var testExperimentVariationParams = {};
757   var testNotificationPermissionLevel = 'denied';
758   var testGoogleNowEnabled = undefined;
759
760   mockInitializeDependencies(this);
761
762   expectInitialization(this);
763
764   expectStateMachineCalls(
765       this,
766       testIdentityToken,
767       testExperimentVariationParams,
768       testNotificationPermissionLevel,
769       testGoogleNowEnabled);
770
771   this.mockGlobals.expects(once()).setBackgroundEnable(false);
772   this.mockGlobals.expects(never()).startPollingCards();
773   this.mockGlobals.expects(once()).stopPollingCards();
774   this.mockGlobals.expects(once()).removeAllCards();
775   this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
776   this.mockApis.expects(once()).optInPollAttempts_stop();
777
778   // Invoking the tested function.
779   initialize();
780 });
781
782 TEST_F(TEST_NAME, 'Initialize_NoBackground', function() {
783   // Tests when the no background variation is received.
784
785   // Setup and expectations.
786   var testIdentityToken = 'some identity token';
787   var testExperimentVariationParams = {canEnableBackground: 'false'};
788   var testNotificationPermissionLevel = 'granted';
789   var testGoogleNowEnabled = true;
790
791   mockInitializeDependencies(this);
792
793   expectInitialization(this);
794
795   expectStateMachineCalls(
796       this,
797       testIdentityToken,
798       testExperimentVariationParams,
799       testNotificationPermissionLevel,
800       testGoogleNowEnabled);
801
802   this.mockGlobals.expects(once()).setBackgroundEnable(false);
803   this.mockGlobals.expects(once()).startPollingCards();
804   this.mockGlobals.expects(never()).stopPollingCards();
805   this.mockGlobals.expects(never()).removeAllCards();
806   this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
807   this.mockApis.expects(once()).optInPollAttempts_stop();
808
809   // Invoking the tested function.
810   initialize();
811 });
812
813 TEST_F(TEST_NAME, 'Initialize_GoogleNowDisabled', function() {
814   // Tests when the user has Google Now disabled.
815
816   // Setup and expectations.
817   var testIdentityToken = 'some identity token';
818   var testExperimentVariationParams = {};
819   var testNotificationPermissionLevel = 'granted';
820   var testGoogleNowEnabled = false;
821
822   mockInitializeDependencies(this);
823
824   expectInitialization(this);
825
826   expectStateMachineCalls(
827       this,
828       testIdentityToken,
829       testExperimentVariationParams,
830       testNotificationPermissionLevel,
831       testGoogleNowEnabled);
832
833   this.mockGlobals.expects(once()).setBackgroundEnable(false);
834   this.mockGlobals.expects(never()).startPollingCards();
835   this.mockGlobals.expects(once()).stopPollingCards();
836   this.mockGlobals.expects(once()).removeAllCards();
837   this.mockGlobals.expects(once()).pollOptedInNoImmediateRecheck();
838   this.mockApis.expects(never()).optInPollAttempts_stop();
839
840   // Invoking the tested function.
841   initialize();
842 });
843
844 TEST_F(TEST_NAME, 'Initialize_RunGoogleNow', function() {
845   // Tests if Google Now will invoke startPollingCards when all
846   // of the required state is fulfilled.
847
848   // Setup and expectations.
849   var testIdentityToken = 'some identity token';
850   var testExperimentVariationParams = {};
851   var testNotificationPermissionLevel = 'granted';
852   var testGoogleNowEnabled = true;
853
854   mockInitializeDependencies(this);
855
856   expectInitialization(this);
857
858   expectStateMachineCalls(
859       this,
860       testIdentityToken,
861       testExperimentVariationParams,
862       testNotificationPermissionLevel,
863       testGoogleNowEnabled);
864
865   this.mockGlobals.expects(once()).setBackgroundEnable(true);
866   this.mockGlobals.expects(once()).startPollingCards();
867   this.mockGlobals.expects(never()).stopPollingCards();
868   this.mockGlobals.expects(never()).removeAllCards();
869   this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
870   this.mockApis.expects(once()).optInPollAttempts_stop();
871
872   // Invoking the tested function.
873   initialize();
874 });
875
876 /**
877  * No Cards Event Recording Tests
878  */
879 TEST_F(TEST_NAME, 'NoCardsSignedOut', function() {
880   var signedIn = false;
881   var notificationEnabled = false;
882   var googleNowEnabled = false;
883   this.makeAndRegisterMockGlobals([
884       'recordEvent',
885       'removeAllCards',
886       'setBackgroundEnable',
887       'setShouldPollCards',
888       'setShouldPollOptInStatus']);
889
890   this.mockGlobals.stubs().removeAllCards();
891   this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
892   this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
893   this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
894
895   this.mockGlobals.expects(once()).recordEvent(
896       GoogleNowEvent.STOPPED);
897   this.mockGlobals.expects(once()).recordEvent(
898       GoogleNowEvent.SIGNED_OUT);
899   this.mockGlobals.expects(never()).recordEvent(
900       GoogleNowEvent.NOTIFICATION_DISABLED);
901   this.mockGlobals.expects(never()).recordEvent(
902       GoogleNowEvent.GOOGLE_NOW_DISABLED);
903   updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
904 });
905
906 TEST_F(TEST_NAME, 'NoCardsNotificationsDisabled', function() {
907   var signedIn = true;
908   var notificationEnabled = false;
909   var googleNowEnabled = false;
910   this.makeAndRegisterMockGlobals([
911       'recordEvent',
912       'removeAllCards',
913       'setBackgroundEnable',
914       'setShouldPollCards',
915       'setShouldPollOptInStatus']);
916
917   this.mockGlobals.stubs().removeAllCards();
918   this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
919   this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
920   this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
921
922   this.mockGlobals.expects(once()).recordEvent(
923       GoogleNowEvent.STOPPED);
924   this.mockGlobals.expects(never()).recordEvent(
925       GoogleNowEvent.SIGNED_OUT);
926   this.mockGlobals.expects(once()).recordEvent(
927       GoogleNowEvent.NOTIFICATION_DISABLED);
928   this.mockGlobals.expects(never()).recordEvent(
929       GoogleNowEvent.GOOGLE_NOW_DISABLED);
930   updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
931 });
932
933 TEST_F(TEST_NAME, 'NoCardsGoogleNowDisabled', function() {
934   var signedIn = true;
935   var notificationEnabled = true;
936   var googleNowEnabled = false;
937   this.makeAndRegisterMockGlobals([
938       'recordEvent',
939       'removeAllCards',
940       'setBackgroundEnable',
941       'setShouldPollCards',
942       'setShouldPollOptInStatus']);
943
944   this.mockGlobals.stubs().removeAllCards();
945   this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
946   this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
947   this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
948
949   this.mockGlobals.expects(never()).recordEvent(
950       GoogleNowEvent.STOPPED);
951   this.mockGlobals.expects(never()).recordEvent(
952       GoogleNowEvent.SIGNED_OUT);
953   this.mockGlobals.expects(never()).recordEvent(
954       GoogleNowEvent.NOTIFICATION_DISABLED);
955   this.mockGlobals.expects(once()).recordEvent(
956       GoogleNowEvent.GOOGLE_NOW_DISABLED);
957   updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
958 });
959
960 TEST_F(TEST_NAME, 'NoCardsEverythingEnabled', function() {
961   var signedIn = true;
962   var notificationEnabled = true;
963   var googleNowEnabled = true;
964   this.makeAndRegisterMockGlobals([
965       'recordEvent',
966       'removeAllCards',
967       'setBackgroundEnable',
968       'setShouldPollCards',
969       'setShouldPollOptInStatus']);
970
971   this.mockGlobals.stubs().removeAllCards();
972   this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
973   this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
974   this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
975
976   this.mockGlobals.expects(never()).recordEvent(
977       GoogleNowEvent.STOPPED);
978   this.mockGlobals.expects(never()).recordEvent(
979       GoogleNowEvent.SIGNED_OUT);
980   this.mockGlobals.expects(never()).recordEvent(
981       GoogleNowEvent.NOTIFICATION_DISABLED);
982   this.mockGlobals.expects(never()).recordEvent(
983       GoogleNowEvent.GOOGLE_NOW_DISABLED);
984   updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
985 });
986
987 /**
988  * Mocks global functions and APIs that onNotificationClicked() depends upon.
989  * @param {Test} fixture Test fixture.
990  */
991 function mockOnNotificationClickedDependencies(fixture) {
992   fixture.makeAndRegisterMockApis([
993     'chrome.windows.create',
994     'chrome.windows.update',
995     'fillFromChromeLocalStorage',
996     'instrumented.tabs.create']);
997 }
998
999 TEST_F(TEST_NAME, 'OnNotificationClicked_NoData', function() {
1000   // Tests the case when there is no data associated with notification id.
1001   // In this case, the function should do nothing.
1002
1003   // Setup and expectations.
1004   var testNotificationId = 'TEST_ID';
1005   var testNotificationDataRequest = {notificationsData: {}};
1006   var testNotificationData = {notificationsData: {}};
1007
1008   mockOnNotificationClickedDependencies(this);
1009   this.makeMockLocalFunctions(['selector']);
1010
1011   expectChromeLocalStorageGet(
1012       this, testNotificationDataRequest, testNotificationData);
1013
1014   // Invoking the tested function.
1015   onNotificationClicked(
1016       testNotificationId, this.mockLocalFunctions.functions().selector);
1017 });
1018
1019 TEST_F(TEST_NAME, 'OnNotificationClicked_ActionUrlsUndefined', function() {
1020   // Tests the case when the data associated with notification id is
1021   // 'undefined'.
1022   // In this case, the function should do nothing.
1023
1024   // Setup and expectations.
1025   var testActionUrls = undefined;
1026   var testNotificationId = 'TEST_ID';
1027   var testNotificationDataRequest = {notificationsData: {}};
1028   var testNotificationData = {
1029       notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
1030   };
1031
1032   mockOnNotificationClickedDependencies(this);
1033   this.makeMockLocalFunctions(['selector']);
1034
1035   expectChromeLocalStorageGet(
1036       this, testNotificationDataRequest, testNotificationData);
1037
1038   this.mockLocalFunctions.expects(once())
1039       .selector(eqJSON(
1040           testNotificationData.notificationsData[testNotificationId]))
1041       .will(returnValue(undefined));
1042
1043   // Invoking the tested function.
1044   onNotificationClicked(
1045       testNotificationId, this.mockLocalFunctions.functions().selector);
1046 });
1047
1048 TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateSuccess', function() {
1049   // Tests the selected URL is OK and crome.tabs.create suceeds.
1050
1051   // Setup and expectations.
1052   var testActionUrls = {testField: 'TEST VALUE'};
1053   var testNotificationId = 'TEST_ID';
1054   var testNotificationDataRequest = {notificationsData: {}};
1055   var testNotificationData = {
1056       notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
1057   };
1058   var testActionUrl = 'http://testurl.com';
1059   var testCreatedTab = {windowId: 239};
1060
1061   mockOnNotificationClickedDependencies(this);
1062   this.makeMockLocalFunctions(['selector']);
1063
1064   expectChromeLocalStorageGet(
1065       this, testNotificationDataRequest, testNotificationData);
1066   this.mockLocalFunctions.expects(once())
1067       .selector(eqJSON(
1068           testNotificationData.notificationsData[testNotificationId]))
1069       .will(returnValue(testActionUrl));
1070   var chromeTabsCreateSavedArgs = new SaveMockArguments();
1071   this.mockApis.expects(once()).
1072       instrumented_tabs_create(
1073           chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
1074           chromeTabsCreateSavedArgs.match(ANYTHING)).
1075       will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
1076   this.mockApis.expects(once()).chrome_windows_update(
1077       testCreatedTab.windowId,
1078       eqJSON({focused: true}));
1079
1080   // Invoking the tested function.
1081   onNotificationClicked(
1082       testNotificationId, this.mockLocalFunctions.functions().selector);
1083 });
1084
1085 TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateFail', function() {
1086   // Tests the selected URL is OK and crome.tabs.create fails.
1087   // In this case, the function should invoke chrome.windows.create as a
1088   // second attempt.
1089
1090   // Setup and expectations.
1091   var testActionUrls = {testField: 'TEST VALUE'};
1092   var testNotificationId = 'TEST_ID';
1093   var testNotificationDataRequest = {notificationsData: {}};
1094   var testNotificationData = {
1095     notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
1096   };
1097   var testActionUrl = 'http://testurl.com';
1098   var testCreatedTab = undefined; // chrome.tabs.create fails
1099
1100   mockOnNotificationClickedDependencies(this);
1101   this.makeMockLocalFunctions(['selector']);
1102
1103   expectChromeLocalStorageGet(
1104       this, testNotificationDataRequest, testNotificationData);
1105   this.mockLocalFunctions.expects(once())
1106       .selector(eqJSON(
1107           testNotificationData.notificationsData[testNotificationId]))
1108       .will(returnValue(testActionUrl));
1109   var chromeTabsCreateSavedArgs = new SaveMockArguments();
1110   this.mockApis.expects(once()).
1111       instrumented_tabs_create(
1112           chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
1113           chromeTabsCreateSavedArgs.match(ANYTHING)).
1114       will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
1115   this.mockApis.expects(once()).chrome_windows_create(
1116       eqJSON({url: testActionUrl, focused: true}));
1117
1118   // Invoking the tested function.
1119   onNotificationClicked(
1120       testNotificationId, this.mockLocalFunctions.functions().selector);
1121 });
1122
1123 TEST_F(TEST_NAME, 'ShowNotificationGroups', function() {
1124   // Tests showNotificationGroups function. Checks that the function properly
1125   // deletes the card that didn't get an update, updates existing card and
1126   // creates a new card that previously didn't exist.
1127
1128   // Setup and expectations.
1129   var existingNotifications = {
1130     'SHOULD BE DELETED': 'SOMETHING',
1131     'SHOULD BE KEPT': 'SOMETHING'
1132   };
1133
1134   var keptCard = {
1135     chromeNotificationId: 'SHOULD BE KEPT',
1136     trigger: {showTimeSec: 0, hideTimeSec: 0}
1137   };
1138
1139   var keptNotification = {
1140     receivedNotification: keptCard,
1141     showTime: 0,
1142     hideTime: 0
1143   };
1144
1145   var newCard = {
1146     chromeNotificationId: 'NEW CARD',
1147     trigger: {showTimeSec: 0, hideTimeSec: 0}
1148   };
1149
1150   var newNotification = {
1151     receivedNotification: newCard,
1152     showTime: 0,
1153     hideTime: 0
1154   };
1155
1156   var notificationGroups = {
1157     'TEST GROUP 1': {cards: [keptCard], cardsTimestamp: 0},
1158     'TEST GROUP 2': {cards: [newCard], cardsTimestamp: 0}
1159   };
1160
1161   var fakeOnCardShownFunction = 'FAKE ON CARD SHOWN FUNCTION';
1162
1163   var expectedUpdatedNotifications = {
1164     'SHOULD BE KEPT': 'KEPT CARD NOTIFICATION DATA',
1165     'NEW CARD': 'NEW CARD NOTIFICATION DATA'
1166   };
1167
1168   this.makeAndRegisterMockApis([
1169     'cardSet.update',
1170     'chrome.storage.local.set',
1171     'instrumented.notifications.getAll'
1172   ]);
1173   this.makeMockLocalFunctions([
1174     'onSuccess'
1175   ]);
1176
1177   var notificationsGetAllSavedArgs = new SaveMockArguments();
1178   this.mockApis.expects(once()).
1179       instrumented_notifications_getAll(
1180           notificationsGetAllSavedArgs.match(ANYTHING)).
1181       will(invokeCallback(
1182           notificationsGetAllSavedArgs, 0, existingNotifications));
1183
1184   this.mockApis.expects(once()).
1185       cardSet_update(
1186           'SHOULD BE KEPT',
1187           eqJSON([keptNotification]),
1188           eqJSON(notificationGroups),
1189           fakeOnCardShownFunction).
1190       will(returnValue('KEPT CARD NOTIFICATION DATA'));
1191   this.mockApis.expects(once()).
1192       cardSet_update(
1193           'NEW CARD',
1194           eqJSON([newNotification]),
1195           eqJSON(notificationGroups),
1196           fakeOnCardShownFunction).
1197       will(returnValue('NEW CARD NOTIFICATION DATA'));
1198   this.mockApis.expects(once()).
1199       cardSet_update(
1200           'SHOULD BE DELETED',
1201           [],
1202           eqJSON(notificationGroups),
1203           fakeOnCardShownFunction).
1204       will(returnValue(undefined));
1205
1206   this.mockApis.expects(once()).
1207       chrome_storage_local_set(
1208           eqJSON({notificationsData: expectedUpdatedNotifications}));
1209
1210   this.mockLocalFunctions.expects(once()).
1211       onSuccess(undefined);
1212
1213   // Invoking the tested function.
1214   showNotificationGroups(notificationGroups, fakeOnCardShownFunction)
1215       .then(this.mockLocalFunctions.functions().onSuccess);
1216 });
1217
1218 TEST_F(TEST_NAME, 'ProcessServerResponse', function() {
1219   // Tests processServerResponse function.
1220
1221   // Setup and expectations.
1222   Date.now = function() { return 3000000; };
1223
1224   // GROUP1 was requested and contains cards c4 and c5. For c5, there is a
1225   // non-expired dismissal, so it will be ignored.
1226   // GROUP2 was not requested, but is contained in server response to
1227   // indicate that the group still exists. Stored group GROUP2 won't change.
1228   // GROUP3 is stored, but is not present in server's response, which means
1229   // it doesn't exist anymore. This group will be deleted.
1230   // GROUP4 doesn't contain cards, but it was requested. This is treated as
1231   // if it had an empty array of cards. Cards in the stored group will be
1232   // replaced with an empty array.
1233   // GROUP5 doesn't have next poll time, and it will be stored without next
1234   // poll time.
1235   var serverResponse = {
1236     groups: {
1237       GROUP1: {requested: true, nextPollSeconds: 46},
1238       GROUP2: {requested: false},
1239       GROUP4: {requested: true, nextPollSeconds: 45},
1240       GROUP5: {requested: true}
1241     },
1242     notifications: [
1243       {notificationId: 'c4', groupName: 'GROUP1'},
1244       {notificationId: 'c5', groupName: 'GROUP1'}
1245     ]
1246   };
1247
1248   var recentDismissals = {
1249     c4: 1800000, // expired dismissal
1250     c5: 1800001  // non-expired dismissal
1251   };
1252
1253   var storedGroups = {
1254     GROUP2: {
1255       cards: [{notificationId: 'c2'}],
1256       cardsTimestamp: 239,
1257       nextPollTime: 10000
1258     },
1259     GROUP3: {
1260       cards: [{notificationId: 'c3'}],
1261       cardsTimestamp: 240,
1262       nextPollTime: 10001
1263     },
1264     GROUP4: {
1265       cards: [{notificationId: 'c6'}],
1266       cardsTimestamp: 241,
1267       nextPollTime: 10002
1268     }
1269   };
1270
1271   var expectedUpdatedGroups = {
1272     GROUP1: {
1273       cards: [{notificationId: 'c4', groupName: 'GROUP1'}],
1274       cardsTimestamp: 3000000,
1275       nextPollTime: 3046000
1276     },
1277     GROUP2: {
1278       cards: [{notificationId: 'c2'}],
1279       cardsTimestamp: 239,
1280       nextPollTime: 10000
1281     },
1282     GROUP4: {
1283       cards: [],
1284       cardsTimestamp: 3000000,
1285       nextPollTime: 3045000
1286     },
1287     GROUP5: {
1288       cards: [],
1289       cardsTimestamp: 3000000
1290     }
1291   };
1292
1293   var expectedUpdatedRecentDismissals = {
1294     c5: 1800001
1295   };
1296
1297   this.makeAndRegisterMockGlobals([
1298     'scheduleNextCardsPoll'
1299   ]);
1300
1301   this.makeAndRegisterMockApis([
1302     'fillFromChromeLocalStorage',
1303   ]);
1304
1305   expectChromeLocalStorageGet(
1306       this,
1307       {
1308         notificationGroups: {},
1309         recentDismissals: {}
1310       },
1311       {
1312         notificationGroups: storedGroups,
1313         recentDismissals: recentDismissals
1314       });
1315
1316   this.mockGlobals.expects(once())
1317       .scheduleNextCardsPoll(eqJSON(expectedUpdatedGroups));
1318
1319   // Invoking the tested function.
1320   processServerResponse(serverResponse);
1321 });
1322
1323 TEST_F(TEST_NAME, 'ProcessServerResponseGoogleNowDisabled', function() {
1324   // Tests processServerResponse function for the case when the response
1325   // indicates that Google Now is disabled.
1326
1327   // Setup and expectations.
1328   var serverResponse = {
1329     googleNowDisabled: true,
1330     groups: {}
1331   };
1332
1333   this.makeAndRegisterMockGlobals([
1334     'scheduleNextCardsPoll'
1335   ]);
1336
1337   this.makeAndRegisterMockApis([
1338     'chrome.storage.local.set',
1339     'fillFromChromeLocalStorage'
1340   ]);
1341
1342   this.mockApis.expects(once()).
1343       chrome_storage_local_set(eqJSON({googleNowEnabled: false}));
1344
1345   this.mockGlobals.expects(never()).scheduleNextCardsPoll();
1346
1347   // Invoking the tested function.
1348   processServerResponse(serverResponse);
1349 });
1350