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.
GetNotificationId(const SyncData & sync_data)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:
TestChangeProcessor()66 TestChangeProcessor() { }
~TestChangeProcessor()67 virtual ~TestChangeProcessor() { }
68
69 // Store a copy of all the changes passed in so we can examine them later.
ProcessSyncChanges(const tracked_objects::Location & from_here,const SyncChangeList & change_list)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
GetAllSyncData(syncer::ModelType type) const83 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
84 OVERRIDE {
85 return syncer::SyncDataList();
86 }
87
change_list_size()88 size_t change_list_size() { return change_map_.size(); }
89
ContainsId(const std::string & id)90 bool ContainsId(const std::string& id) {
91 return change_map_.find(id) != change_map_.end();
92 }
93
GetChangeById(const std::string & id)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:
ChromeNotifierServiceTest()108 ChromeNotifierServiceTest()
109 : sync_processor_(new TestChangeProcessor),
110 sync_processor_wrapper_(
111 new SyncChangeProcessorWrapperForTest(sync_processor_.get())) {}
~ChromeNotifierServiceTest()112 virtual ~ChromeNotifierServiceTest() {}
113
114 // Methods from testing::Test.
SetUp()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
TearDown()134 virtual void TearDown() {
135 notification_manager_.reset();
136 }
137
notification_manager()138 StubNotificationUIManager* notification_manager() {
139 return notification_manager_.get();
140 }
141
processor()142 TestChangeProcessor* processor() {
143 return static_cast<TestChangeProcessor*>(sync_processor_.get());
144 }
145
PassProcessor()146 scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() {
147 return sync_processor_wrapper_.Pass();
148 }
149
CreateNotification(const std::string & title,const std::string & text,const std::string & app_icon_url,const std::string & image_url,const std::string & app_id,const std::string & key,sync_pb::CoalescedSyncedNotification_ReadState read_state)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.
CreateSyncChange(SyncChange::SyncChangeType type,SyncedNotification * notification)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
AddTestingAppInfos()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.
TEST_F(ChromeNotifierServiceTest,NotificationToSyncDataToNotification)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.
TEST_F(ChromeNotifierServiceTest,ModelAssocBothEmpty)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.
TEST_F(ChromeNotifierServiceTest,ProcessSyncChangesEmptyModel)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.
TEST_F(ChromeNotifierServiceTest,ProcessSyncChangesNonEmptyModel)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.
TEST_F(ChromeNotifierServiceTest,ProcessSyncChangesOutOfOrder)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.
TEST_F(ChromeNotifierServiceTest,LocalRemoteBothNonEmptyNoOverlap)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.
TEST_F(ChromeNotifierServiceTest,ModelAssocBothNonEmptyReadMismatch1)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.
TEST_F(ChromeNotifierServiceTest,ModelAssocBothNonEmptyReadMismatch2)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.
TEST_F(ChromeNotifierServiceTest,ModelAssocBothNonEmptyWithUpdate)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
TEST_F(ChromeNotifierServiceTest,ServiceEnabledTest)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
TEST_F(ChromeNotifierServiceTest,AddNewSendingServicesTest)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
TEST_F(ChromeNotifierServiceTest,CheckInitializedServicesTest)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
TEST_F(ChromeNotifierServiceTest,SetAddedAppIdsTest)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(¬ifier);
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
TEST_F(ChromeNotifierServiceTest,SetRemovedAppIdsTest)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