| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <map> |
| |
| #include "base/command_line.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "chrome/browser/notifications/notification.h" |
| #include "chrome/browser/notifications/notification_test_util.h" |
| #include "chrome/browser/notifications/notification_ui_manager.h" |
| #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h" |
| #include "chrome/browser/notifications/sync_notifier/sync_notifier_test_utils.h" |
| #include "chrome/browser/notifications/sync_notifier/synced_notification.h" |
| #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info.h" |
| #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service.h" |
| #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service_factory.h" |
| #include "chrome/browser/prefs/browser_prefs.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/testing_pref_service_syncable.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/user_prefs/pref_registry_syncable.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "sync/api/sync_change.h" |
| #include "sync/api/sync_change_processor.h" |
| #include "sync/api/sync_change_processor_wrapper_for_test.h" |
| #include "sync/api/sync_error_factory.h" |
| #include "sync/api/sync_error_factory_mock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using sync_pb::SyncedNotificationSpecifics; |
| using sync_pb::EntitySpecifics; |
| using syncer::SyncData; |
| using syncer::SyncChange; |
| using syncer::SyncChangeList; |
| using syncer::SyncChangeProcessorWrapperForTest; |
| using syncer::SyncDataList; |
| using syncer::SYNCED_NOTIFICATIONS; |
| using notifier::SyncedNotification; |
| using notifier::ChromeNotifierService; |
| |
| namespace { |
| |
| // Extract notification id from syncer::SyncData. |
| std::string GetNotificationId(const SyncData& sync_data) { |
| SyncedNotificationSpecifics specifics = sync_data.GetSpecifics(). |
| synced_notification(); |
| |
| return specifics.coalesced_notification().key(); |
| } |
| |
| } // namespace |
| |
| namespace notifier { |
| |
| // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed |
| // back up to Sync. |
| class TestChangeProcessor : public syncer::SyncChangeProcessor { |
| public: |
| TestChangeProcessor() { } |
| virtual ~TestChangeProcessor() { } |
| |
| // Store a copy of all the changes passed in so we can examine them later. |
| virtual syncer::SyncError ProcessSyncChanges( |
| const tracked_objects::Location& from_here, |
| const SyncChangeList& change_list) OVERRIDE { |
| change_map_.clear(); |
| for (SyncChangeList::const_iterator iter = change_list.begin(); |
| iter != change_list.end(); ++iter) { |
| // Put the data into the change tracking map. |
| change_map_[GetNotificationId(iter->sync_data())] = *iter; |
| } |
| |
| return syncer::SyncError(); |
| } |
| |
| virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const |
| OVERRIDE { |
| return syncer::SyncDataList(); |
| } |
| |
| size_t change_list_size() { return change_map_.size(); } |
| |
| bool ContainsId(const std::string& id) { |
| return change_map_.find(id) != change_map_.end(); |
| } |
| |
| SyncChange GetChangeById(const std::string& id) { |
| EXPECT_TRUE(ContainsId(id)); |
| return change_map_[id]; |
| } |
| |
| private: |
| // Track the changes received in ProcessSyncChanges. |
| std::map<std::string, SyncChange> change_map_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor); |
| }; |
| |
| class ChromeNotifierServiceTest : public testing::Test { |
| public: |
| ChromeNotifierServiceTest() |
| : sync_processor_(new TestChangeProcessor), |
| sync_processor_wrapper_( |
| new SyncChangeProcessorWrapperForTest(sync_processor_.get())) {} |
| virtual ~ChromeNotifierServiceTest() {} |
| |
| // Methods from testing::Test. |
| virtual void SetUp() { |
| // These tests rely on synced notifications being active. Some testers |
| // report the channel as STABLE so we need to manually enable it. |
| // See crbug.com/338426 for details. |
| CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kEnableSyncSyncedNotifications); |
| |
| // Prevent test code from trying to go to the network. |
| ChromeNotifierService::set_avoid_bitmap_fetching_for_test(true); |
| notification_manager_.reset(new StubNotificationUIManager(GURL( |
| kSyncedNotificationsWelcomeOrigin))); |
| |
| // Set up a profile for the unit tests to use. |
| profile_.reset(new TestingProfile()); |
| |
| // Set up the testing SyncedNotificationAppInfoService with some test data. |
| AddTestingAppInfos(); |
| } |
| |
| virtual void TearDown() { |
| notification_manager_.reset(); |
| } |
| |
| StubNotificationUIManager* notification_manager() { |
| return notification_manager_.get(); |
| } |
| |
| TestChangeProcessor* processor() { |
| return static_cast<TestChangeProcessor*>(sync_processor_.get()); |
| } |
| |
| scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() { |
| return sync_processor_wrapper_.Pass(); |
| } |
| |
| SyncedNotification* CreateNotification( |
| const std::string& title, |
| const std::string& text, |
| const std::string& app_icon_url, |
| const std::string& image_url, |
| const std::string& app_id, |
| const std::string& key, |
| sync_pb::CoalescedSyncedNotification_ReadState read_state) { |
| SyncData sync_data = CreateSyncData(title, text, app_icon_url, image_url, |
| app_id, key, read_state); |
| // Set enough fields in sync_data, including specifics, for our tests |
| // to pass. |
| return new SyncedNotification(sync_data, NULL, notification_manager_.get()); |
| } |
| |
| // Helper to create syncer::SyncChange. |
| static SyncChange CreateSyncChange( |
| SyncChange::SyncChangeType type, |
| SyncedNotification* notification) { |
| // Take control of the notification to clean it up after we create data |
| // out of it. |
| scoped_ptr<SyncedNotification> scoped_notification(notification); |
| return SyncChange( |
| FROM_HERE, |
| type, |
| ChromeNotifierService::CreateSyncDataFromNotification(*notification)); |
| } |
| |
| void AddTestingAppInfos() { |
| // Get the SyncedNotificationAppInfoService from the browser object. |
| SyncedNotificationAppInfoService* synced_notification_app_info_service = |
| SyncedNotificationAppInfoServiceFactory::GetForProfile( |
| profile_.get(), Profile::EXPLICIT_ACCESS); |
| |
| // Create a notification to add. |
| // The sending_service_infos_ list will take ownership of this pointer. |
| scoped_ptr<SyncedNotificationAppInfo> test_service1( |
| new SyncedNotificationAppInfo(profile_.get(), |
| std::string(kSendingService1Name), |
| synced_notification_app_info_service)); |
| |
| // Add some App IDs. |
| test_service1->AddAppId(kAppId1); |
| test_service1->AddAppId(kAppId2); |
| |
| // Set this icon's GURLs. |
| test_service1->SetSettingsURLs(GURL(kTestIconUrl), GURL()); |
| |
| // Call AddForTest. |
| synced_notification_app_info_service->AddForTest(test_service1.Pass()); |
| } |
| |
| protected: |
| scoped_ptr<TestingProfile> profile_; |
| |
| private: |
| scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; |
| scoped_ptr<syncer::SyncChangeProcessor> sync_processor_wrapper_; |
| scoped_ptr<StubNotificationUIManager> notification_manager_; |
| content::TestBrowserThreadBundle thread_bundle_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ChromeNotifierServiceTest); |
| }; |
| |
| // Create a Notification, convert it to SyncData and convert it back. |
| TEST_F(ChromeNotifierServiceTest, NotificationToSyncDataToNotification) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| |
| scoped_ptr<SyncedNotification> notification1( |
| CreateNotification(kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, |
| kKey1, kUnread)); |
| SyncData sync_data = |
| ChromeNotifierService::CreateSyncDataFromNotification(*notification1); |
| scoped_ptr<SyncedNotification> notification2( |
| notifier.CreateNotificationFromSyncData(sync_data)); |
| EXPECT_TRUE(notification2.get()); |
| EXPECT_TRUE(notification1->EqualsIgnoringReadState(*notification2)); |
| EXPECT_EQ(notification1->GetReadState(), notification2->GetReadState()); |
| } |
| |
| // Model assocation: We have no local data, and no remote data. |
| TEST_F(ChromeNotifierServiceTest, ModelAssocBothEmpty) { |
| |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| |
| notifier.MergeDataAndStartSyncing( |
| SYNCED_NOTIFICATIONS, |
| SyncDataList(), // Empty. |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| EXPECT_EQ(0U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| EXPECT_EQ(0U, processor()->change_list_size()); |
| } |
| |
| // Process sync changes when there is no local data. |
| TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesEmptyModel) { |
| // We initially have no data. |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| notifier.MergeDataAndStartSyncing( |
| SYNCED_NOTIFICATIONS, |
| SyncDataList(), |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| // Set up a bunch of ADDs. |
| SyncChangeList changes; |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_ADD, CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread))); |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_ADD, CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread))); |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_ADD, CreateNotification( |
| kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread))); |
| |
| notifier.ProcessSyncChanges(FROM_HERE, changes); |
| |
| EXPECT_EQ(3U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| // TODO(petewil): verify that the list entries have expected values to make |
| // this test more robust. |
| } |
| |
| // Process sync changes when there is local data. |
| TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesNonEmptyModel) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| notifier.AddForTest(n1.Pass()); |
| scoped_ptr<SyncedNotification> n2(CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); |
| notifier.AddForTest(n2.Pass()); |
| scoped_ptr<SyncedNotification> n3(CreateNotification( |
| kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread)); |
| notifier.AddForTest(n3.Pass()); |
| |
| notifier.MergeDataAndStartSyncing( |
| SYNCED_NOTIFICATIONS, |
| SyncDataList(), |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| // Set up some ADDs, some UPDATES, and some DELETEs |
| SyncChangeList changes; |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_ADD, CreateNotification( |
| kTitle4, kText4, kIconUrl4, kImageUrl4, kAppId4, kKey4, kUnread))); |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_UPDATE, CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kRead))); |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_DELETE, CreateNotification( |
| kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kDismissed))); |
| |
| // Simulate incoming new notifications at runtime. |
| notifier.ProcessSyncChanges(FROM_HERE, changes); |
| |
| // We should find notifications 1, 2, and 4, but not 3. |
| EXPECT_EQ(3U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey1)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey2)); |
| EXPECT_FALSE(notifier.FindNotificationById(kKey3)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey4)); |
| |
| // Verify that the first run preference is now set to false. |
| bool first_run = notifier.profile()->GetPrefs()->GetBoolean( |
| prefs::kSyncedNotificationFirstRun); |
| EXPECT_NE(true, first_run); |
| } |
| |
| // Process sync changes that arrive before the change they are supposed to |
| // modify. |
| TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesOutOfOrder) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| notifier.AddForTest(n1.Pass()); |
| scoped_ptr<SyncedNotification> n2(CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); |
| notifier.AddForTest(n2.Pass()); |
| scoped_ptr<SyncedNotification> n3(CreateNotification( |
| kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread)); |
| notifier.AddForTest(n3.Pass()); |
| |
| notifier.MergeDataAndStartSyncing( |
| SYNCED_NOTIFICATIONS, |
| SyncDataList(), |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| SyncChangeList changes; |
| // UPDATE a notification we have not seen an add for. |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_UPDATE, CreateNotification( |
| kTitle4, kText4, kIconUrl4, kImageUrl4, kAppId4, kKey4, kUnread))); |
| // ADD a notification that we already have. |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_ADD, CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kRead))); |
| // DELETE a notification we have not seen yet. |
| changes.push_back(CreateSyncChange( |
| SyncChange::ACTION_DELETE, CreateNotification( |
| kTitle5, kText5, kIconUrl5, kImageUrl5, kAppId5, kKey5, kDismissed))); |
| |
| // Simulate incoming new notifications at runtime. |
| notifier.ProcessSyncChanges(FROM_HERE, changes); |
| |
| // We should find notifications 1, 2, 3, and 4, but not 5. |
| EXPECT_EQ(4U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey1)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey2)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey3)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey4)); |
| EXPECT_FALSE(notifier.FindNotificationById(kKey5)); |
| } |
| |
| |
| // Model has some notifications, some of them are local only. Sync has some |
| // notifications. No items match up. |
| TEST_F(ChromeNotifierServiceTest, LocalRemoteBothNonEmptyNoOverlap) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| notifier.AddForTest(n1.Pass()); |
| scoped_ptr<SyncedNotification> n2(CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); |
| notifier.AddForTest(n2.Pass()); |
| scoped_ptr<SyncedNotification> n3(CreateNotification( |
| kTitle3, kText3, kIconUrl3, kImageUrl3, kAppId3, kKey3, kUnread)); |
| notifier.AddForTest(n3.Pass()); |
| |
| // Create some remote fake data. |
| SyncDataList initial_data; |
| initial_data.push_back(CreateSyncData(kTitle4, kText4, kIconUrl4, kImageUrl4, |
| kAppId4, kKey4, kUnread)); |
| initial_data.push_back(CreateSyncData(kTitle5, kText5, kIconUrl5, kImageUrl5, |
| kAppId5, kKey5, kUnread)); |
| initial_data.push_back(CreateSyncData(kTitle6, kText6, kIconUrl6, kImageUrl6, |
| kAppId6, kKey6, kUnread)); |
| initial_data.push_back(CreateSyncData(kTitle7, kText7, kIconUrl7, kImageUrl7, |
| kAppId7, kKey7, kUnread)); |
| |
| // Merge the local and remote data. |
| notifier.MergeDataAndStartSyncing( |
| SYNCED_NOTIFICATIONS, |
| initial_data, |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| // Ensure the local store now has all local and remote notifications. |
| EXPECT_EQ(7U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey1)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey2)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey3)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey4)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey5)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey6)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey7)); |
| |
| // Test the type conversion and construction functions. |
| for (SyncDataList::const_iterator iter = initial_data.begin(); |
| iter != initial_data.end(); ++iter) { |
| scoped_ptr<SyncedNotification> notification1( |
| notifier.CreateNotificationFromSyncData(*iter)); |
| // TODO(petewil): Revisit this when we add version info to notifications. |
| const std::string& key = notification1->GetKey(); |
| const SyncedNotification* notification2 = |
| notifier.FindNotificationById(key); |
| EXPECT_TRUE(NULL != notification2); |
| EXPECT_TRUE(notification1->EqualsIgnoringReadState(*notification2)); |
| EXPECT_EQ(notification1->GetReadState(), notification2->GetReadState()); |
| } |
| EXPECT_TRUE(notifier.FindNotificationById(kKey1)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey2)); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey3)); |
| } |
| |
| // Test the local store having the read bit unset, the remote store having |
| // it set. |
| TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch1) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| notifier.AddForTest(n1.Pass()); |
| scoped_ptr<SyncedNotification> n2(CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); |
| notifier.AddForTest(n2.Pass()); |
| |
| // Create some remote fake data, item 1 matches except for the read state. |
| syncer::SyncDataList initial_data; |
| initial_data.push_back(CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1, |
| kAppId1, kKey1, kDismissed)); |
| // Merge the local and remote data. |
| notifier.MergeDataAndStartSyncing( |
| syncer::SYNCED_NOTIFICATIONS, |
| initial_data, |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| // Ensure the local store still has only two notifications, and the read |
| // state of the first is now read. |
| EXPECT_EQ(2U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size()); |
| SyncedNotification* notification1 = |
| notifier.FindNotificationById(kKey1); |
| EXPECT_FALSE(NULL == notification1); |
| EXPECT_EQ(SyncedNotification::kDismissed, notification1->GetReadState()); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey2)); |
| EXPECT_FALSE(notifier.FindNotificationById(kKey3)); |
| |
| // Make sure that the notification manager was told to dismiss the |
| // notification. |
| EXPECT_EQ(std::string(kKey1), notification_manager()->dismissed_id()); |
| |
| // Ensure no new data will be sent to the remote store for notification1. |
| EXPECT_EQ(0U, processor()->change_list_size()); |
| EXPECT_FALSE(processor()->ContainsId(kKey1)); |
| } |
| |
| // Test when the local store has the read bit set, and the remote store has |
| // it unset. |
| TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch2) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kDismissed)); |
| notifier.AddForTest(n1.Pass()); |
| scoped_ptr<SyncedNotification> n2(CreateNotification( |
| kTitle2, kText2, kIconUrl2, kImageUrl2, kAppId2, kKey2, kUnread)); |
| notifier.AddForTest(n2.Pass()); |
| |
| // Create some remote fake data, item 1 matches except for the read state. |
| syncer::SyncDataList initial_data; |
| initial_data.push_back(CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1, |
| kAppId1, kKey1, kUnread)); |
| // Merge the local and remote data. |
| notifier.MergeDataAndStartSyncing( |
| syncer::SYNCED_NOTIFICATIONS, |
| initial_data, |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| // Ensure the local store still has only two notifications, and the read |
| // state of the first is now read. |
| EXPECT_EQ(2U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size()); |
| SyncedNotification* notification1 = |
| notifier.FindNotificationById(kKey1); |
| EXPECT_FALSE(NULL == notification1); |
| EXPECT_EQ(SyncedNotification::kDismissed, notification1->GetReadState()); |
| EXPECT_TRUE(notifier.FindNotificationById(kKey2)); |
| EXPECT_FALSE(notifier.FindNotificationById(kKey3)); |
| |
| // Ensure the new data will be sent to the remote store for notification1. |
| EXPECT_EQ(1U, processor()->change_list_size()); |
| EXPECT_TRUE(processor()->ContainsId(kKey1)); |
| EXPECT_EQ(SyncChange::ACTION_UPDATE, processor()->GetChangeById( |
| kKey1).change_type()); |
| } |
| |
| // We have a notification in the local store, we get an updated version |
| // of the same notification remotely, it should take precedence. |
| TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyWithUpdate) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kDismissed)); |
| notifier.AddForTest(n1.Pass()); |
| |
| // Create some remote fake data, item 1 matches the ID, but has different data |
| syncer::SyncDataList initial_data; |
| initial_data.push_back(CreateSyncData(kTitle2, kText2, kIconUrl2, kImageUrl2, |
| kAppId1, kKey1, kUnread)); |
| // Merge the local and remote data. |
| notifier.MergeDataAndStartSyncing( |
| syncer::SYNCED_NOTIFICATIONS, |
| initial_data, |
| PassProcessor(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| // Ensure the local store still has only one notification |
| EXPECT_EQ(1U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size()); |
| SyncedNotification* notification1 = |
| notifier.FindNotificationById(kKey1); |
| |
| EXPECT_FALSE(NULL == notification1); |
| EXPECT_EQ(SyncedNotification::kUnread, notification1->GetReadState()); |
| EXPECT_EQ(std::string(kTitle2), notification1->GetTitle()); |
| |
| // Ensure no new data will be sent to the remote store for notification1. |
| EXPECT_EQ(0U, processor()->change_list_size()); |
| EXPECT_FALSE(processor()->ContainsId(kKey1)); |
| } |
| |
| TEST_F(ChromeNotifierServiceTest, ServiceEnabledTest) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| std::set<std::string>::iterator iter; |
| std::string first_synced_notification_service_id(kSendingService1Name); |
| |
| // Create some local fake data. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| notifier.AddForTest(n1.Pass()); |
| |
| // Enable the service and ensure the service is in the list. |
| // Initially the service starts in the disabled state. |
| notifier.OnSyncedNotificationServiceEnabled(kSendingService1Name, true); |
| iter = find(notifier.enabled_sending_services_.begin(), |
| notifier.enabled_sending_services_.end(), |
| first_synced_notification_service_id); |
| |
| EXPECT_NE(notifier.enabled_sending_services_.end(), iter); |
| |
| // TODO(petewil): Verify Display gets called too. |
| // Disable the service and ensure it is gone from the list and the |
| // notification_manager. |
| notifier.OnSyncedNotificationServiceEnabled(kSendingService1Name, false); |
| iter = find(notifier.enabled_sending_services_.begin(), |
| notifier.enabled_sending_services_.end(), |
| first_synced_notification_service_id); |
| |
| EXPECT_EQ(notifier.enabled_sending_services_.end(), iter); |
| EXPECT_EQ(notification_manager()->dismissed_id(), std::string(kKey1)); |
| } |
| |
| // http://crbug.com/341326 |
| #if defined(TOOLKIT_GTK) |
| #define MAYBE_AddNewSendingServicesTest DISABLED_AddNewSendingServicesTest |
| #else |
| #define MAYBE_AddNewSendingServicesTest AddNewSendingServicesTest |
| #endif |
| TEST_F(ChromeNotifierServiceTest, MAYBE_AddNewSendingServicesTest) { |
| // This test will see if we get a new sending service after the first |
| // notification for that service. |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // We initially have no data. |
| EXPECT_EQ(0U, notifier.enabled_sending_services_.size()); |
| EXPECT_EQ(0U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| |
| // Set up an ADD. |
| SyncChangeList changes; |
| changes.push_back( |
| CreateSyncChange(SyncChange::ACTION_ADD, |
| CreateNotification(kTitle1, |
| kText1, |
| kIconUrl1, |
| kImageUrl1, |
| kAppId1, |
| kKey1, |
| kUnread))); |
| |
| notifier.ProcessSyncChanges(FROM_HERE, changes); |
| |
| EXPECT_EQ(1U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| |
| // Verify that the first synced notification service is enabled in memory. |
| std::set<std::string>::iterator iter; |
| std::string first_notification_service_id(kSendingService1Name); |
| iter = find(notifier.enabled_sending_services_.begin(), |
| notifier.enabled_sending_services_.end(), |
| first_notification_service_id); |
| |
| EXPECT_NE(notifier.enabled_sending_services_.end(), iter); |
| |
| // We should have gotten the synced notification and a welcome notification. |
| EXPECT_EQ(2U, notification_manager()->added_notifications()); |
| EXPECT_TRUE(notification_manager()->welcomed()); |
| |
| changes.clear(); |
| changes.push_back( |
| CreateSyncChange(SyncChange::ACTION_ADD, |
| CreateNotification(kTitle2, |
| kText2, |
| kIconUrl2, |
| kImageUrl2, |
| kAppId1, |
| kKey2, |
| kUnread))); |
| notifier.ProcessSyncChanges(FROM_HERE, changes); |
| |
| // But adding another notification should not cause another welcome. |
| EXPECT_EQ(3U, notification_manager()->added_notifications()); |
| } |
| |
| TEST_F(ChromeNotifierServiceTest, CheckInitializedServicesTest) { |
| // This test will see if we get a new sending service after the first |
| // notification for that service. |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Initialize but do not enable the sending service. |
| notifier.initialized_sending_services_.insert(kSendingService1Name); |
| ASSERT_EQ(0U, notifier.enabled_sending_services_.size()); |
| ASSERT_EQ(1U, notifier.initialized_sending_services_.size()); |
| |
| // We initially have no data. |
| EXPECT_EQ(0U, notifier.enabled_sending_services_.size()); |
| EXPECT_EQ(0U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size()); |
| |
| // Set up an ADD. |
| std::string first_synced_notification_service_id(kSendingService1Name); |
| |
| SyncChangeList changes; |
| changes.push_back( |
| CreateSyncChange(SyncChange::ACTION_ADD, |
| CreateNotification(kTitle1, |
| kText1, |
| kIconUrl1, |
| kImageUrl1, |
| kAppId1, |
| kKey1, |
| kUnread))); |
| |
| notifier.ProcessSyncChanges(FROM_HERE, changes); |
| |
| // Since we added to |initialized_sending_services_| before receiving the |
| // synced notification, we should not have enabled this service while |
| // processing the sync change. |
| EXPECT_EQ(0U, notifier.enabled_sending_services_.size()); |
| EXPECT_EQ(0U, notification_manager()->added_notifications()); |
| } |
| |
| #if defined(TOOLKIT_GTK) |
| // TODO(petewil): crbug.com/358031 |
| #define MAYBE_SetAddedAppIdsTest DISABLED_SetAddedAppIdsTest |
| #else |
| #define MAYBE_SetAddedAppIdsTest SetAddedAppIdsTest |
| #endif |
| TEST_F(ChromeNotifierServiceTest, MAYBE_SetAddedAppIdsTest) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Add some notifications to our notification list. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| n1->SetNotifierServiceForTest(¬ifier); |
| notifier.AddForTest(n1.Pass()); |
| |
| EXPECT_EQ(static_cast<size_t>(0), |
| notification_manager()->added_notifications()); |
| |
| // Call SetAddedAppIds. |
| std::vector<std::string> added_app_ids; |
| added_app_ids.push_back(std::string(kAppId1)); |
| notifier.OnAddedAppIds(added_app_ids); |
| |
| // Verify the notification was added by the notification_manager. |
| // We see one welcome notification and one new notification. |
| EXPECT_EQ(static_cast<size_t>(2), |
| notification_manager()->added_notifications()); |
| } |
| |
| TEST_F(ChromeNotifierServiceTest, SetRemovedAppIdsTest) { |
| ChromeNotifierService notifier(profile_.get(), notification_manager()); |
| notifier.set_avoid_bitmap_fetching_for_test(true); |
| |
| // Add some notifications to our notification list. |
| scoped_ptr<SyncedNotification> n1(CreateNotification( |
| kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread)); |
| notifier.AddForTest(n1.Pass()); |
| |
| // Call SetRemovedAppIds. |
| std::vector<std::string> removed_app_ids; |
| removed_app_ids.push_back(std::string(kAppId1)); |
| notifier.OnRemovedAppIds(removed_app_ids); |
| |
| // Verify the notification was "removed" in the notification manager. |
| EXPECT_EQ(std::string(kKey1), notification_manager()->dismissed_id()); |
| } |
| |
| // TODO(petewil): Add a test that we do *not* get a welcome dialog unless we |
| // have a valid app info for the notification. |
| |
| } // namespace notifier |