Home | History | Annotate | Download | only in google_now
      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 /**
      6  * Test fixture for background.js.
      7  * @constructor
      8  * @extends {testing.Test}
      9  */
     10 function GoogleNowBackgroundUnitTest () {
     11   testing.Test.call(this);
     12 }
     13 
     14 GoogleNowBackgroundUnitTest.prototype = {
     15   __proto__: testing.Test.prototype,
     16 
     17   /** @override */
     18   extraLibraries: [
     19     'background_test_util.js',
     20     'background.js'
     21   ]
     22 };
     23 
     24 TEST_F('GoogleNowBackgroundUnitTest', 'AreTasksConflicting', function() {
     25   function testTaskPair(newTaskName, scheduledTaskName, expected) {
     26     assertTrue(areTasksConflicting(newTaskName, scheduledTaskName) == expected,
     27                '(' + newTaskName + ', ' + scheduledTaskName + ')');
     28   }
     29 
     30   testTaskPair(UPDATE_CARDS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
     31   testTaskPair(UPDATE_CARDS_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
     32   testTaskPair(UPDATE_CARDS_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
     33   testTaskPair(UPDATE_CARDS_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
     34 
     35   testTaskPair(DISMISS_CARD_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
     36   testTaskPair(DISMISS_CARD_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
     37   testTaskPair(DISMISS_CARD_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
     38   testTaskPair(DISMISS_CARD_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
     39 
     40   testTaskPair(RETRY_DISMISS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
     41   testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true);
     42   testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true);
     43   testTaskPair(RETRY_DISMISS_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
     44 
     45   testTaskPair(STATE_CHANGED_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
     46   testTaskPair(STATE_CHANGED_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
     47   testTaskPair(STATE_CHANGED_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
     48   testTaskPair(STATE_CHANGED_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
     49 });
     50 
     51 /**
     52  * Mocks global functions and APIs that initialize() depends upon.
     53  * @param {Test} fixture Test fixture.
     54  */
     55 function mockInitializeDependencies(fixture) {
     56   fixture.makeAndRegisterMockGlobals([
     57     'recordEvent',
     58     'showWelcomeToast',
     59     'startPollingCards'
     60   ]);
     61   fixture.makeAndRegisterMockApis([
     62     'authenticationManager.isSignedIn',
     63     'chrome.location.clearWatch',
     64     'chrome.storage.local.set',
     65     'instrumented.notifications.getAll',
     66     'instrumented.preferencesPrivate.googleGeolocationAccessEnabled.get',
     67     'instrumented.storage.local.get',
     68     'tasks.add',
     69     'updateCardsAttempts.isRunning',
     70     'updateCardsAttempts.stop'
     71   ]);
     72 }
     73 
     74 /**
     75  * Sets up the test to expect the state machine calls and send
     76  * the specified state machine state. Currently used to test initialize().
     77  * Note that this CAN NOT be used if any of the methods below are called
     78  * outside of this context with the same argument matchers.
     79  * expects() calls cannot be chained with the same argument matchers.
     80  * @param {object} mockApisObj Mock APIs Object.
     81  * @param {string} testIdentityToken getAuthToken callback token.
     82  * @param {boolean} testGeolocationPref Geolocation Preference callback value.
     83  * @param {boolean} testUserRespondedToToast User Response to toast
     84  &     callback value.
     85  */
     86 function expectStateMachineCalls(
     87     mockApisObj,
     88     testIdentityToken,
     89     testGeolocationPref,
     90     testUserRespondedToToast) {
     91   var authenticationManagerIsSignedInSavedArgs = new SaveMockArguments();
     92   mockApisObj.expects(once()).
     93       authenticationManager_isSignedIn(
     94           authenticationManagerIsSignedInSavedArgs.match(ANYTHING)).
     95       will(invokeCallback(
     96           authenticationManagerIsSignedInSavedArgs,
     97           0,
     98           testIdentityToken));
     99 
    100   var googleGeolocationPrefGetSavedArgs = new SaveMockArguments();
    101   mockApisObj.expects(once()).
    102       instrumented_preferencesPrivate_googleGeolocationAccessEnabled_get(
    103           googleGeolocationPrefGetSavedArgs.match(eqJSON({})),
    104           googleGeolocationPrefGetSavedArgs.match(ANYTHING)).
    105       will(invokeCallback(
    106           googleGeolocationPrefGetSavedArgs, 1, {value: testGeolocationPref}));
    107 
    108   var storageGetSavedArgs = new SaveMockArguments();
    109   mockApisObj.expects(once()).
    110       instrumented_storage_local_get(
    111           storageGetSavedArgs.match(eq('userRespondedToToast')),
    112           storageGetSavedArgs.match(ANYTHING)).
    113       will(invokeCallback(storageGetSavedArgs, 1, testUserRespondedToToast));
    114 }
    115 
    116 /**
    117  * Sets up the test to expect the initialization calls that
    118  * initialize() invokes.
    119  * Note that this CAN NOT be used if any of the methods below are called
    120  * outside of this context with the same argument matchers.
    121  * expects() calls cannot be chained with the same argument matchers.
    122  */
    123 function expectInitialization(mockApisObj) {
    124   mockApisObj.expects(once()).
    125       chrome_location_clearWatch(ANYTHING);
    126   mockApisObj.expects(once()).
    127       updateCardsAttempts_stop();
    128   mockApisObj.expects(once()).
    129       chrome_storage_local_set(eqJSON({notificationsData: {}}));
    130   var tasksAddSavedArgs = new SaveMockArguments();
    131   mockApisObj.expects(once()).
    132       tasks_add(
    133           tasksAddSavedArgs.match(ANYTHING),
    134           tasksAddSavedArgs.match(ANYTHING)).
    135       will(invokeCallback(tasksAddSavedArgs, 1, function() {}));
    136   var updateCardsAttemptsIsRunningSavedArgs = new SaveMockArguments();
    137   mockApisObj.expects(once()).
    138       updateCardsAttempts_isRunning(
    139           updateCardsAttemptsIsRunningSavedArgs.match(ANYTHING)).
    140       will(
    141           invokeCallback(
    142              updateCardsAttemptsIsRunningSavedArgs, 0, false));
    143 }
    144 
    145 TEST_F(
    146     'GoogleNowBackgroundUnitTest',
    147     'Initialize_ToastStateEmpty1',
    148     function() {
    149       // Tests the case when the user isn't signed in and NOTIFICATION_CARDS_URL
    150       // is not set. Since NOTIFICATION_CARDS_URL is empty,
    151       // nothing should start.
    152 
    153       // Setup and expectations.
    154       NOTIFICATION_CARDS_URL = undefined;
    155       var testIdentityToken = undefined;
    156       var testGeolocationPref = false;
    157       var testUserRespondedToToast = {};
    158 
    159       mockInitializeDependencies(this);
    160 
    161       this.mockGlobals.expects(once()).recordEvent(
    162           GoogleNowEvent.EXTENSION_START);
    163 
    164       this.mockGlobals.expects(once()).recordEvent(
    165           GoogleNowEvent.STOPPED);
    166 
    167       expectInitialization(this.mockApis);
    168 
    169       expectStateMachineCalls(
    170           this.mockApis,
    171           testIdentityToken,
    172           testGeolocationPref,
    173           testUserRespondedToToast);
    174 
    175       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
    176       this.mockApis.expects(exactly(2)).
    177           instrumented_notifications_getAll(
    178               chromeNotificationGetAllSavedArgs.match(ANYTHING)).
    179           will(
    180               invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}),
    181               invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}));
    182 
    183       // TODO(robliao,vadimt): Determine the granularity of testing to perform.
    184 
    185       // Invoking the tested function.
    186       initialize();
    187     });
    188 
    189 TEST_F(
    190     'GoogleNowBackgroundUnitTest',
    191     'Initialize_ToastStateEmpty2',
    192     function() {
    193       // Tests the case when NOTIFICATION_CARDS_URL is but getAuthToken fails
    194       // most likely because the user is not signed in. In this case, the
    195       // function should quietly exit after finding out that getAuthToken fails.
    196 
    197       // Setup and expectations.
    198       NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
    199       var testIdentityToken = undefined;
    200       var testGeolocationPref = false;
    201       var testUserRespondedToToast = {};
    202 
    203       mockInitializeDependencies(this);
    204 
    205       this.mockGlobals.expects(once()).recordEvent(
    206           GoogleNowEvent.EXTENSION_START);
    207 
    208       this.mockGlobals.expects(once()).recordEvent(
    209           GoogleNowEvent.STOPPED);
    210 
    211       expectInitialization(this.mockApis);
    212 
    213       expectStateMachineCalls(
    214           this.mockApis,
    215           testIdentityToken,
    216           testGeolocationPref,
    217           testUserRespondedToToast);
    218 
    219       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
    220       this.mockApis.expects(exactly(2)).
    221           instrumented_notifications_getAll(
    222               chromeNotificationGetAllSavedArgs.match(ANYTHING)).
    223           will(
    224               invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}),
    225               invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}));
    226 
    227       // Invoking the tested function.
    228       initialize();
    229     });
    230 
    231 TEST_F(
    232     'GoogleNowBackgroundUnitTest',
    233     'Initialize_ToastStateEmpty3',
    234     function() {
    235       // Tests the case when NOTIFICATION_CARDS_URL is set, getAuthToken
    236       // succeeds, and the user has never responded to the toast.
    237       // In this case, the function should invoke showWelcomeToast().
    238 
    239       // Setup and expectations.
    240       NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
    241       var testIdentityToken = 'some identity token';
    242       var testGeolocationPref = false;
    243       var testUserRespondedToToast = {};
    244 
    245       mockInitializeDependencies(this);
    246 
    247       this.mockGlobals.expects(once()).recordEvent(
    248           GoogleNowEvent.EXTENSION_START);
    249 
    250       expectInitialization(this.mockApis);
    251 
    252       expectStateMachineCalls(
    253           this.mockApis,
    254           testIdentityToken,
    255           testGeolocationPref,
    256           testUserRespondedToToast);
    257 
    258       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
    259       this.mockApis.expects(exactly(2)).
    260           instrumented_notifications_getAll(
    261               chromeNotificationGetAllSavedArgs.match(ANYTHING)).
    262           will(
    263               invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}),
    264               invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}));
    265 
    266       this.mockGlobals.expects(once()).showWelcomeToast();
    267 
    268       // Invoking the tested function.
    269       initialize();
    270     });
    271 
    272 TEST_F('GoogleNowBackgroundUnitTest', 'Initialize_RunGoogleNow', function() {
    273   // Tests if Google Now will invoke startPollingCards when all
    274   // of the required state is fulfilled.
    275 
    276   // Setup and expectations.
    277   NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
    278   var testIdentityToken = 'some identity token';
    279   var testGeolocationPref = true;
    280   var testUserRespondedToToast = {userRespondedToToast: true};
    281 
    282   mockInitializeDependencies(this);
    283 
    284   this.mockGlobals.expects(once()).recordEvent(
    285         GoogleNowEvent.EXTENSION_START);
    286 
    287   expectInitialization(this.mockApis);
    288 
    289   expectStateMachineCalls(
    290       this.mockApis,
    291       testIdentityToken,
    292       testGeolocationPref,
    293       testUserRespondedToToast);
    294 
    295   var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
    296   this.mockApis.expects(exactly(2)).
    297       instrumented_notifications_getAll(
    298           chromeNotificationGetAllSavedArgs.match(ANYTHING)).
    299       will(
    300           invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}),
    301           invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}));
    302 
    303   this.mockGlobals.expects(once()).startPollingCards();
    304 
    305   // Invoking the tested function.
    306   initialize();
    307 });
    308 
    309 TEST_F('GoogleNowBackgroundUnitTest', 'Initialize_NoGeolocation', function() {
    310   // Tests the case where everything is in place except for the
    311   // Geolocation Preference after the user responded to the toast.
    312 
    313   // Setup and expectations.
    314   NOTIFICATION_CARDS_URL = 'https://some.server.url.com';
    315   var testIdentityToken = 'some identity token';
    316   var testGeolocationPref = false;
    317   var testUserRespondedToToast = {userRespondedToToast: true};
    318 
    319   mockInitializeDependencies(this);
    320 
    321   this.mockGlobals.expects(once()).recordEvent(
    322         GoogleNowEvent.EXTENSION_START);
    323 
    324   this.mockGlobals.expects(once()).recordEvent(
    325       GoogleNowEvent.USER_SUPPRESSED);
    326 
    327   expectInitialization(this.mockApis);
    328 
    329   expectStateMachineCalls(
    330       this.mockApis,
    331       testIdentityToken,
    332       testGeolocationPref,
    333       testUserRespondedToToast);
    334 
    335   var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
    336   this.mockApis.expects(exactly(2)).
    337       instrumented_notifications_getAll(
    338           chromeNotificationGetAllSavedArgs.match(ANYTHING)).
    339       will(
    340           invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}),
    341           invokeCallback(chromeNotificationGetAllSavedArgs, 0, {}));
    342 
    343   // Invoking the tested function.
    344   initialize();
    345 });
    346 
    347 /**
    348  * Mocks global functions and APIs that onNotificationClicked() depends upon.
    349  * @param {Test} fixture Test fixture.
    350  */
    351 function mockOnNotificationClickedDependencies(fixture) {
    352   fixture.makeAndRegisterMockApis([
    353       'chrome.windows.create',
    354       'instrumented.storage.local.get',
    355       'instrumented.tabs.create']);
    356 }
    357 
    358 TEST_F(
    359     'GoogleNowBackgroundUnitTest',
    360     'OnNotificationClicked_NoData',
    361     function() {
    362       // Tests the case when there is no data associated with notification id.
    363       // In this case, the function should do nothing.
    364 
    365       // Setup and expectations.
    366       var testNotificationId = 'TEST_ID';
    367       var testNotificationData = {};
    368 
    369       mockOnNotificationClickedDependencies(this);
    370       this.makeMockLocalFunctions(['selector']);
    371 
    372       var storageGetSavedArgs = new SaveMockArguments();
    373       this.mockApis.expects(once()).
    374           instrumented_storage_local_get(
    375               storageGetSavedArgs.match(eq('notificationsData')),
    376               storageGetSavedArgs.match(ANYTHING)).
    377           will(invokeCallback(storageGetSavedArgs, 1, testNotificationData));
    378 
    379       // Invoking the tested function.
    380       onNotificationClicked(
    381           testNotificationId, this.mockLocalFunctions.functions().selector);
    382     });
    383 
    384 TEST_F(
    385     'GoogleNowBackgroundUnitTest',
    386     'OnNotificationClicked_ActionUrlsNotObject',
    387     function() {
    388       // Tests the case when the data associated with notification id is not an
    389       // object, probably because of a malformed server response.
    390       // In this case, the function should do nothing.
    391 
    392       // Setup and expectations.
    393       var testActionUrls = 'string, not object';
    394       var testNotificationId = 'TEST_ID';
    395       var testNotificationData = {
    396           notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
    397       };
    398 
    399       mockOnNotificationClickedDependencies(this);
    400       this.makeMockLocalFunctions(['selector']);
    401 
    402       var storageGetSavedArgs = new SaveMockArguments();
    403       this.mockApis.expects(once()).
    404           instrumented_storage_local_get(
    405               storageGetSavedArgs.match(eq('notificationsData')),
    406               storageGetSavedArgs.match(ANYTHING)).
    407           will(invokeCallback(storageGetSavedArgs, 1, testNotificationData));
    408 
    409       // Invoking the tested function.
    410       onNotificationClicked(
    411           testNotificationId, this.mockLocalFunctions.functions().selector);
    412     });
    413 
    414 TEST_F(
    415     'GoogleNowBackgroundUnitTest',
    416     'OnNotificationClicked_UrlNotString',
    417     function() {
    418       // Tests the case when selector returns a non-string, probably because of
    419       // a malformed server response.
    420       // In this case, the function should do nothing.
    421 
    422       // Setup and expectations.
    423       var testActionUrls = {testField: 'TEST VALUE'};
    424       var testNotificationId = 'TEST_ID';
    425       var testNotificationData = {
    426           notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
    427       };
    428       var testActionUrl = {};
    429 
    430       mockOnNotificationClickedDependencies(this);
    431       this.makeMockLocalFunctions(['selector']);
    432 
    433       var storageGetSavedArgs = new SaveMockArguments();
    434       this.mockApis.expects(once()).
    435           instrumented_storage_local_get(
    436               storageGetSavedArgs.match(eq('notificationsData')),
    437               storageGetSavedArgs.match(ANYTHING)).
    438           will(invokeCallback(storageGetSavedArgs, 1, testNotificationData));
    439       this.mockLocalFunctions.expects(once()).selector(testActionUrls).will(
    440           returnValue(testActionUrl));
    441 
    442       // Invoking the tested function.
    443       onNotificationClicked(
    444           testNotificationId, this.mockLocalFunctions.functions().selector);
    445     });
    446 
    447 TEST_F(
    448     'GoogleNowBackgroundUnitTest',
    449     'OnNotificationClicked_TabCreateSuccess',
    450     function() {
    451       // Tests the selected URL is OK and crome.tabs.create suceeds.
    452 
    453       // Setup and expectations.
    454       var testActionUrls = {testField: 'TEST VALUE'};
    455       var testNotificationId = 'TEST_ID';
    456       var testNotificationData = {
    457           notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
    458       };
    459       var testActionUrl = 'http://testurl.com';
    460       var testCreatedTab = {};
    461 
    462       mockOnNotificationClickedDependencies(this);
    463       this.makeMockLocalFunctions(['selector']);
    464 
    465       var storageGetSavedArgs = new SaveMockArguments();
    466       this.mockApis.expects(once()).
    467           instrumented_storage_local_get(
    468               storageGetSavedArgs.match(eq('notificationsData')),
    469               storageGetSavedArgs.match(ANYTHING)).
    470           will(invokeCallback(storageGetSavedArgs, 1, testNotificationData));
    471       this.mockLocalFunctions.expects(once()).selector(testActionUrls).will(
    472           returnValue(testActionUrl));
    473       var chromeTabsCreateSavedArgs = new SaveMockArguments();
    474       this.mockApis.expects(once()).
    475           instrumented_tabs_create(
    476               chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
    477               chromeTabsCreateSavedArgs.match(ANYTHING)).
    478           will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
    479 
    480       // Invoking the tested function.
    481       onNotificationClicked(
    482           testNotificationId, this.mockLocalFunctions.functions().selector);
    483     });
    484 
    485 TEST_F(
    486     'GoogleNowBackgroundUnitTest',
    487     'OnNotificationClicked_TabCreateFail',
    488     function() {
    489       // Tests the selected URL is OK and crome.tabs.create fails.
    490       // In this case, the function should invoke chrome.windows.create as a
    491       // second attempt.
    492 
    493       // Setup and expectations.
    494       var testActionUrls = {testField: 'TEST VALUE'};
    495       var testNotificationId = 'TEST_ID';
    496       var testNotificationData = {
    497         notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
    498       };
    499       var testActionUrl = 'http://testurl.com';
    500       var testCreatedTab = undefined; // chrome.tabs.create fails
    501 
    502       mockOnNotificationClickedDependencies(this);
    503       this.makeMockLocalFunctions(['selector']);
    504 
    505       var storageGetSavedArgs = new SaveMockArguments();
    506       this.mockApis.expects(once()).
    507           instrumented_storage_local_get(
    508               storageGetSavedArgs.match(eq('notificationsData')),
    509               storageGetSavedArgs.match(ANYTHING)).
    510           will(invokeCallback(storageGetSavedArgs, 1, testNotificationData));
    511       this.mockLocalFunctions.expects(once()).selector(testActionUrls).will(
    512           returnValue(testActionUrl));
    513       var chromeTabsCreateSavedArgs = new SaveMockArguments();
    514       this.mockApis.expects(once()).
    515           instrumented_tabs_create(
    516               chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
    517               chromeTabsCreateSavedArgs.match(ANYTHING)).
    518           will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
    519       this.mockApis.expects(once()).chrome_windows_create(
    520           eqJSON({url: testActionUrl}));
    521 
    522       // Invoking the tested function.
    523       onNotificationClicked(
    524           testNotificationId, this.mockLocalFunctions.functions().selector);
    525     });
    526