| OLD | NEW |
| (Empty) |
| 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_noti
fications_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 ~SyncedNotificationsShimTest() override; | |
| 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 // Records that a refresh has been requested. | |
| 85 void RequestRefresh(); | |
| 86 | |
| 87 SyncedNotificationsShim* shim() { return &shim_; } | |
| 88 syncer::FakeSyncChangeProcessor* notification_processor() { | |
| 89 return notification_processor_; | |
| 90 } | |
| 91 syncer::FakeSyncChangeProcessor* app_info_processor() { | |
| 92 return app_info_processor_; | |
| 93 } | |
| 94 bool refresh_requested() const { return refresh_requested_; } | |
| 95 | |
| 96 private: | |
| 97 void EventCallback(scoped_ptr<Event> event); | |
| 98 | |
| 99 // Shim being tested. | |
| 100 SyncedNotificationsShim shim_; | |
| 101 | |
| 102 syncer::FakeSyncChangeProcessor* notification_processor_; | |
| 103 syncer::FakeSyncChangeProcessor* app_info_processor_; | |
| 104 | |
| 105 // The last event fired by the shim. | |
| 106 scoped_ptr<Event> last_event_fired_; | |
| 107 | |
| 108 // Whether a refresh has been requested; | |
| 109 bool refresh_requested_; | |
| 110 }; | |
| 111 | |
| 112 SyncedNotificationsShimTest::SyncedNotificationsShimTest() | |
| 113 : shim_(base::Bind(&SyncedNotificationsShimTest::EventCallback, | |
| 114 base::Unretained(this)), | |
| 115 base::Bind(&SyncedNotificationsShimTest::RequestRefresh, | |
| 116 base::Unretained(this))), | |
| 117 notification_processor_(NULL), | |
| 118 app_info_processor_(NULL), | |
| 119 refresh_requested_(false) {} | |
| 120 | |
| 121 SyncedNotificationsShimTest::~SyncedNotificationsShimTest() {} | |
| 122 | |
| 123 void SyncedNotificationsShimTest::EventCallback(scoped_ptr<Event> event) { | |
| 124 ASSERT_FALSE(last_event_fired_); | |
| 125 last_event_fired_ = event.Pass(); | |
| 126 } | |
| 127 | |
| 128 void SyncedNotificationsShimTest::RequestRefresh() { | |
| 129 ASSERT_FALSE(refresh_requested_); | |
| 130 refresh_requested_ = true; | |
| 131 } | |
| 132 | |
| 133 scoped_ptr<Event> SyncedNotificationsShimTest::GetLastEvent() { | |
| 134 return last_event_fired_.Pass(); | |
| 135 } | |
| 136 | |
| 137 void SyncedNotificationsShimTest::StartSync() { | |
| 138 StartSync(syncer::SYNCED_NOTIFICATIONS); | |
| 139 StartSync(syncer::SYNCED_NOTIFICATION_APP_INFO); | |
| 140 GetLastEvent(); | |
| 141 } | |
| 142 | |
| 143 void SyncedNotificationsShimTest::StartSync(syncer::ModelType type) { | |
| 144 scoped_ptr<syncer::FakeSyncChangeProcessor> change_processor( | |
| 145 new syncer::FakeSyncChangeProcessor()); | |
| 146 if (type == syncer::SYNCED_NOTIFICATIONS) | |
| 147 notification_processor_ = change_processor.get(); | |
| 148 else | |
| 149 app_info_processor_ = change_processor.get(); | |
| 150 syncer::SyncDataList sync_data; | |
| 151 shim_.MergeDataAndStartSyncing( | |
| 152 type, sync_data, change_processor.Pass(), nullptr); | |
| 153 } | |
| 154 | |
| 155 // Starting sync should fire the sync started event, but only after both types | |
| 156 // have started. | |
| 157 TEST_F(SyncedNotificationsShimTest, StartSync) { | |
| 158 EXPECT_FALSE(shim()->IsSyncReady()); | |
| 159 StartSync(syncer::SYNCED_NOTIFICATIONS); | |
| 160 EXPECT_FALSE(shim()->IsSyncReady()); | |
| 161 EXPECT_FALSE(GetLastEvent()); | |
| 162 | |
| 163 StartSync(syncer::SYNCED_NOTIFICATION_APP_INFO); | |
| 164 EXPECT_TRUE(shim()->IsSyncReady()); | |
| 165 | |
| 166 scoped_ptr<Event> event = GetLastEvent(); | |
| 167 ASSERT_TRUE(event); | |
| 168 EXPECT_EQ(synced_notifications_private::OnSyncStartup::kEventName, | |
| 169 event->event_name); | |
| 170 | |
| 171 EXPECT_TRUE(notification_processor()->changes().empty()); | |
| 172 EXPECT_TRUE(app_info_processor()->changes().empty()); | |
| 173 } | |
| 174 | |
| 175 // A sync update should fire the OnDataChanges event with the updated | |
| 176 // notification. | |
| 177 TEST_F(SyncedNotificationsShimTest, ProcessSyncChangesSingleNotification) { | |
| 178 StartSync(); | |
| 179 syncer::SyncChangeList change_list; | |
| 180 change_list.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS, "key")); | |
| 181 shim()->ProcessSyncChanges(FROM_HERE, change_list); | |
| 182 scoped_ptr<Event> event = GetLastEvent(); | |
| 183 ASSERT_TRUE(event); | |
| 184 EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName, | |
| 185 event->event_name); | |
| 186 ASSERT_TRUE(event->event_args); | |
| 187 EXPECT_EQ(1U, event->event_args->GetSize()); | |
| 188 | |
| 189 base::ListValue* args = NULL; | |
| 190 ASSERT_TRUE(event->event_args->GetList(0, &args)); | |
| 191 EXPECT_EQ(1U, args->GetSize()); | |
| 192 base::DictionaryValue* sync_change_value = NULL; | |
| 193 ASSERT_TRUE(args->GetDictionary(0, &sync_change_value)); | |
| 194 scoped_ptr<synced_notifications_private::SyncChange> sync_change = | |
| 195 synced_notifications_private::SyncChange::FromValue(*sync_change_value); | |
| 196 ASSERT_TRUE(sync_change); | |
| 197 EXPECT_TRUE(ChangeSpecificsMatch(change_list[0], | |
| 198 sync_change->data.data_item)); | |
| 199 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED, | |
| 200 sync_change->change_type); | |
| 201 } | |
| 202 | |
| 203 // Verify that multiple notification updates can be sent in one event. | |
| 204 TEST_F(SyncedNotificationsShimTest, ProcessSyncChangesMultipleNotification) { | |
| 205 StartSync(); | |
| 206 syncer::SyncChangeList change_list; | |
| 207 change_list.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS, "key")); | |
| 208 change_list.push_back(BuildChange(syncer::SYNCED_NOTIFICATIONS, "key2")); | |
| 209 shim()->ProcessSyncChanges(FROM_HERE, change_list); | |
| 210 scoped_ptr<Event> event = GetLastEvent(); | |
| 211 ASSERT_TRUE(event); | |
| 212 EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName, | |
| 213 event->event_name); | |
| 214 ASSERT_TRUE(event->event_args); | |
| 215 base::ListValue* args = NULL; | |
| 216 ASSERT_TRUE(event->event_args->GetList(0, &args)); | |
| 217 EXPECT_EQ(2U, args->GetSize()); | |
| 218 | |
| 219 base::DictionaryValue* sync_change_value = NULL; | |
| 220 ASSERT_TRUE(args->GetDictionary(0, &sync_change_value)); | |
| 221 scoped_ptr<synced_notifications_private::SyncChange> sync_change = | |
| 222 synced_notifications_private::SyncChange::FromValue(*sync_change_value); | |
| 223 ASSERT_TRUE(sync_change); | |
| 224 EXPECT_TRUE(ChangeSpecificsMatch(change_list[0], | |
| 225 sync_change->data.data_item)); | |
| 226 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED, | |
| 227 sync_change->change_type); | |
| 228 | |
| 229 ASSERT_TRUE(args->GetDictionary(1, &sync_change_value)); | |
| 230 sync_change = | |
| 231 synced_notifications_private::SyncChange::FromValue(*sync_change_value); | |
| 232 ASSERT_TRUE(sync_change); | |
| 233 EXPECT_TRUE(ChangeSpecificsMatch(change_list[1], | |
| 234 sync_change->data.data_item)); | |
| 235 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED, | |
| 236 sync_change->change_type); | |
| 237 } | |
| 238 | |
| 239 // Verify AppInfo updates trigger OnDataChanges events. | |
| 240 TEST_F(SyncedNotificationsShimTest, ProcessSyncChangeAppInfo) { | |
| 241 StartSync(); | |
| 242 syncer::SyncChangeList change_list; | |
| 243 change_list.push_back( | |
| 244 BuildChange(syncer::SYNCED_NOTIFICATION_APP_INFO, "key")); | |
| 245 shim()->ProcessSyncChanges(FROM_HERE, change_list); | |
| 246 scoped_ptr<Event> event = GetLastEvent(); | |
| 247 ASSERT_TRUE(event); | |
| 248 EXPECT_EQ(synced_notifications_private::OnDataChanges::kEventName, | |
| 249 event->event_name); | |
| 250 ASSERT_TRUE(event->event_args); | |
| 251 EXPECT_EQ(1U, event->event_args->GetSize()); | |
| 252 | |
| 253 base::ListValue* args = NULL; | |
| 254 ASSERT_TRUE(event->event_args->GetList(0, &args)); | |
| 255 EXPECT_EQ(1U, args->GetSize()); | |
| 256 base::DictionaryValue* sync_change_value = NULL; | |
| 257 ASSERT_TRUE(args->GetDictionary(0, &sync_change_value)); | |
| 258 scoped_ptr<synced_notifications_private::SyncChange> sync_change = | |
| 259 synced_notifications_private::SyncChange::FromValue(*sync_change_value); | |
| 260 ASSERT_TRUE(sync_change); | |
| 261 EXPECT_TRUE(ChangeSpecificsMatch(change_list[0], | |
| 262 sync_change->data.data_item)); | |
| 263 EXPECT_EQ(synced_notifications_private::CHANGE_TYPE_UPDATED, | |
| 264 sync_change->change_type); | |
| 265 } | |
| 266 | |
| 267 // Attempt to get the initial sync data both before and after sync starts. | |
| 268 TEST_F(SyncedNotificationsShimTest, GetInitialData) { | |
| 269 std::vector<linked_ptr<synced_notifications_private::SyncData> > data; | |
| 270 EXPECT_FALSE(shim()->GetInitialData( | |
| 271 synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION, &data)); | |
| 272 EXPECT_FALSE(shim()->GetInitialData( | |
| 273 synced_notifications_private::SYNC_DATA_TYPE_APP_INFO, &data)); | |
| 274 | |
| 275 StartSync(); | |
| 276 | |
| 277 EXPECT_TRUE(shim()->GetInitialData( | |
| 278 synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION, &data)); | |
| 279 EXPECT_TRUE(data.empty()); | |
| 280 EXPECT_TRUE(shim()->GetInitialData( | |
| 281 synced_notifications_private::SYNC_DATA_TYPE_APP_INFO, &data)); | |
| 282 EXPECT_TRUE(data.empty()); | |
| 283 | |
| 284 notification_processor()->data().push_back(BuildData( | |
| 285 syncer::SYNCED_NOTIFICATIONS, "notif_key")); | |
| 286 EXPECT_TRUE(shim()->GetInitialData( | |
| 287 synced_notifications_private::SYNC_DATA_TYPE_SYNCED_NOTIFICATION, &data)); | |
| 288 EXPECT_EQ(1U, data.size()); | |
| 289 EXPECT_TRUE(DataSpecificsMatch(notification_processor()->data()[0], | |
| 290 data[0]->data_item)); | |
| 291 | |
| 292 data.clear(); | |
| 293 app_info_processor()->data().push_back(BuildData( | |
| 294 syncer::SYNCED_NOTIFICATION_APP_INFO, "app_key")); | |
| 295 EXPECT_TRUE(shim()->GetInitialData( | |
| 296 synced_notifications_private::SYNC_DATA_TYPE_APP_INFO, &data)); | |
| 297 EXPECT_EQ(1U, data.size()); | |
| 298 EXPECT_TRUE(DataSpecificsMatch(app_info_processor()->data()[0], | |
| 299 data[0]->data_item)); | |
| 300 } | |
| 301 | |
| 302 // Verify that notification updates are properly handled. | |
| 303 TEST_F(SyncedNotificationsShimTest, UpdateNotification) { | |
| 304 syncer::SyncData data = | |
| 305 BuildData(syncer::SYNCED_NOTIFICATIONS, "notif_key"); | |
| 306 std::string serialized = | |
| 307 data.GetSpecifics().synced_notification().SerializeAsString(); | |
| 308 EXPECT_FALSE(shim()->UpdateNotification(serialized)); | |
| 309 | |
| 310 StartSync(); | |
| 311 | |
| 312 EXPECT_FALSE(shim()->UpdateNotification("gibberish")); | |
| 313 EXPECT_TRUE(notification_processor()->changes().empty()); | |
| 314 | |
| 315 EXPECT_TRUE(shim()->UpdateNotification(serialized)); | |
| 316 EXPECT_EQ(1U, notification_processor()->changes().size()); | |
| 317 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, | |
| 318 notification_processor()->changes()[0].change_type()); | |
| 319 EXPECT_EQ(syncer::SYNCED_NOTIFICATIONS, | |
| 320 notification_processor()->changes()[0].sync_data().GetDataType()); | |
| 321 EXPECT_EQ(serialized, | |
| 322 notification_processor() | |
| 323 ->changes()[0] | |
| 324 .sync_data() | |
| 325 .GetSpecifics() | |
| 326 .synced_notification() | |
| 327 .SerializeAsString()); | |
| 328 } | |
| 329 | |
| 330 // Verify that SetRenderContext updates the datatype context properly. | |
| 331 TEST_F(SyncedNotificationsShimTest, SetRenderContext) { | |
| 332 const std::string kContext = "context"; | |
| 333 EXPECT_FALSE(shim()->SetRenderContext( | |
| 334 synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED, kContext)); | |
| 335 EXPECT_FALSE(refresh_requested()); | |
| 336 | |
| 337 StartSync(); | |
| 338 | |
| 339 EXPECT_TRUE(shim()->SetRenderContext( | |
| 340 synced_notifications_private::REFRESH_REQUEST_REFRESH_NEEDED, kContext)); | |
| 341 EXPECT_EQ(kContext, notification_processor()->context()); | |
| 342 EXPECT_TRUE(refresh_requested()); | |
| 343 } | |
| 344 | |
| 345 } // namespace | |
| OLD | NEW |