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.
5 #include "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service.h"
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"
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;
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();
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();
42 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
44 class TestChangeProcessor : public syncer::SyncChangeProcessor {
46 TestChangeProcessor() {}
47 virtual ~TestChangeProcessor() {}
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 {
54 for (SyncChangeList::const_iterator iter = change_list.begin();
55 iter != change_list.end();
57 // Put the data into the change tracking map.
58 change_map_[GetAppInfoId(iter->sync_data())] = *iter;
61 return syncer::SyncError();
64 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
66 return syncer::SyncDataList();
69 size_t change_list_size() { return change_map_.size(); }
71 bool ContainsId(const std::string& id) {
72 return change_map_.find(id) != change_map_.end();
75 SyncChange GetChangeById(const std::string& id) {
76 EXPECT_TRUE(ContainsId(id));
77 return change_map_[id];
81 // Track the changes received in ProcessSyncChanges.
82 std::map<std::string, SyncChange> change_map_;
84 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
87 class SyncedNotificationAppInfoServiceTest : public testing::Test {
90 SyncedNotificationAppInfoServiceTest()
91 : sync_processor_(new TestChangeProcessor),
92 sync_processor_delegate_(
93 new syncer::FakeSyncChangeProcessor()) {}
95 virtual ~SyncedNotificationAppInfoServiceTest() {}
97 // Overrides from testing::Test.
98 virtual void SetUp() { profile_.reset(new TestingProfile()); }
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.
105 // The sending_service_infos_ list will take ownership of this pointer.
106 SyncedNotificationAppInfo* test_item1 = new SyncedNotificationAppInfo(
107 NULL, kSendingService1Name, app_info_service);
110 test_item1->AddAppId(kAppId1);
111 test_item1->AddAppId(kAppId2);
113 // Set this icon GURL.
114 test_item1->SetSettingsURLs(GURL(kTestIconUrl), GURL());
117 app_info_service->sending_service_infos_.push_back(test_item1);
119 // Add a second test item for another service.
120 SyncedNotificationAppInfo* test_item2 = new SyncedNotificationAppInfo(
121 NULL, kSendingService2Name, app_info_service);
124 test_item2->AddAppId(kAppId4);
125 test_item2->AddAppId(kAppId5);
127 // Set thi icon GURL.
128 test_item2->SetSettingsURLs(GURL(kTestIconUrl), GURL());
131 app_info_service->sending_service_infos_.push_back(test_item2);
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);
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);
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) {
163 settings_display_name, info_url, icon_url, app_id1, app_id2));
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());
176 sync_pb::SyncedNotificationAppInfoSpecifics* specifics =
177 entity_specifics.mutable_synced_notification_app_info();
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);
184 // Add the key, the settings display name.
185 app_info->set_settings_display_name(settings_display_name);
187 // Add the welcome notification info URL.
188 app_info->set_info_url(info_url);
191 app_info->mutable_icon()->set_url(icon_url);
194 app_info->add_app_id(app_id1);
196 // Only add the second if it is non-empty
197 if (!app_id2.empty()) {
198 app_info->add_app_id(app_id2);
201 // Create the sync data.
203 SyncData::CreateLocalData("syncer::SYNCED_NOTIFICATION_APP_INFO",
204 "SyncedNotificationAppInfoServiceUnitTest",
210 TestChangeProcessor* processor() {
211 return static_cast<TestChangeProcessor*>(sync_processor_.get());
214 scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() {
215 return sync_processor_delegate_.Pass();
219 scoped_ptr<TestingProfile> profile_;
222 scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
223 scoped_ptr<syncer::SyncChangeProcessor> sync_processor_delegate_;
225 DISALLOW_COPY_AND_ASSIGN(SyncedNotificationAppInfoServiceTest);
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());
232 app_info_service.MergeDataAndStartSyncing(
233 SYNCED_NOTIFICATION_APP_INFO,
234 SyncDataList(), // Empty.
236 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
238 EXPECT_EQ(static_cast<size_t>(0),
239 app_info_service.sending_service_infos_size());
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);
249 SyncChangeList changes;
250 changes.push_back(CreateSyncChange(SyncChange::ACTION_ADD,
251 kSendingService1Name,
257 // Process the changes we built.
258 app_info_service.ProcessSyncChanges(FROM_HERE, changes);
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));
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);
276 // Create some local fake data. We rely on the specific ids set up here.
277 AddTestingAppInfosToList(&app_info_service);
280 SyncChangeList changes;
282 changes.push_back(CreateSyncChange(SyncChange::ACTION_UPDATE,
283 kSendingService1Name,
289 // Simulate incoming changed sync data at runtime.
290 app_info_service.ProcessSyncChanges(FROM_HERE, changes);
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));
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);
310 // Get an app info protobuf.
311 sync_pb::SyncedNotificationAppInfo protobuf;
312 FillProtobufWithTestData1(protobuf);
314 // Call the function we are testing.
315 app_info_service.ProcessIncomingAppInfoProtobuf(protobuf);
317 // Ensure that we now have an app_info in our list, and it looks like we
319 notifier::SyncedNotificationAppInfo* found_app_info;
320 found_app_info = app_info_service.FindSyncedNotificationAppInfoByName(
321 kSendingService1Name);
322 EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
324 EXPECT_TRUE(found_app_info->HasAppId(kAppId1));
325 EXPECT_TRUE(found_app_info->HasAppId(kAppId2));
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);
335 // Make an app info with the same display name as the first one in the test
337 sync_pb::SyncedNotificationAppInfo protobuf1;
338 FillProtobufWithTestData1(protobuf1);
339 app_info_service.ProcessIncomingAppInfoProtobuf(protobuf1);
341 // Ensure that we now have an app_info in our list, and it looks like we
343 notifier::SyncedNotificationAppInfo* found_app_info1;
344 found_app_info1 = app_info_service.FindSyncedNotificationAppInfoByName(
345 kSendingService1Name);
346 EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
348 EXPECT_TRUE(found_app_info1->HasAppId(kAppId1));
349 EXPECT_TRUE(found_app_info1->HasAppId(kAppId2));
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);
358 // Ensure we have the same named app info as before, but it has the new
360 notifier::SyncedNotificationAppInfo* found_app_info2;
361 found_app_info2 = app_info_service.FindSyncedNotificationAppInfoByName(
362 kSendingService1Name);
363 EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
365 EXPECT_FALSE(found_app_info2->HasAppId(kAppId1));
366 EXPECT_TRUE(found_app_info2->HasAppId(kAppId3));
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);
377 scoped_ptr<SyncedNotificationAppInfo> app_info;
379 app_info_service.CreateSyncedNotificationAppInfoFromProtobuf(protobuf);
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());
390 // Test our find by sending service name function.
391 TEST_F(SyncedNotificationAppInfoServiceTest,
392 FindSyncedNotificationAppInfoByNameTest) {
393 SyncedNotificationAppInfoService app_info_service(profile_.get());
395 AddTestingAppInfosToList(&app_info_service);
397 SyncedNotificationAppInfo* found;
399 found = app_info_service.FindSyncedNotificationAppInfoByName(
400 kSendingService1Name);
402 EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), found);
403 EXPECT_EQ(std::string(kSendingService1Name), found->settings_display_name());
405 found = app_info_service.FindSyncedNotificationAppInfoByName(
406 kSendingService3Name);
407 EXPECT_EQ(NULL, found);
410 // Test our find by AppId function.
411 TEST_F(SyncedNotificationAppInfoServiceTest,
412 FindSyncedNotificationAppInfoByAppIdTest) {
413 SyncedNotificationAppInfoService app_info_service(profile_.get());
415 AddTestingAppInfosToList(&app_info_service);
417 SyncedNotificationAppInfo* found;
419 found = app_info_service.FindSyncedNotificationAppInfoByAppId(kAppId1);
421 EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), found);
422 EXPECT_EQ(std::string(kSendingService1Name), found->settings_display_name());
424 found = app_info_service.FindSyncedNotificationAppInfoByName(kAppId5);
425 EXPECT_EQ(NULL, found);
428 // Test our find sending service name by app id function.
429 TEST_F(SyncedNotificationAppInfoServiceTest,
430 FindSendingServiceNameFromAppIdTest) {
431 SyncedNotificationAppInfoService app_info_service(profile_.get());
433 AddTestingAppInfosToList(&app_info_service);
435 std::string found_name;
437 found_name = app_info_service.FindSendingServiceNameFromAppId(kAppId1);
439 EXPECT_EQ(std::string(kSendingService1Name), found_name);
441 found_name = app_info_service.FindSendingServiceNameFromAppId(kAppId6);
442 EXPECT_TRUE(found_name.empty());
445 // Test our delete function.
446 TEST_F(SyncedNotificationAppInfoServiceTest,
447 FreeSyncedNotificationAppInfoByNameTest) {
448 SyncedNotificationAppInfoService app_info_service(profile_.get());
450 AddTestingAppInfosToList(&app_info_service);
452 SyncedNotificationAppInfo* found;
454 app_info_service.FreeSyncedNotificationAppInfoByName(kSendingService1Name);
455 found = app_info_service.FindSyncedNotificationAppInfoByName(
456 kSendingService1Name);
457 EXPECT_EQ(NULL, found);
460 TEST_F(SyncedNotificationAppInfoServiceTest,
461 GetAllSendingServiceSettingsDataTest) {
462 SyncedNotificationAppInfoService app_info_service(profile_.get());
464 AddTestingAppInfosToList(&app_info_service);
466 std::vector<SyncedNotificationSendingServiceSettingsData> data;
467 data = app_info_service.GetAllSendingServiceSettingsData();
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);
474 } // namespace notifier