Home | History | Annotate | Download | only in synced_notifications_private
      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/extensions/api/synced_notifications_private/synced_notifications_shim.h"
      6 
      7 #include "base/json/json_writer.h"
      8 #include "extensions/browser/event_router.h"
      9 #include "sync/api/fake_sync_change_processor.h"
     10 #include "sync/api/sync_change.h"
     11 #include "sync/api/sync_error_factory.h"
     12 #include "sync/protocol/sync.pb.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 using namespace extensions;
     16 using namespace extensions::api;
     17 
     18 namespace {
     19 
     20 // Builds a SyncData for the specified |type| based on |key|.
     21 syncer::SyncData BuildData(syncer::ModelType type, const std::string& key) {
     22   sync_pb::EntitySpecifics specifics;
     23   if (type == syncer::SYNCED_NOTIFICATIONS) {
     24     specifics.mutable_synced_notification()
     25         ->mutable_coalesced_notification()
     26         ->set_key(key);
     27   } else {
     28     specifics.mutable_synced_notification_app_info()
     29         ->add_synced_notification_app_info()
     30         ->add_app_id(key);
     31   }
     32   syncer::SyncData data = syncer::SyncData::CreateLocalData(
     33       key, key, specifics);
     34   return data;
     35 }
     36 
     37 // Builds a SyncChange with an update to the specified |type| based on |key|.
     38 syncer::SyncChange BuildChange(syncer::ModelType type, const std::string& key) {
     39   syncer::SyncChangeList change_list;
     40   syncer::SyncData data = BuildData(type, key);
     41   return syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data);
     42 }
     43 
     44 // Verifies that the specifics within |data| match the serialized specifics
     45 // within |serialized|.
     46 testing::AssertionResult DataSpecificsMatch(const syncer::SyncData& data,
     47                                             const std::string& serialized) {
     48   if (data.GetDataType() == syncer::SYNCED_NOTIFICATIONS) {
     49     const sync_pb::SyncedNotificationSpecifics& proto =
     50         data.GetSpecifics().synced_notification();
     51     if (serialized != proto.SerializeAsString())
     52       return testing::AssertionFailure() << "Notification specifics mismatch";
     53   } else {
     54     const sync_pb::SyncedNotificationAppInfoSpecifics& proto =
     55         data.GetSpecifics().synced_notification_app_info();
     56     if (serialized != proto.SerializeAsString())
     57       return testing::AssertionFailure() << "App info specifics mismatch";
     58   }
     59   return testing::AssertionSuccess();
     60 }
     61 
     62 // Verifies that the update within |change| matchs the serialized specifics
     63 // within |serialized|.
     64 testing::AssertionResult ChangeSpecificsMatch(const syncer::SyncChange& change,
     65                                               const std::string& serialized) {
     66   if (change.change_type() != syncer::SyncChange::ACTION_UPDATE)
     67     return testing::AssertionFailure() << "Invalid change type";
     68   return DataSpecificsMatch(change.sync_data(), serialized);
     69 }
     70 
     71 class SyncedNotificationsShimTest : public testing::Test {
     72  public:
     73   SyncedNotificationsShimTest();
     74   virtual ~SyncedNotificationsShimTest();
     75 
     76   // Starts sync for both sync types.
     77   void StartSync();
     78   // Starts sync for the specified datatype |type|.
     79   void StartSync(syncer::ModelType type);
     80 
     81   // Transfers ownership of the last event received.
     82   scoped_ptr<Event> GetLastEvent();
     83 
     84   SyncedNotificationsShim* shim() { return &shim_; }
     85   syncer::FakeSyncChangeProcessor* notification_processor() {
     86     return notification_processor_;
     87   }
     88   syncer::FakeSyncChangeProcessor* app_info_processor() {
     89     return app_info_processor_;
     90   }
     91 
     92  private:
     93   void EventCallback(scoped_ptr<Event> event);
     94 
     95   // Shim being tested.
     96   SyncedNotificationsShim shim_;
     97 
     98   syncer::FakeSyncChangeProcessor* notification_processor_;
     99   syncer::FakeSyncChangeProcessor* app_info_processor_;
    100 
    101   // The last event fired by the shim.
    102   scoped_ptr<Event> last_event_fired_;
    103 };
    104 
    105 SyncedNotificationsShimTest::SyncedNotificationsShimTest()
    106     : shim_(base::Bind(&SyncedNotificationsShimTest::EventCallback,
    107                        base::Unretained(this))),
    108       notification_processor_(NULL),
    109       app_info_processor_(NULL) {}
    110 
    111 SyncedNotificationsShimTest::~SyncedNotificationsShimTest() {}
    112 
    113 void SyncedNotificationsShimTest::EventCallback(scoped_ptr<Event> event) {
    114   ASSERT_FALSE(last_event_fired_);
    115   last_event_fired_ = event.Pass();
    116 }
    117 
    118 scoped_ptr<Event> SyncedNotificationsShimTest::GetLastEvent() {
    119   return last_event_fired_.Pass();
    120 }
    121 
    122 void SyncedNotificationsShimTest::StartSync() {
    123   StartSync(syncer::SYNCED_NOTIFICATIONS);
    124   StartSync(syncer::SYNCED_NOTIFICATION_APP_INFO);
    125   GetLastEvent();
    126 }
    127 
    128 void SyncedNotificationsShimTest::StartSync(syncer::ModelType type) {
    129   scoped_ptr<syncer::FakeSyncChangeProcessor> change_processor(
    130       new syncer::FakeSyncChangeProcessor());
    131   if (type == syncer::SYNCED_NOTIFICATIONS)
    132     notification_processor_ = change_processor.get();
    133   else
    134     app_info_processor_ = change_processor.get();
    135   syncer::SyncDataList sync_data;
    136   shim_.MergeDataAndStartSyncing(
    137       type,
    138       sync_data,
    139       change_processor.PassAs<syncer::SyncChangeProcessor>(),
    140       scoped_ptr<syncer::SyncErrorFactory>());
    141 }
    142 
    143 // Starting sync should fire the sync started event, but only after both types
    144 // have started.
    145 TEST_F(SyncedNotificationsShimTest, StartSync) {
    146   EXPECT_FALSE(shim()->IsSyncReady());
    147   StartSync(syncer::SYNCED_NOTIFICATIONS);
    148   EXPECT_FALSE(shim()->IsSyncReady());
    149   EXPECT_FALSE(GetLastEvent());
    150 
    151   StartSync(syncer::SYNCED_NOTIFICATION_APP_INFO);
    152   EXPECT_TRUE(shim()->IsSyncReady());
    153 
    154   scoped_ptr<Event> event = GetLastEvent();
    155   ASSERT_TRUE(event);
    156   EXPECT_EQ(synced_notifications_private::OnSyncStartup::kEventName,
    157             event->event_name);
    158 
    159   EXPECT_TRUE(notification_processor()->changes().empty());
    160   EXPECT_TRUE(app_info_processor()->changes().empty());
    161 }
    162 
    163 // A sync update should fire the OnDataChanges event with the updated
    164 // notification.
    165 TEST_F(SyncedNotificationsShimTest, ProcessSyncChangesSingleNotification) {
    166   StartSync();
    167   syncer::SyncChangeList change_list;
    168   change_list.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS, "key"));
    169   shim()->ProcessSyncChanges(FROM_HERE, change_list);
    170   scoped_ptr<Event> event = GetLastEvent();
    171   ASSERT_TRUE(event);
    172   EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName,
    173             event->event_name);
    174   ASSERT_TRUE(event->event_args);
    175   EXPECT_EQ(1U, event->event_args->GetSize());
    176 
    177   base::ListValue* args = NULL;
    178   ASSERT_TRUE(event->event_args->GetList(0, &args));
    179   EXPECT_EQ(1U, args->GetSize());
    180   base::DictionaryValue* sync_change_value = NULL;
    181   ASSERT_TRUE(args->GetDictionary(0, &sync_change_value));
    182   scoped_ptr<synced_notifications_private::SyncChange> sync_change =
    183       synced_notifications_private::SyncChange::FromValue(*sync_change_value);
    184   ASSERT_TRUE(sync_change);
    185   EXPECT_TRUE(ChangeSpecificsMatch(change_list[0],
    186                                    sync_change->data.data_item));
    187   EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED,
    188             sync_change->change_type);
    189 }
    190 
    191 // Verify that multiple notification updates can be sent in one event.
    192 TEST_F(SyncedNotificationsShimTest, ProcessSyncChangesMultipleNotification) {
    193   StartSync();
    194   syncer::SyncChangeList change_list;
    195   change_list.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS, "key"));
    196   change_list.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS, "key2"));
    197   shim()->ProcessSyncChanges(FROM_HERE, change_list);
    198   scoped_ptr<Event> event = GetLastEvent();
    199   ASSERT_TRUE(event);
    200   EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName,
    201             event->event_name);
    202   ASSERT_TRUE(event->event_args);
    203   base::ListValue* args = NULL;
    204   ASSERT_TRUE(event->event_args->GetList(0, &args));
    205   EXPECT_EQ(2U, args->GetSize());
    206 
    207   base::DictionaryValue* sync_change_value = NULL;
    208   ASSERT_TRUE(args->GetDictionary(0, &sync_change_value));
    209   scoped_ptr<synced_notifications_private::SyncChange> sync_change =
    210       synced_notifications_private::SyncChange::FromValue(*sync_change_value);
    211   ASSERT_TRUE(sync_change);
    212   EXPECT_TRUE(ChangeSpecificsMatch(change_list[0],
    213                                    sync_change->data.data_item));
    214   EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED,
    215             sync_change->change_type);
    216 
    217   ASSERT_TRUE(args->GetDictionary(1, &sync_change_value));
    218   sync_change =
    219       synced_notifications_private::SyncChange::FromValue(*sync_change_value);
    220   ASSERT_TRUE(sync_change);
    221   EXPECT_TRUE(ChangeSpecificsMatch(change_list[1],
    222                                    sync_change->data.data_item));
    223   EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED,
    224             sync_change->change_type);
    225 }
    226 
    227 // Verify AppInfo updates trigger OnDataChanges events.
    228 TEST_F(SyncedNotificationsShimTest, ProcessSyncChangeAppInfo) {
    229   StartSync();
    230   syncer::SyncChangeList change_list;
    231   change_list.push_back(
    232       BuildChange(syncer::SYNCED_NOTIFICATION_APP_INFO, "key"));
    233   shim()->ProcessSyncChanges(FROM_HERE, change_list);
    234   scoped_ptr<Event> event = GetLastEvent();
    235   ASSERT_TRUE(event);
    236   EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName,
    237             event->event_name);
    238   ASSERT_TRUE(event->event_args);
    239   EXPECT_EQ(1U, event->event_args->GetSize());
    240 
    241   base::ListValue* args = NULL;
    242   ASSERT_TRUE(event->event_args->GetList(0, &args));
    243   EXPECT_EQ(1U, args->GetSize());
    244   base::DictionaryValue* sync_change_value = NULL;
    245   ASSERT_TRUE(args->GetDictionary(0, &sync_change_value));
    246   scoped_ptr<synced_notifications_private::SyncChange> sync_change =
    247       synced_notifications_private::SyncChange::FromValue(*sync_change_value);
    248   ASSERT_TRUE(sync_change);
    249   EXPECT_TRUE(ChangeSpecificsMatch(change_list[0],
    250                                    sync_change->data.data_item));
    251   EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED,
    252             sync_change->change_type);
    253 }
    254 
    255 // Attempt to get the initial sync data both before and after sync starts.
    256 TEST_F(SyncedNotificationsShimTest, GetInitialData) {
    257   std::vector<linked_ptr<synced_notifications_private::SyncData> > data;
    258   EXPECT_FALSE(shim()->GetInitialData(
    259       synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION, &data));
    260   EXPECT_FALSE(shim()->GetInitialData(
    261       synced_notifications_private::SYNC_DATA_TYPE_APP_INFO, &data));
    262 
    263   StartSync();
    264 
    265   EXPECT_TRUE(shim()->GetInitialData(
    266       synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION, &data));
    267   EXPECT_TRUE(data.empty());
    268   EXPECT_TRUE(shim()->GetInitialData(
    269       synced_notifications_private::SYNC_DATA_TYPE_APP_INFO, &data));
    270   EXPECT_TRUE(data.empty());
    271 
    272   notification_processor()->data().push_back(BuildData(
    273       syncer::SYNCED_NOTIFICATIONS, "notif_key"));
    274   EXPECT_TRUE(shim()->GetInitialData(
    275       synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION, &data));
    276   EXPECT_EQ(1U, data.size());
    277   EXPECT_TRUE(DataSpecificsMatch(notification_processor()->data()[0],
    278                                  data[0]->data_item));
    279 
    280   data.clear();
    281   app_info_processor()->data().push_back(BuildData(
    282       syncer::SYNCED_NOTIFICATION_APP_INFO, "app_key"));
    283   EXPECT_TRUE(shim()->GetInitialData(
    284       synced_notifications_private::SYNC_DATA_TYPE_APP_INFO, &data));
    285   EXPECT_EQ(1U, data.size());
    286   EXPECT_TRUE(DataSpecificsMatch(app_info_processor()->data()[0],
    287                                  data[0]->data_item));
    288 }
    289 
    290 // Verify that notification updates are properly handled.
    291 TEST_F(SyncedNotificationsShimTest, UpdateNotification) {
    292   syncer::SyncData data =
    293       BuildData(syncer::SYNCED_NOTIFICATIONS, "notif_key");
    294   std::string serialized =
    295       data.GetSpecifics().synced_notification().SerializeAsString();
    296   EXPECT_FALSE(shim()->UpdateNotification(serialized));
    297 
    298   StartSync();
    299 
    300   EXPECT_FALSE(shim()->UpdateNotification("gibberish"));
    301   EXPECT_TRUE(notification_processor()->changes().empty());
    302 
    303   EXPECT_TRUE(shim()->UpdateNotification(serialized));
    304   EXPECT_EQ(1U, notification_processor()->changes().size());
    305   EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
    306             notification_processor()->changes()[0].change_type());
    307   EXPECT_EQ(syncer::SYNCED_NOTIFICATIONS,
    308             notification_processor()->changes()[0].sync_data().GetDataType());
    309   EXPECT_EQ(serialized,
    310             notification_processor()
    311                 ->changes()[0]
    312                 .sync_data()
    313                 .GetSpecifics()
    314                 .synced_notification()
    315                 .SerializeAsString());
    316 }
    317 
    318 // Verify that SetRenderContext updates the datatype context properly.
    319 TEST_F(SyncedNotificationsShimTest, SetRenderContext) {
    320   const std::string kContext = "context";
    321   EXPECT_FALSE(shim()->SetRenderContext(
    322       synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED, kContext));
    323 
    324   StartSync();
    325 
    326   EXPECT_TRUE(shim()->SetRenderContext(
    327       synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED, kContext));
    328   EXPECT_EQ(kContext, notification_processor()->context());
    329 }
    330 
    331 }  // namespace
    332