• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
12function GoogleNowBackgroundUnitTest () {
13  testing.Test.call(this);
14}
15
16GoogleNowBackgroundUnitTest.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
27var TEST_NAME = 'GoogleNowBackgroundUnitTest';
28
29/**
30 * Tasks Conflict Test
31 */
32TEST_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 */
62TEST_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
73TEST_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
92TEST_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
111function 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
152TEST_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 */
176TEST_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
216TEST_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
259TEST_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
299TEST_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 */
336TEST_F(TEST_NAME, 'ShouldScheduleRetryEmptyGroupList', function() {
337  assertTrue(shouldScheduleRetryFromGroupList([]));
338});
339
340TEST_F(TEST_NAME, 'ShouldScheduleRetryNorOnlyGroupList', function() {
341  assertFalse(shouldScheduleRetryFromGroupList(['NOR']));
342});
343
344TEST_F(TEST_NAME, 'ShouldScheduleRetryNotOnlyGroupList', function() {
345  assertTrue(shouldScheduleRetryFromGroupList(['NOT']));
346});
347
348TEST_F(TEST_NAME, 'ShouldScheduleRetryMultipleGroupsList', function() {
349  assertTrue(shouldScheduleRetryFromGroupList(['NOR', 'NOT']));
350});
351
352/**
353 * requestAndUpdateOptIn Tests
354 */
355TEST_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
381TEST_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
407TEST_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 */
432TEST_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
450TEST_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
473TEST_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 */
499TEST_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
516TEST_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 */
546TEST_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 */
603function 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 */
643function 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 */
701function 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
718TEST_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
751TEST_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
782TEST_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
813TEST_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
844TEST_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 */
879TEST_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
906TEST_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
933TEST_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
960TEST_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 */
991function mockOnNotificationClickedDependencies(fixture) {
992  fixture.makeAndRegisterMockApis([
993    'chrome.windows.create',
994    'chrome.windows.update',
995    'fillFromChromeLocalStorage',
996    'instrumented.tabs.create']);
997}
998
999TEST_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
1019TEST_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
1048TEST_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
1085TEST_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
1123TEST_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
1218TEST_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
1323TEST_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
1351