1 // Copyright (c) 2012 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 #include <map> 6 7 #include "base/command_line.h" 8 #include "base/gtest_prod_util.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/values.h" 13 #include "chrome/browser/notifications/notification.h" 14 #include "chrome/browser/notifications/notification_test_util.h" 15 #include "chrome/browser/notifications/notification_ui_manager.h" 16 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h" 17 #include "chrome/browser/notifications/sync_notifier/sync_notifier_test_utils.h" 18 #include "chrome/browser/notifications/sync_notifier/synced_notification.h" 19 #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info.h" 20 #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service.h" 21 #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service_factory.h" 22 #include "chrome/browser/prefs/browser_prefs.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/common/chrome_switches.h" 25 #include "chrome/common/pref_names.h" 26 #include "chrome/test/base/testing_pref_service_syncable.h" 27 #include "chrome/test/base/testing_profile.h" 28 #include "components/pref_registry/pref_registry_syncable.h" 29 #include "content/public/test/test_browser_thread_bundle.h" 30 #include "sync/api/sync_change.h" 31 #include "sync/api/sync_change_processor.h" 32 #include "sync/api/sync_change_processor_wrapper_for_test.h" 33 #include "sync/api/sync_error_factory.h" 34 #include "sync/api/sync_error_factory_mock.h" 35 #include "testing/gtest/include/gtest/gtest.h" 36 37 using sync_pb::SyncedNotificationSpecifics; 38 using sync_pb::EntitySpecifics; 39 using syncer::SyncData; 40 using syncer::SyncChange; 41 using syncer::SyncChangeList; 42 using syncer::SyncChangeProcessorWrapperForTest; 43 using syncer::SyncDataList; 44 using syncer::SYNCED_NOTIFICATIONS; 45 using notifier::SyncedNotification; 46 using notifier::ChromeNotifierService; 47 48 namespace { 49 50 // Extract notification id from syncer::SyncData. 51 std::string GetNotificationId(const SyncData& sync_data) { 52 SyncedNotificationSpecifics specifics = sync_data.GetSpecifics(). 53 synced_notification(); 54 55 return specifics.coalesced_notification().key(); 56 } 57 58 } // namespace 59 60 namespace notifier { 61 62 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed 63 // back up to Sync. 64 class TestChangeProcessor : public syncer::SyncChangeProcessor { 65 public: 66 TestChangeProcessor() { } 67 virtual ~TestChangeProcessor() { } 68 69 // Store a copy of all the changes passed in so we can examine them later. 70 virtual syncer::SyncError ProcessSyncChanges( 71 const tracked_objects::Location& from_here, 72 const SyncChangeList& change_list) OVERRIDE { 73 change_map_.clear(); 74 for (SyncChangeList::const_iterator iter = change_list.begin(); 75 iter != change_list.end(); ++iter) { 76 // Put the data into the change tracking map. 77 change_map_[GetNotificationId(iter->sync_data())] = *iter; 78 } 79 80 return syncer::SyncError(); 81 } 82 83 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const 84 OVERRIDE { 85 return syncer::SyncDataList(); 86 } 87 88 size_t change_list_size() { return change_map_.size(); } 89 90 bool ContainsId(const std::string& id) { 91 return change_map_.find(id) != change_map_.end(); 92 } 93 94 SyncChange GetChangeById(const std::string& id) { 95 EXPECT_TRUE(ContainsId(id)); 96 return change_map_[id]; 97 } 98 99 private: 100 // Track the changes received in ProcessSyncChanges. 101 std::map<std::string, SyncChange> change_map_; 102 103 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor); 104 }; 105 106 class ChromeNotifierServiceTest : public testing::Test { 107 public: 108 ChromeNotifierServiceTest() 109 : sync_processor_(new TestChangeProcessor), 110 sync_processor_wrapper_( 111 new SyncChangeProcessorWrapperForTest(sync_processor_.get())) {} 112 virtual ~ChromeNotifierServiceTest() {} 113 114 // Methods from testing::Test. 115 virtual void SetUp() { 116 // These tests rely on synced notifications being active. Some testers 117 // report the channel as STABLE so we need to manually enable it. 118 // See crbug.com/338426 for details. 119 CommandLine::ForCurrentProcess()->AppendSwitch( 120 switches::kEnableSyncSyncedNotifications); 121 122 // Prevent test code from trying to go to the network. 123 ChromeNotifierService::set_avoid_bitmap_fetching_for_test(true); 124 notification_manager_.reset(new StubNotificationUIManager(GURL( 125 kSyncedNotificationsWelcomeOrigin))); 126 127 // Set up a profile for the unit tests to use. 128 profile_.reset(new TestingProfile()); 129 130 // Set up the testing SyncedNotificationAppInfoService with some test data. 131 AddTestingAppInfos(); 132 } 133 134 virtual void TearDown() { 135 notification_manager_.reset(); 136 } 137 138 StubNotificationUIManager* notification_manager() { 139 return notification_manager_.get(); 140 } 141 142 TestChangeProcessor* processor() { 143 return static_cast<TestChangeProcessor*>(sync_processor_.get()); 144 } 145 146 scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() { 147 return sync_processor_wrapper_.Pass(); 148 } 149 150 SyncedNotification* CreateNotification( 151 const std::string& title, 152 const std::string& text, 153 const std::string& app_icon_url, 154 const std::string& image_url, 155 const std::string& app_id, 156 const std::string& key, 157 sync_pb::CoalescedSyncedNotification_ReadState read_state) { 158 SyncData sync_data = CreateSyncData(title, text, app_icon_url, image_url, 159 app_id, key, read_state); 160 // Set enough fields in sync_data, including specifics, for our tests 161 // to pass. 162 return new SyncedNotification(sync_data, NULL, notification_manager_.get()); 163 } 164 165 // Helper to create syncer::SyncChange. 166 static SyncChange CreateSyncChange( 167 SyncChange::SyncChangeType type, 168 SyncedNotification* notification) { 169 // Take control of the notification to clean it up after we create data 170 // out of it. 171 scoped_ptr<SyncedNotification> scoped_notification(notification); 172 return SyncChange( 173 FROM_HERE, 174 type, 175 ChromeNotifierService::CreateSyncDataFromNotification(*notification)); 176 } 177 178 void AddTestingAppInfos() { 179 // Get the SyncedNotificationAppInfoService from the browser object. 180 SyncedNotificationAppInfoService* synced_notification_app_info_service = 181 SyncedNotificationAppInfoServiceFactory::GetForProfile( 182 profile_.get(), Profile::EXPLICIT_ACCESS); 183 184 // Create a notification to add. 185 // The sending_service_infos_ list will take ownership of this pointer. 186 scoped_ptr<SyncedNotificationAppInfo> test_service1( 187 new SyncedNotificationAppInfo(profile_.get(), 188 std::string(kSendingService1Name), 189 synced_notification_app_info_service)); 190 191 // Add some App IDs. 192 test_service1->AddAppId(kAppId1); 193 test_service1->AddAppId(kAppId2); 194 195 // Set this icon's GURLs. 196 test_service1->SetSettingsURLs(GURL(kTestIconUrl), GURL()); 197 198 // Call AddForTest. 199 synced_notification_app_info_service->AddForTest(test_service1.Pass()); 200 } 201 202 protected: 203 scoped_ptr<TestingProfile> profile_; 204 205 private: 206 scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; 207 scoped_ptr<syncer::SyncChangeProcessor> sync_processor_wrapper_; 208 scoped_ptr<StubNotificationUIManager> notification_manager_; 209 content::TestBrowserThreadBundle thread_bundle_; 210 211 DISALLOW_COPY_AND_ASSIGN(ChromeNotifierServiceTest); 212 }; 213 214 // Create a Notification, convert it to SyncData and convert it back. 215 TEST_F(ChromeNotifierServiceTest, NotificationToSyncDataToNotification) { 216 ChromeNotifierService notifier(profile_.get(), notification_manager()); 217 218 scoped_ptr<SyncedNotification> notification1( 219 CreateNotification(kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, 220 kKey1, kUnread)); 221 SyncData sync_data = 222 ChromeNotifierService::CreateSyncDataFromNotification(*notification1); 223 scoped_ptr<SyncedNotification> notification2( 224 notifier.CreateNotificationFromSyncData(sync_data)); 225 EXPECT_TRUE(notification2.get()); 226 EXPECT_TRUE(notification1->EqualsIgnoringReadState(*notification2)); 227 EXPECT_EQ(notification1->GetReadState(), notification2->GetReadState()); 228 } 229 230 // Model assocation: We have no local data, and no remote data. 231 TEST_F(ChromeNotifierServiceTest, ModelAssocBothEmpty) { 232 ChromeNotifierService notifier(profile_.get(), notification_manager()); 233 234 notifier.MergeDataAndStartSyncing( 235 SYNCED_NOTIFICATIONS, 236 SyncDataList(), // Empty. 237 PassProcessor(), 238 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 239 240 EXPECT_EQ(0U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 241 EXPECT_EQ(0U, processor()->change_list_size()); 242 } 243 244 // Process sync changes when there is no local data. 245 TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesEmptyModel) { 246 // We initially have no data. 247 ChromeNotifierService notifier(profile_.get(), notification_manager()); 248 notifier.set_avoid_bitmap_fetching_for_test(true); 249 250 notifier.MergeDataAndStartSyncing( 251 SYNCED_NOTIFICATIONS, 252 SyncDataList(), 253 PassProcessor(), 254 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 255 256 // Set up a bunch of ADDs. 257 SyncChangeList changes; 258 changes.push_back(CreateSyncChange( 259 SyncChange::ACTION_ADD, CreateNotification( 260 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread))); 261 changes.push_back(CreateSyncChange( 262 SyncChange::ACTION_ADD, CreateNotification( 263 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread))); 264 changes.push_back(CreateSyncChange( 265 SyncChange::ACTION_ADD, CreateNotification( 266 kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread))); 267 268 notifier.ProcessSyncChanges(FROM_HERE, changes); 269 270 EXPECT_EQ(3U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 271 // TODO(petewil): verify that the list entries have expected values to make 272 // this test more robust. 273 } 274 275 // Process sync changes when there is local data. 276 TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesNonEmptyModel) { 277 ChromeNotifierService notifier(profile_.get(), notification_manager()); 278 notifier.set_avoid_bitmap_fetching_for_test(true); 279 280 // Create some local fake data. 281 scoped_ptr<SyncedNotification> n1(CreateNotification( 282 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 283 notifier.AddForTest(n1.Pass()); 284 scoped_ptr<SyncedNotification> n2(CreateNotification( 285 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); 286 notifier.AddForTest(n2.Pass()); 287 scoped_ptr<SyncedNotification> n3(CreateNotification( 288 kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread)); 289 notifier.AddForTest(n3.Pass()); 290 291 notifier.MergeDataAndStartSyncing( 292 SYNCED_NOTIFICATIONS, 293 SyncDataList(), 294 PassProcessor(), 295 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 296 297 // Set up some ADDs, some UPDATES, and some DELETEs 298 SyncChangeList changes; 299 changes.push_back(CreateSyncChange( 300 SyncChange::ACTION_ADD, CreateNotification( 301 kTitle4, kText4, kIconUrl4, kImageUrl4, kAppId4, kKey4, kUnread))); 302 changes.push_back(CreateSyncChange( 303 SyncChange::ACTION_UPDATE, CreateNotification( 304 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kRead))); 305 changes.push_back(CreateSyncChange( 306 SyncChange::ACTION_DELETE, CreateNotification( 307 kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kDismissed))); 308 309 // Simulate incoming new notifications at runtime. 310 notifier.ProcessSyncChanges(FROM_HERE, changes); 311 312 // We should find notifications 1, 2, and 4, but not 3. 313 EXPECT_EQ(3U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 314 EXPECT_TRUE(notifier.FindNotificationById(kKey1)); 315 EXPECT_TRUE(notifier.FindNotificationById(kKey2)); 316 EXPECT_FALSE(notifier.FindNotificationById(kKey3)); 317 EXPECT_TRUE(notifier.FindNotificationById(kKey4)); 318 319 // Verify that the first run preference is now set to false. 320 bool first_run = notifier.profile()->GetPrefs()->GetBoolean( 321 prefs::kSyncedNotificationFirstRun); 322 EXPECT_NE(true, first_run); 323 } 324 325 // Process sync changes that arrive before the change they are supposed to 326 // modify. 327 TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesOutOfOrder) { 328 ChromeNotifierService notifier(profile_.get(), notification_manager()); 329 notifier.set_avoid_bitmap_fetching_for_test(true); 330 331 // Create some local fake data. 332 scoped_ptr<SyncedNotification> n1(CreateNotification( 333 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 334 notifier.AddForTest(n1.Pass()); 335 scoped_ptr<SyncedNotification> n2(CreateNotification( 336 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); 337 notifier.AddForTest(n2.Pass()); 338 scoped_ptr<SyncedNotification> n3(CreateNotification( 339 kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread)); 340 notifier.AddForTest(n3.Pass()); 341 342 notifier.MergeDataAndStartSyncing( 343 SYNCED_NOTIFICATIONS, 344 SyncDataList(), 345 PassProcessor(), 346 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 347 348 SyncChangeList changes; 349 // UPDATE a notification we have not seen an add for. 350 changes.push_back(CreateSyncChange( 351 SyncChange::ACTION_UPDATE, CreateNotification( 352 kTitle4, kText4, kIconUrl4, kImageUrl4, kAppId4, kKey4, kUnread))); 353 // ADD a notification that we already have. 354 changes.push_back(CreateSyncChange( 355 SyncChange::ACTION_ADD, CreateNotification( 356 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kRead))); 357 // DELETE a notification we have not seen yet. 358 changes.push_back(CreateSyncChange( 359 SyncChange::ACTION_DELETE, CreateNotification( 360 kTitle5, kText5, kIconUrl5, kImageUrl5, kAppId5, kKey5, kDismissed))); 361 362 // Simulate incoming new notifications at runtime. 363 notifier.ProcessSyncChanges(FROM_HERE, changes); 364 365 // We should find notifications 1, 2, 3, and 4, but not 5. 366 EXPECT_EQ(4U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 367 EXPECT_TRUE(notifier.FindNotificationById(kKey1)); 368 EXPECT_TRUE(notifier.FindNotificationById(kKey2)); 369 EXPECT_TRUE(notifier.FindNotificationById(kKey3)); 370 EXPECT_TRUE(notifier.FindNotificationById(kKey4)); 371 EXPECT_FALSE(notifier.FindNotificationById(kKey5)); 372 } 373 374 375 // Model has some notifications, some of them are local only. Sync has some 376 // notifications. No items match up. 377 TEST_F(ChromeNotifierServiceTest, LocalRemoteBothNonEmptyNoOverlap) { 378 ChromeNotifierService notifier(profile_.get(), notification_manager()); 379 notifier.set_avoid_bitmap_fetching_for_test(true); 380 381 // Create some local fake data. 382 scoped_ptr<SyncedNotification> n1(CreateNotification( 383 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 384 notifier.AddForTest(n1.Pass()); 385 scoped_ptr<SyncedNotification> n2(CreateNotification( 386 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); 387 notifier.AddForTest(n2.Pass()); 388 scoped_ptr<SyncedNotification> n3(CreateNotification( 389 kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread)); 390 notifier.AddForTest(n3.Pass()); 391 392 // Create some remote fake data. 393 SyncDataList initial_data; 394 initial_data.push_back(CreateSyncData(kTitle4, kText4, kIconUrl4, kImageUrl4, 395 kAppId4, kKey4, kUnread)); 396 initial_data.push_back(CreateSyncData(kTitle5, kText5, kIconUrl5, kImageUrl5, 397 kAppId5, kKey5, kUnread)); 398 initial_data.push_back(CreateSyncData(kTitle6, kText6, kIconUrl6, kImageUrl6, 399 kAppId6, kKey6, kUnread)); 400 initial_data.push_back(CreateSyncData(kTitle7, kText7, kIconUrl7, kImageUrl7, 401 kAppId7, kKey7, kUnread)); 402 403 // Merge the local and remote data. 404 notifier.MergeDataAndStartSyncing( 405 SYNCED_NOTIFICATIONS, 406 initial_data, 407 PassProcessor(), 408 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 409 410 // Ensure the local store now has all local and remote notifications. 411 EXPECT_EQ(7U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 412 EXPECT_TRUE(notifier.FindNotificationById(kKey1)); 413 EXPECT_TRUE(notifier.FindNotificationById(kKey2)); 414 EXPECT_TRUE(notifier.FindNotificationById(kKey3)); 415 EXPECT_TRUE(notifier.FindNotificationById(kKey4)); 416 EXPECT_TRUE(notifier.FindNotificationById(kKey5)); 417 EXPECT_TRUE(notifier.FindNotificationById(kKey6)); 418 EXPECT_TRUE(notifier.FindNotificationById(kKey7)); 419 420 // Test the type conversion and construction functions. 421 for (SyncDataList::const_iterator iter = initial_data.begin(); 422 iter != initial_data.end(); ++iter) { 423 scoped_ptr<SyncedNotification> notification1( 424 notifier.CreateNotificationFromSyncData(*iter)); 425 // TODO(petewil): Revisit this when we add version info to notifications. 426 const std::string& key = notification1->GetKey(); 427 const SyncedNotification* notification2 = 428 notifier.FindNotificationById(key); 429 EXPECT_TRUE(NULL != notification2); 430 EXPECT_TRUE(notification1->EqualsIgnoringReadState(*notification2)); 431 EXPECT_EQ(notification1->GetReadState(), notification2->GetReadState()); 432 } 433 EXPECT_TRUE(notifier.FindNotificationById(kKey1)); 434 EXPECT_TRUE(notifier.FindNotificationById(kKey2)); 435 EXPECT_TRUE(notifier.FindNotificationById(kKey3)); 436 } 437 438 // Test the local store having the read bit unset, the remote store having 439 // it set. 440 TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch1) { 441 ChromeNotifierService notifier(profile_.get(), notification_manager()); 442 notifier.set_avoid_bitmap_fetching_for_test(true); 443 444 // Create some local fake data. 445 scoped_ptr<SyncedNotification> n1(CreateNotification( 446 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 447 notifier.AddForTest(n1.Pass()); 448 scoped_ptr<SyncedNotification> n2(CreateNotification( 449 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); 450 notifier.AddForTest(n2.Pass()); 451 452 // Create some remote fake data, item 1 matches except for the read state. 453 syncer::SyncDataList initial_data; 454 initial_data.push_back(CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1, 455 kAppId1, kKey1, kDismissed)); 456 // Merge the local and remote data. 457 notifier.MergeDataAndStartSyncing( 458 syncer::SYNCED_NOTIFICATIONS, 459 initial_data, 460 PassProcessor(), 461 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 462 463 // Ensure the local store still has only two notifications, and the read 464 // state of the first is now read. 465 EXPECT_EQ(2U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size()); 466 SyncedNotification* notification1 = 467 notifier.FindNotificationById(kKey1); 468 EXPECT_FALSE(NULL == notification1); 469 EXPECT_EQ(SyncedNotification::kDismissed, notification1->GetReadState()); 470 EXPECT_TRUE(notifier.FindNotificationById(kKey2)); 471 EXPECT_FALSE(notifier.FindNotificationById(kKey3)); 472 473 // Make sure that the notification manager was told to dismiss the 474 // notification. 475 EXPECT_EQ(std::string(kKey1), notification_manager()->dismissed_id()); 476 477 // Ensure no new data will be sent to the remote store for notification1. 478 EXPECT_EQ(0U, processor()->change_list_size()); 479 EXPECT_FALSE(processor()->ContainsId(kKey1)); 480 } 481 482 // Test when the local store has the read bit set, and the remote store has 483 // it unset. 484 TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch2) { 485 ChromeNotifierService notifier(profile_.get(), notification_manager()); 486 notifier.set_avoid_bitmap_fetching_for_test(true); 487 488 // Create some local fake data. 489 scoped_ptr<SyncedNotification> n1(CreateNotification( 490 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kDismissed)); 491 notifier.AddForTest(n1.Pass()); 492 scoped_ptr<SyncedNotification> n2(CreateNotification( 493 kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); 494 notifier.AddForTest(n2.Pass()); 495 496 // Create some remote fake data, item 1 matches except for the read state. 497 syncer::SyncDataList initial_data; 498 initial_data.push_back(CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1, 499 kAppId1, kKey1, kUnread)); 500 // Merge the local and remote data. 501 notifier.MergeDataAndStartSyncing( 502 syncer::SYNCED_NOTIFICATIONS, 503 initial_data, 504 PassProcessor(), 505 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 506 507 // Ensure the local store still has only two notifications, and the read 508 // state of the first is now read. 509 EXPECT_EQ(2U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size()); 510 SyncedNotification* notification1 = 511 notifier.FindNotificationById(kKey1); 512 EXPECT_FALSE(NULL == notification1); 513 EXPECT_EQ(SyncedNotification::kDismissed, notification1->GetReadState()); 514 EXPECT_TRUE(notifier.FindNotificationById(kKey2)); 515 EXPECT_FALSE(notifier.FindNotificationById(kKey3)); 516 517 // Ensure the new data will be sent to the remote store for notification1. 518 EXPECT_EQ(1U, processor()->change_list_size()); 519 EXPECT_TRUE(processor()->ContainsId(kKey1)); 520 EXPECT_EQ(SyncChange::ACTION_UPDATE, processor()->GetChangeById( 521 kKey1).change_type()); 522 } 523 524 // We have a notification in the local store, we get an updated version 525 // of the same notification remotely, it should take precedence. 526 TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyWithUpdate) { 527 ChromeNotifierService notifier(profile_.get(), notification_manager()); 528 529 // Create some local fake data. 530 scoped_ptr<SyncedNotification> n1(CreateNotification( 531 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kDismissed)); 532 notifier.AddForTest(n1.Pass()); 533 534 // Create some remote fake data, item 1 matches the ID, but has different data 535 syncer::SyncDataList initial_data; 536 initial_data.push_back(CreateSyncData(kTitle2, kText2, kIconUrl2, kImageUrl2, 537 kAppId1, kKey1, kUnread)); 538 // Merge the local and remote data. 539 notifier.MergeDataAndStartSyncing( 540 syncer::SYNCED_NOTIFICATIONS, 541 initial_data, 542 PassProcessor(), 543 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 544 545 // Ensure the local store still has only one notification 546 EXPECT_EQ(1U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size()); 547 SyncedNotification* notification1 = 548 notifier.FindNotificationById(kKey1); 549 550 EXPECT_FALSE(NULL == notification1); 551 EXPECT_EQ(SyncedNotification::kUnread, notification1->GetReadState()); 552 EXPECT_EQ(std::string(kTitle2), notification1->GetTitle()); 553 554 // Ensure no new data will be sent to the remote store for notification1. 555 EXPECT_EQ(0U, processor()->change_list_size()); 556 EXPECT_FALSE(processor()->ContainsId(kKey1)); 557 } 558 559 TEST_F(ChromeNotifierServiceTest, ServiceEnabledTest) { 560 ChromeNotifierService notifier(profile_.get(), notification_manager()); 561 std::set<std::string>::iterator iter; 562 std::string first_synced_notification_service_id(kSendingService1Name); 563 564 // Create some local fake data. 565 scoped_ptr<SyncedNotification> n1(CreateNotification( 566 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 567 notifier.AddForTest(n1.Pass()); 568 569 // Enable the service and ensure the service is in the list. 570 // Initially the service starts in the disabled state. 571 notifier.OnSyncedNotificationServiceEnabled(kSendingService1Name, true); 572 iter = find(notifier.enabled_sending_services_.begin(), 573 notifier.enabled_sending_services_.end(), 574 first_synced_notification_service_id); 575 576 EXPECT_NE(notifier.enabled_sending_services_.end(), iter); 577 578 // TODO(petewil): Verify Display gets called too. 579 // Disable the service and ensure it is gone from the list and the 580 // notification_manager. 581 notifier.OnSyncedNotificationServiceEnabled(kSendingService1Name, false); 582 iter = find(notifier.enabled_sending_services_.begin(), 583 notifier.enabled_sending_services_.end(), 584 first_synced_notification_service_id); 585 586 EXPECT_EQ(notifier.enabled_sending_services_.end(), iter); 587 EXPECT_EQ(notification_manager()->dismissed_id(), std::string(kKey1)); 588 } 589 590 TEST_F(ChromeNotifierServiceTest, AddNewSendingServicesTest) { 591 // This test will see if we get a new sending service after the first 592 // notification for that service. 593 ChromeNotifierService notifier(profile_.get(), notification_manager()); 594 notifier.set_avoid_bitmap_fetching_for_test(true); 595 596 // We initially have no data. 597 EXPECT_EQ(0U, notifier.enabled_sending_services_.size()); 598 EXPECT_EQ(0U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 599 600 // Set up an ADD. 601 SyncChangeList changes; 602 changes.push_back( 603 CreateSyncChange(SyncChange::ACTION_ADD, 604 CreateNotification(kTitle1, 605 kText1, 606 kIconUrl1, 607 kImageUrl1, 608 kAppId1, 609 kKey1, 610 kUnread))); 611 612 notifier.ProcessSyncChanges(FROM_HERE, changes); 613 614 EXPECT_EQ(1U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 615 616 // Verify that the first synced notification service is enabled in memory. 617 std::set<std::string>::iterator iter; 618 std::string first_notification_service_id(kSendingService1Name); 619 iter = find(notifier.enabled_sending_services_.begin(), 620 notifier.enabled_sending_services_.end(), 621 first_notification_service_id); 622 623 EXPECT_NE(notifier.enabled_sending_services_.end(), iter); 624 625 // We should have gotten the synced notification and a welcome notification. 626 EXPECT_EQ(2U, notification_manager()->added_notifications()); 627 EXPECT_TRUE(notification_manager()->welcomed()); 628 629 changes.clear(); 630 changes.push_back( 631 CreateSyncChange(SyncChange::ACTION_ADD, 632 CreateNotification(kTitle2, 633 kText2, 634 kIconUrl2, 635 kImageUrl2, 636 kAppId1, 637 kKey2, 638 kUnread))); 639 notifier.ProcessSyncChanges(FROM_HERE, changes); 640 641 // But adding another notification should not cause another welcome. 642 EXPECT_EQ(3U, notification_manager()->added_notifications()); 643 } 644 645 TEST_F(ChromeNotifierServiceTest, CheckInitializedServicesTest) { 646 // This test will see if we get a new sending service after the first 647 // notification for that service. 648 ChromeNotifierService notifier(profile_.get(), notification_manager()); 649 notifier.set_avoid_bitmap_fetching_for_test(true); 650 651 // Initialize but do not enable the sending service. 652 notifier.initialized_sending_services_.insert(kSendingService1Name); 653 ASSERT_EQ(0U, notifier.enabled_sending_services_.size()); 654 ASSERT_EQ(1U, notifier.initialized_sending_services_.size()); 655 656 // We initially have no data. 657 EXPECT_EQ(0U, notifier.enabled_sending_services_.size()); 658 EXPECT_EQ(0U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); 659 660 // Set up an ADD. 661 std::string first_synced_notification_service_id(kSendingService1Name); 662 663 SyncChangeList changes; 664 changes.push_back( 665 CreateSyncChange(SyncChange::ACTION_ADD, 666 CreateNotification(kTitle1, 667 kText1, 668 kIconUrl1, 669 kImageUrl1, 670 kAppId1, 671 kKey1, 672 kUnread))); 673 674 notifier.ProcessSyncChanges(FROM_HERE, changes); 675 676 // Since we added to |initialized_sending_services_| before receiving the 677 // synced notification, we should not have enabled this service while 678 // processing the sync change. 679 EXPECT_EQ(0U, notifier.enabled_sending_services_.size()); 680 EXPECT_EQ(0U, notification_manager()->added_notifications()); 681 } 682 683 TEST_F(ChromeNotifierServiceTest, SetAddedAppIdsTest) { 684 ChromeNotifierService notifier(profile_.get(), notification_manager()); 685 notifier.set_avoid_bitmap_fetching_for_test(true); 686 687 // Add some notifications to our notification list. 688 scoped_ptr<SyncedNotification> n1(CreateNotification( 689 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 690 n1->SetNotifierServiceForTest(¬ifier); 691 notifier.AddForTest(n1.Pass()); 692 693 EXPECT_EQ(static_cast<size_t>(0), 694 notification_manager()->added_notifications()); 695 696 // Call SetAddedAppIds. 697 std::vector<std::string> added_app_ids; 698 added_app_ids.push_back(std::string(kAppId1)); 699 notifier.OnAddedAppIds(added_app_ids); 700 701 // Verify the notification was added by the notification_manager. 702 // We see one welcome notification and one new notification. 703 EXPECT_EQ(static_cast<size_t>(2), 704 notification_manager()->added_notifications()); 705 } 706 707 TEST_F(ChromeNotifierServiceTest, SetRemovedAppIdsTest) { 708 ChromeNotifierService notifier(profile_.get(), notification_manager()); 709 notifier.set_avoid_bitmap_fetching_for_test(true); 710 711 // Add some notifications to our notification list. 712 scoped_ptr<SyncedNotification> n1(CreateNotification( 713 kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); 714 notifier.AddForTest(n1.Pass()); 715 716 // Call SetRemovedAppIds. 717 std::vector<std::string> removed_app_ids; 718 removed_app_ids.push_back(std::string(kAppId1)); 719 notifier.OnRemovedAppIds(removed_app_ids); 720 721 // Verify the notification was "removed" in the notification manager. 722 EXPECT_EQ(std::string(kKey1), notification_manager()->dismissed_id()); 723 } 724 725 // TODO(petewil): Add a test that we do *not* get a welcome dialog unless we 726 // have a valid app info for the notification. 727 728 } // namespace notifier 729