Home | History | Annotate | Download | only in sync_notifier
      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(&notifier);
    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