Home | History | Annotate | Download | only in sync_notifier
      1 // Copyright 2014 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 "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service.h"
      6 
      7 #include "chrome/browser/notifications/sync_notifier/sync_notifier_test_utils.h"
      8 #include "chrome/browser/profiles/profile.h"
      9 #include "chrome/test/base/testing_pref_service_syncable.h"
     10 #include "chrome/test/base/testing_profile.h"
     11 #include "content/public/test/test_browser_thread.h"
     12 #include "sync/api/fake_sync_change_processor.h"
     13 #include "sync/api/sync_change.h"
     14 #include "sync/api/sync_change_processor.h"
     15 #include "sync/api/sync_error_factory.h"
     16 #include "sync/api/sync_error_factory_mock.h"
     17 #include "sync/protocol/sync.pb.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 using sync_pb::EntitySpecifics;
     21 using syncer::SyncData;
     22 using syncer::SyncChange;
     23 using syncer::SyncChangeList;
     24 using syncer::SyncDataList;
     25 using syncer::SYNCED_NOTIFICATION_APP_INFO;
     26 using notifier::SyncedNotificationAppInfo;
     27 using notifier::SyncedNotificationAppInfoService;
     28 using sync_pb::SyncedNotificationAppInfoSpecifics;
     29 
     30 namespace notifier {
     31 
     32 // Extract app_info id from syncer::SyncData.
     33 std::string GetAppInfoId(const SyncData& sync_data) {
     34   SyncedNotificationAppInfoSpecifics specifics =
     35       sync_data.GetSpecifics().synced_notification_app_info();
     36 
     37   // TODO(petewil): It would be better if we had a designated unique identifier
     38   // instead of relying on the display name to be unique.
     39   return specifics.synced_notification_app_info(0).settings_display_name();
     40 }
     41 
     42 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
     43 // back up to Sync.
     44 class TestChangeProcessor : public syncer::SyncChangeProcessor {
     45  public:
     46   TestChangeProcessor() {}
     47   virtual ~TestChangeProcessor() {}
     48 
     49   // Store a copy of all the changes passed in so we can examine them later.
     50   virtual syncer::SyncError ProcessSyncChanges(
     51       const tracked_objects::Location& from_here,
     52       const SyncChangeList& change_list) OVERRIDE {
     53     change_map_.clear();
     54     for (SyncChangeList::const_iterator iter = change_list.begin();
     55          iter != change_list.end();
     56          ++iter) {
     57       // Put the data into the change tracking map.
     58       change_map_[GetAppInfoId(iter->sync_data())] = *iter;
     59     }
     60 
     61     return syncer::SyncError();
     62   }
     63 
     64   virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
     65       const OVERRIDE {
     66     return syncer::SyncDataList();
     67   }
     68 
     69   size_t change_list_size() { return change_map_.size(); }
     70 
     71   bool ContainsId(const std::string& id) {
     72     return change_map_.find(id) != change_map_.end();
     73   }
     74 
     75   SyncChange GetChangeById(const std::string& id) {
     76     EXPECT_TRUE(ContainsId(id));
     77     return change_map_[id];
     78   }
     79 
     80  private:
     81   // Track the changes received in ProcessSyncChanges.
     82   std::map<std::string, SyncChange> change_map_;
     83 
     84   DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
     85 };
     86 
     87 class SyncedNotificationAppInfoServiceTest : public testing::Test {
     88 
     89  public:
     90   SyncedNotificationAppInfoServiceTest()
     91       : sync_processor_(new TestChangeProcessor),
     92         sync_processor_delegate_(
     93             new syncer::FakeSyncChangeProcessor()) {}
     94 
     95   virtual ~SyncedNotificationAppInfoServiceTest() {}
     96 
     97   // Overrides from testing::Test.
     98   virtual void SetUp() { profile_.reset(new TestingProfile()); }
     99 
    100   // Introduce some sample test data into the system.
    101   void AddTestingAppInfosToList(
    102       SyncedNotificationAppInfoService* app_info_service) {
    103     // Create the app_info struct, setting the settings display name.
    104 
    105     // The sending_service_infos_ list will take ownership of this pointer.
    106     SyncedNotificationAppInfo* test_item1 = new SyncedNotificationAppInfo(
    107         NULL, kSendingService1Name, app_info_service);
    108 
    109     // Add some App IDs.
    110     test_item1->AddAppId(kAppId1);
    111     test_item1->AddAppId(kAppId2);
    112 
    113     // Set this icon GURL.
    114     test_item1->SetSettingsURLs(GURL(kTestIconUrl), GURL());
    115 
    116     // Add to the list.
    117     app_info_service->sending_service_infos_.push_back(test_item1);
    118 
    119     // Add a second test item for another service.
    120     SyncedNotificationAppInfo* test_item2 = new SyncedNotificationAppInfo(
    121         NULL, kSendingService2Name, app_info_service);
    122 
    123     // Add some App IDs.
    124     test_item2->AddAppId(kAppId4);
    125     test_item2->AddAppId(kAppId5);
    126 
    127     // Set thi icon GURL.
    128     test_item2->SetSettingsURLs(GURL(kTestIconUrl), GURL());
    129 
    130     // Add to the list.
    131     app_info_service->sending_service_infos_.push_back(test_item2);
    132   }
    133 
    134   // Put some representative test data into the AppInfo protobuf.
    135   static void FillProtobufWithTestData1(
    136       sync_pb::SyncedNotificationAppInfo& protobuf) {
    137     protobuf.add_app_id(std::string(kAppId1));
    138     protobuf.add_app_id(std::string(kAppId2));
    139     protobuf.set_settings_display_name(kSendingService1Name);
    140     protobuf.set_info_url(kTestInfoUrl);
    141     protobuf.mutable_icon()->set_url(kTestIconUrl);
    142   }
    143 
    144   static void FillProtobufWithTestData2(
    145       sync_pb::SyncedNotificationAppInfo& protobuf) {
    146     protobuf.add_app_id(std::string(kAppId3));
    147     protobuf.set_settings_display_name(kSendingService1Name);
    148     protobuf.mutable_icon()->set_url(kTestIconUrl);
    149   }
    150 
    151   // Helper to create syncer::SyncChange.
    152   static SyncChange CreateSyncChange(SyncChange::SyncChangeType type,
    153                                      const std::string& settings_display_name,
    154                                      const std::string& info_url,
    155                                      const std::string& icon_url,
    156                                      const std::string& app_id1,
    157                                      const std::string& app_id2) {
    158 
    159     return SyncChange(
    160         FROM_HERE,
    161         type,
    162         CreateSyncData(
    163             settings_display_name, info_url, icon_url, app_id1, app_id2));
    164   }
    165 
    166   // Build a SyncData object to look like what Sync would deliver.
    167   static SyncData CreateSyncData(const std::string& settings_display_name,
    168                                  const std::string& info_url,
    169                                  const std::string& icon_url,
    170                                  const std::string& app_id1,
    171                                  const std::string& app_id2) {
    172     // CreateLocalData makes a copy of this, so it can safely live on the stack.
    173     EntitySpecifics entity_specifics;
    174     EXPECT_FALSE(app_id1.empty());
    175 
    176     sync_pb::SyncedNotificationAppInfoSpecifics* specifics =
    177         entity_specifics.mutable_synced_notification_app_info();
    178 
    179     // Add a synced_notification_app_info object.
    180     specifics->add_synced_notification_app_info();
    181     sync_pb::SyncedNotificationAppInfo* app_info =
    182         specifics->mutable_synced_notification_app_info(0);
    183 
    184     // Add the key, the settings display name.
    185     app_info->set_settings_display_name(settings_display_name);
    186 
    187     // Add the welcome notification info URL.
    188     app_info->set_info_url(info_url);
    189 
    190     // Add the icon URL.
    191     app_info->mutable_icon()->set_url(icon_url);
    192 
    193     // Add the app IDs.
    194     app_info->add_app_id(app_id1);
    195 
    196     // Only add the second if it is non-empty
    197     if (!app_id2.empty()) {
    198       app_info->add_app_id(app_id2);
    199     }
    200 
    201     // Create the sync data.
    202     SyncData sync_data =
    203         SyncData::CreateLocalData("syncer::SYNCED_NOTIFICATION_APP_INFO",
    204                                   "SyncedNotificationAppInfoServiceUnitTest",
    205                                   entity_specifics);
    206 
    207     return sync_data;
    208   }
    209 
    210   TestChangeProcessor* processor() {
    211     return static_cast<TestChangeProcessor*>(sync_processor_.get());
    212   }
    213 
    214   scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() {
    215     return sync_processor_delegate_.Pass();
    216   }
    217 
    218  protected:
    219   scoped_ptr<TestingProfile> profile_;
    220 
    221  private:
    222   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
    223   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_delegate_;
    224 
    225   DISALLOW_COPY_AND_ASSIGN(SyncedNotificationAppInfoServiceTest);
    226 };
    227 
    228 // Null data case - we have no data, and sync has no data when we start up.
    229 TEST_F(SyncedNotificationAppInfoServiceTest, MergeDataAndStartSyncingTest) {
    230     SyncedNotificationAppInfoService app_info_service(profile_.get());
    231 
    232   app_info_service.MergeDataAndStartSyncing(
    233       SYNCED_NOTIFICATION_APP_INFO,
    234       SyncDataList(),  // Empty.
    235       PassProcessor(),
    236       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
    237 
    238   EXPECT_EQ(static_cast<size_t>(0),
    239             app_info_service.sending_service_infos_size());
    240 }
    241 
    242 // Process sync changes when there is no local data.
    243 TEST_F(SyncedNotificationAppInfoServiceTest, ProcessSyncChangesEmptyModel) {
    244   // We initially have no data.
    245   SyncedNotificationAppInfoService app_info_service(profile_.get());
    246   app_info_service.set_avoid_bitmap_fetching_for_test(true);
    247 
    248   // Set up an ADD.
    249   SyncChangeList changes;
    250   changes.push_back(CreateSyncChange(SyncChange::ACTION_ADD,
    251                                      kSendingService1Name,
    252                                      kTestInfoUrl,
    253                                      kTestIconUrl,
    254                                      kAppId1,
    255                                      kAppId2));
    256 
    257   // Process the changes we built.
    258   app_info_service.ProcessSyncChanges(FROM_HERE, changes);
    259 
    260   // Verify sync change made it to the SyncedNotificationAppInfo list.
    261   SyncedNotificationAppInfo* app_info1 =
    262       app_info_service.FindSyncedNotificationAppInfoByName(
    263           kSendingService1Name);
    264   EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), app_info1);
    265   EXPECT_TRUE(app_info1->HasAppId(kAppId1));
    266   EXPECT_TRUE(app_info1->HasAppId(kAppId2));
    267   EXPECT_FALSE(app_info1->HasAppId(kAppId3));
    268   EXPECT_EQ(app_info1->settings_icon_url(), GURL(kTestIconUrl));
    269 }
    270 
    271 // Process sync changes when there is local data.
    272 TEST_F(SyncedNotificationAppInfoServiceTest, ProcessSyncChangesNonEmptyModel) {
    273     SyncedNotificationAppInfoService app_info_service(profile_.get());
    274     app_info_service.set_avoid_bitmap_fetching_for_test(true);
    275 
    276   // Create some local fake data. We rely on the specific ids set up here.
    277   AddTestingAppInfosToList(&app_info_service);
    278 
    279   // Set up an UPDATE.
    280   SyncChangeList changes;
    281 
    282   changes.push_back(CreateSyncChange(SyncChange::ACTION_UPDATE,
    283                                      kSendingService1Name,
    284                                      kTestInfoUrl,
    285                                      kTestIconUrl,
    286                                      kAppId1,
    287                                      kAppId3));
    288 
    289   // Simulate incoming changed sync data at runtime.
    290   app_info_service.ProcessSyncChanges(FROM_HERE, changes);
    291 
    292   // We should find that the first item now has a different set of app ids.
    293   SyncedNotificationAppInfo* app_info1 =
    294       app_info_service.FindSyncedNotificationAppInfoByName(
    295           kSendingService1Name);
    296   EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), app_info1);
    297   EXPECT_TRUE(app_info1->HasAppId(kAppId1));
    298   EXPECT_FALSE(app_info1->HasAppId(kAppId2));
    299   EXPECT_TRUE(app_info1->HasAppId(kAppId3));
    300   EXPECT_EQ(app_info1->settings_icon_url(), GURL(kTestIconUrl));
    301 }
    302 
    303 // Test ProcessIncomingAppInfoProtobuf with an add.
    304 TEST_F(SyncedNotificationAppInfoServiceTest,
    305        ProcessIncomingAppInfoProtobufAddTest) {
    306   // Get an app info service object.
    307   SyncedNotificationAppInfoService app_info_service(profile_.get());
    308   app_info_service.set_avoid_bitmap_fetching_for_test(true);
    309 
    310   // Get an app info protobuf.
    311   sync_pb::SyncedNotificationAppInfo protobuf;
    312   FillProtobufWithTestData1(protobuf);
    313 
    314   // Call the function we are testing.
    315   app_info_service.ProcessIncomingAppInfoProtobuf(protobuf);
    316 
    317   // Ensure that we now have an app_info in our list, and it looks like we
    318   // expect.
    319   notifier::SyncedNotificationAppInfo* found_app_info;
    320   found_app_info = app_info_service.FindSyncedNotificationAppInfoByName(
    321       kSendingService1Name);
    322   EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
    323             found_app_info);
    324   EXPECT_TRUE(found_app_info->HasAppId(kAppId1));
    325   EXPECT_TRUE(found_app_info->HasAppId(kAppId2));
    326 }
    327 
    328 // Test ProcessIncomingAppInfoProtobuf with an update
    329 TEST_F(SyncedNotificationAppInfoServiceTest,
    330        ProcessIncomingAppInfoProtobufUpdateTest) {
    331   // Get an app info service object.
    332   SyncedNotificationAppInfoService app_info_service(profile_.get());
    333   app_info_service.set_avoid_bitmap_fetching_for_test(true);
    334 
    335   // Make an app info with the same display name as the first one in the test
    336   // data.
    337   sync_pb::SyncedNotificationAppInfo protobuf1;
    338   FillProtobufWithTestData1(protobuf1);
    339   app_info_service.ProcessIncomingAppInfoProtobuf(protobuf1);
    340 
    341   // Ensure that we now have an app_info in our list, and it looks like we
    342   // expect.
    343   notifier::SyncedNotificationAppInfo* found_app_info1;
    344   found_app_info1 = app_info_service.FindSyncedNotificationAppInfoByName(
    345       kSendingService1Name);
    346   EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
    347             found_app_info1);
    348   EXPECT_TRUE(found_app_info1->HasAppId(kAppId1));
    349   EXPECT_TRUE(found_app_info1->HasAppId(kAppId2));
    350 
    351   // Make an update to the protobuf that has already been sent.
    352   app_info_service.FreeSyncedNotificationAppInfoByName(kSendingService1Name);
    353   // Change appid1 to appid3
    354   sync_pb::SyncedNotificationAppInfo protobuf2;
    355   FillProtobufWithTestData2(protobuf2);
    356   app_info_service.ProcessIncomingAppInfoProtobuf(protobuf2);
    357 
    358   // Ensure we have the same named app info as before, but it has the new
    359   // contents.
    360   notifier::SyncedNotificationAppInfo* found_app_info2;
    361   found_app_info2 = app_info_service.FindSyncedNotificationAppInfoByName(
    362       kSendingService1Name);
    363   EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
    364             found_app_info2);
    365   EXPECT_FALSE(found_app_info2->HasAppId(kAppId1));
    366   EXPECT_TRUE(found_app_info2->HasAppId(kAppId3));
    367 }
    368 
    369 // Test our function that creates a synced notification from a protobuf.
    370 TEST_F(SyncedNotificationAppInfoServiceTest,
    371        CreateSyncedNotificationAppInfoFromProtobufTest) {
    372   SyncedNotificationAppInfoService app_info_service(profile_.get());
    373   // Build a protobuf and fill it with data.
    374   sync_pb::SyncedNotificationAppInfo protobuf;
    375   FillProtobufWithTestData1(protobuf);
    376 
    377   scoped_ptr<SyncedNotificationAppInfo> app_info;
    378   app_info =
    379       app_info_service.CreateSyncedNotificationAppInfoFromProtobuf(protobuf);
    380 
    381   // Ensure the app info class has the fields we expect.
    382   EXPECT_EQ(std::string(kSendingService1Name),
    383             app_info->settings_display_name());
    384   EXPECT_EQ(GURL(kTestInfoUrl), app_info->welcome_link_url());
    385   EXPECT_TRUE(app_info->HasAppId(kAppId1));
    386   EXPECT_TRUE(app_info->HasAppId(kAppId2));
    387   EXPECT_EQ(GURL(std::string(kTestIconUrl)), app_info->settings_icon_url());
    388 }
    389 
    390 // Test our find by sending service name function.
    391 TEST_F(SyncedNotificationAppInfoServiceTest,
    392        FindSyncedNotificationAppInfoByNameTest) {
    393   SyncedNotificationAppInfoService app_info_service(profile_.get());
    394 
    395   AddTestingAppInfosToList(&app_info_service);
    396 
    397   SyncedNotificationAppInfo* found;
    398 
    399   found = app_info_service.FindSyncedNotificationAppInfoByName(
    400       kSendingService1Name);
    401 
    402   EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), found);
    403   EXPECT_EQ(std::string(kSendingService1Name), found->settings_display_name());
    404 
    405   found = app_info_service.FindSyncedNotificationAppInfoByName(
    406       kSendingService3Name);
    407   EXPECT_EQ(NULL, found);
    408 }
    409 
    410 // Test our find by AppId function.
    411 TEST_F(SyncedNotificationAppInfoServiceTest,
    412        FindSyncedNotificationAppInfoByAppIdTest) {
    413   SyncedNotificationAppInfoService app_info_service(profile_.get());
    414 
    415   AddTestingAppInfosToList(&app_info_service);
    416 
    417   SyncedNotificationAppInfo* found;
    418 
    419   found = app_info_service.FindSyncedNotificationAppInfoByAppId(kAppId1);
    420 
    421   EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), found);
    422   EXPECT_EQ(std::string(kSendingService1Name), found->settings_display_name());
    423 
    424   found = app_info_service.FindSyncedNotificationAppInfoByName(kAppId5);
    425   EXPECT_EQ(NULL, found);
    426 }
    427 
    428 // Test our find sending service name by app id function.
    429 TEST_F(SyncedNotificationAppInfoServiceTest,
    430        FindSendingServiceNameFromAppIdTest) {
    431   SyncedNotificationAppInfoService app_info_service(profile_.get());
    432 
    433   AddTestingAppInfosToList(&app_info_service);
    434 
    435   std::string found_name;
    436 
    437   found_name = app_info_service.FindSendingServiceNameFromAppId(kAppId1);
    438 
    439   EXPECT_EQ(std::string(kSendingService1Name), found_name);
    440 
    441   found_name = app_info_service.FindSendingServiceNameFromAppId(kAppId6);
    442   EXPECT_TRUE(found_name.empty());
    443 }
    444 
    445 // Test our delete function.
    446 TEST_F(SyncedNotificationAppInfoServiceTest,
    447        FreeSyncedNotificationAppInfoByNameTest) {
    448   SyncedNotificationAppInfoService app_info_service(profile_.get());
    449 
    450   AddTestingAppInfosToList(&app_info_service);
    451 
    452   SyncedNotificationAppInfo* found;
    453 
    454   app_info_service.FreeSyncedNotificationAppInfoByName(kSendingService1Name);
    455   found = app_info_service.FindSyncedNotificationAppInfoByName(
    456       kSendingService1Name);
    457   EXPECT_EQ(NULL, found);
    458 }
    459 
    460 TEST_F(SyncedNotificationAppInfoServiceTest,
    461        GetAllSendingServiceSettingsDataTest) {
    462   SyncedNotificationAppInfoService app_info_service(profile_.get());
    463 
    464   AddTestingAppInfosToList(&app_info_service);
    465 
    466   std::vector<SyncedNotificationSendingServiceSettingsData> data;
    467   data = app_info_service.GetAllSendingServiceSettingsData();
    468 
    469   EXPECT_EQ(static_cast<unsigned int>(2), data.size());
    470   EXPECT_EQ(kSendingService1Name, data[0].settings_display_name);
    471   EXPECT_EQ(kSendingService2Name, data[1].settings_display_name);
    472 }
    473 
    474 }  // namespace notifier
    475