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