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.
7 #include "base/gtest_prod_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/notifications/notification.h"
13 #include "chrome/browser/notifications/notification_test_util.h"
14 #include "chrome/browser/notifications/notification_ui_manager.h"
15 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
16 #include "chrome/browser/notifications/sync_notifier/sync_notifier_test_utils.h"
17 #include "chrome/browser/notifications/sync_notifier/synced_notification.h"
18 #include "chrome/browser/prefs/browser_prefs.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/test/base/testing_pref_service_syncable.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "components/user_prefs/pref_registry_syncable.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "sync/api/sync_change.h"
26 #include "sync/api/sync_change_processor.h"
27 #include "sync/api/sync_error_factory.h"
28 #include "sync/api/sync_error_factory_mock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "ui/message_center/message_center_util.h"
32 using sync_pb::SyncedNotificationSpecifics
;
33 using sync_pb::EntitySpecifics
;
34 using syncer::SyncData
;
35 using syncer::SyncChange
;
36 using syncer::SyncChangeList
;
37 using syncer::SyncDataList
;
38 using syncer::SYNCED_NOTIFICATIONS
;
39 using notifier::SyncedNotification
;
40 using notifier::ChromeNotifierService
;
44 // Extract notification id from syncer::SyncData.
45 std::string
GetNotificationId(const SyncData
& sync_data
) {
46 SyncedNotificationSpecifics specifics
= sync_data
.GetSpecifics().
47 synced_notification();
49 return specifics
.coalesced_notification().key();
56 // Stub out the NotificationUIManager for unit testing.
57 class StubNotificationUIManager
: public NotificationUIManager
{
59 StubNotificationUIManager()
60 : notification_(GURL(),
64 new MockNotificationDelegate("stub")) {}
65 virtual ~StubNotificationUIManager() {}
67 // Adds a notification to be displayed. Virtual for unit test override.
68 virtual void Add(const Notification
& notification
, Profile
* profile
)
70 // Make a deep copy of the notification that we can inspect.
71 notification_
= notification
;
75 virtual bool Update(const Notification
& notification
, Profile
* profile
)
77 // Make a deep copy of the notification that we can inspect.
78 notification_
= notification
;
83 // Returns true if any notifications match the supplied ID, either currently
84 // displayed or in the queue.
85 virtual const Notification
* FindById(const std::string
& id
) const OVERRIDE
{
86 return (notification_
.id() == id
) ? ¬ification_
: NULL
;
89 // Removes any notifications matching the supplied ID, either currently
90 // displayed or in the queue. Returns true if anything was removed.
91 virtual bool CancelById(const std::string
& notification_id
) OVERRIDE
{
92 dismissed_id_
= notification_id
;
96 // Adds the notification_id for each outstanding notification to the set
97 // |notification_ids| (must not be NULL).
98 virtual std::set
<std::string
> GetAllIdsByProfileAndSourceOrigin(
100 const GURL
& source
) OVERRIDE
{
101 std::set
<std::string
> notification_ids
;
102 if (source
== notification_
.origin_url() &&
103 profile
->IsSameProfile(profile_
))
104 notification_ids
.insert(notification_
.notification_id());
105 return notification_ids
;
108 // Removes notifications matching the |source_origin| (which could be an
109 // extension ID). Returns true if anything was removed.
110 virtual bool CancelAllBySourceOrigin(const GURL
& source_origin
) OVERRIDE
{
114 // Removes notifications matching |profile|. Returns true if any were removed.
115 virtual bool CancelAllByProfile(Profile
* profile
) OVERRIDE
{
119 // Cancels all pending notifications and closes anything currently showing.
120 // Used when the app is terminating.
121 virtual void CancelAll() OVERRIDE
{}
123 // Test hook to get the notification so we can check it
124 const Notification
& notification() const { return notification_
; }
126 // Test hook to check the ID of the last notification cancelled.
127 std::string
& dismissed_id() { return dismissed_id_
; }
130 DISALLOW_COPY_AND_ASSIGN(StubNotificationUIManager
);
131 Notification notification_
;
133 std::string dismissed_id_
;
136 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
138 class TestChangeProcessor
: public syncer::SyncChangeProcessor
{
140 TestChangeProcessor() { }
141 virtual ~TestChangeProcessor() { }
143 // Store a copy of all the changes passed in so we can examine them later.
144 virtual syncer::SyncError
ProcessSyncChanges(
145 const tracked_objects::Location
& from_here
,
146 const SyncChangeList
& change_list
) OVERRIDE
{
148 for (SyncChangeList::const_iterator iter
= change_list
.begin();
149 iter
!= change_list
.end(); ++iter
) {
150 // Put the data into the change tracking map.
151 change_map_
[GetNotificationId(iter
->sync_data())] = *iter
;
154 return syncer::SyncError();
157 virtual syncer::SyncDataList
GetAllSyncData(syncer::ModelType type
) const
159 return syncer::SyncDataList();
162 size_t change_list_size() { return change_map_
.size(); }
164 bool ContainsId(const std::string
& id
) {
165 return change_map_
.find(id
) != change_map_
.end();
168 SyncChange
GetChangeById(const std::string
& id
) {
169 EXPECT_TRUE(ContainsId(id
));
170 return change_map_
[id
];
174 // Track the changes received in ProcessSyncChanges.
175 std::map
<std::string
, SyncChange
> change_map_
;
177 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor
);
180 class SyncChangeProcessorDelegate
: public syncer::SyncChangeProcessor
{
182 explicit SyncChangeProcessorDelegate(SyncChangeProcessor
* recipient
)
183 : recipient_(recipient
) {
184 EXPECT_TRUE(recipient_
);
186 virtual ~SyncChangeProcessorDelegate() {}
188 // syncer::SyncChangeProcessor implementation.
189 virtual syncer::SyncError
ProcessSyncChanges(
190 const tracked_objects::Location
& from_here
,
191 const SyncChangeList
& change_list
) OVERRIDE
{
192 return recipient_
->ProcessSyncChanges(from_here
, change_list
);
195 virtual syncer::SyncDataList
GetAllSyncData(syncer::ModelType type
) const
197 return recipient_
->GetAllSyncData(type
);
201 // The recipient of all sync changes.
202 SyncChangeProcessor
* recipient_
;
204 DISALLOW_COPY_AND_ASSIGN(SyncChangeProcessorDelegate
);
207 class ChromeNotifierServiceTest
: public testing::Test
{
209 ChromeNotifierServiceTest()
210 : sync_processor_(new TestChangeProcessor
),
211 sync_processor_delegate_(new SyncChangeProcessorDelegate(
212 sync_processor_
.get())) {}
213 virtual ~ChromeNotifierServiceTest() {}
215 // Methods from testing::Test.
216 virtual void SetUp() {
217 // Prevent test code from trying to go to the network.
218 ChromeNotifierService::set_avoid_bitmap_fetching_for_test(true);
220 // Set up a profile for the unit tests to use.
221 profile_
.reset(new TestingProfile());
224 virtual void TearDown() {}
226 TestChangeProcessor
* processor() {
227 return static_cast<TestChangeProcessor
*>(sync_processor_
.get());
230 scoped_ptr
<syncer::SyncChangeProcessor
> PassProcessor() {
231 return sync_processor_delegate_
.Pass();
234 SyncedNotification
* CreateNotification(
235 const std::string
& title
,
236 const std::string
& text
,
237 const std::string
& app_icon_url
,
238 const std::string
& image_url
,
239 const std::string
& app_id
,
240 const std::string
& key
,
241 sync_pb::CoalescedSyncedNotification_ReadState read_state
) {
242 SyncData sync_data
= CreateSyncData(title
, text
, app_icon_url
, image_url
,
243 app_id
, key
, read_state
);
244 // Set enough fields in sync_data, including specifics, for our tests
246 return new SyncedNotification(sync_data
);
249 // Helper to create syncer::SyncChange.
250 static SyncChange
CreateSyncChange(
251 SyncChange::SyncChangeType type
,
252 SyncedNotification
* notification
) {
253 // Take control of the notification to clean it up after we create data
255 scoped_ptr
<SyncedNotification
> scoped_notification(notification
);
259 ChromeNotifierService::CreateSyncDataFromNotification(*notification
));
263 scoped_ptr
<TestingProfile
> profile_
;
266 scoped_ptr
<syncer::SyncChangeProcessor
> sync_processor_
;
267 scoped_ptr
<syncer::SyncChangeProcessor
> sync_processor_delegate_
;
268 content::TestBrowserThreadBundle thread_bundle_
;
270 DISALLOW_COPY_AND_ASSIGN(ChromeNotifierServiceTest
);
273 // TODO(petewil): Add more tests as I add functionalty. Tests are based on
274 // chrome/browser/extensions/app_notification_manager_sync_unittest.cc
276 // Create a Notification, convert it to SyncData and convert it back.
277 TEST_F(ChromeNotifierServiceTest
, NotificationToSyncDataToNotification
) {
278 scoped_ptr
<SyncedNotification
> notification1(
279 CreateNotification(kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
,
282 ChromeNotifierService::CreateSyncDataFromNotification(*notification1
);
283 scoped_ptr
<SyncedNotification
> notification2(
284 ChromeNotifierService::CreateNotificationFromSyncData(sync_data
));
285 EXPECT_TRUE(notification2
.get());
286 EXPECT_TRUE(notification1
->EqualsIgnoringReadState(*notification2
));
287 EXPECT_EQ(notification1
->GetReadState(), notification2
->GetReadState());
290 // Model assocation: We have no local data, and no remote data.
291 TEST_F(ChromeNotifierServiceTest
, ModelAssocBothEmpty
) {
292 StubNotificationUIManager notification_manager
;
294 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
296 notifier
.MergeDataAndStartSyncing(
297 SYNCED_NOTIFICATIONS
,
298 SyncDataList(), // Empty.
300 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
302 EXPECT_EQ(0U, notifier
.GetAllSyncData(SYNCED_NOTIFICATIONS
).size());
303 EXPECT_EQ(0U, processor()->change_list_size());
306 // Process sync changes when there is no local data.
307 TEST_F(ChromeNotifierServiceTest
, ProcessSyncChangesEmptyModel
) {
308 // We initially have no data.
309 StubNotificationUIManager notification_manager
;
310 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
311 notifier
.set_avoid_bitmap_fetching_for_test(true);
313 notifier
.MergeDataAndStartSyncing(
314 SYNCED_NOTIFICATIONS
,
317 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
319 // Set up a bunch of ADDs.
320 SyncChangeList changes
;
321 changes
.push_back(CreateSyncChange(
322 SyncChange::ACTION_ADD
, CreateNotification(
323 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kUnread
)));
324 changes
.push_back(CreateSyncChange(
325 SyncChange::ACTION_ADD
, CreateNotification(
326 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kUnread
)));
327 changes
.push_back(CreateSyncChange(
328 SyncChange::ACTION_ADD
, CreateNotification(
329 kTitle3
, kText3
, kIconUrl3
, kImageUrl3
, kAppId3
, kKey3
, kUnread
)));
331 notifier
.ProcessSyncChanges(FROM_HERE
, changes
);
333 EXPECT_EQ(3U, notifier
.GetAllSyncData(SYNCED_NOTIFICATIONS
).size());
334 // TODO(petewil): verify that the list entries have expected values to make
335 // this test more robust.
338 // Process sync changes when there is no local data.
339 TEST_F(ChromeNotifierServiceTest
, ProcessSyncChangesNonEmptyModel
) {
340 StubNotificationUIManager notification_manager
;
341 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
342 notifier
.set_avoid_bitmap_fetching_for_test(true);
344 // Create some local fake data.
345 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
346 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kUnread
));
347 notifier
.AddForTest(n1
.Pass());
348 scoped_ptr
<SyncedNotification
> n2(CreateNotification(
349 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kUnread
));
350 notifier
.AddForTest(n2
.Pass());
351 scoped_ptr
<SyncedNotification
> n3(CreateNotification(
352 kTitle3
, kText3
, kIconUrl3
, kImageUrl3
, kAppId3
, kKey3
, kUnread
));
353 notifier
.AddForTest(n3
.Pass());
355 notifier
.MergeDataAndStartSyncing(
356 SYNCED_NOTIFICATIONS
,
359 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
361 // Set up some ADDs, some UPDATES, and some DELETEs
362 SyncChangeList changes
;
363 changes
.push_back(CreateSyncChange(
364 SyncChange::ACTION_ADD
, CreateNotification(
365 kTitle4
, kText4
, kIconUrl4
, kImageUrl4
, kAppId4
, kKey4
, kUnread
)));
366 changes
.push_back(CreateSyncChange(
367 SyncChange::ACTION_UPDATE
, CreateNotification(
368 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kRead
)));
369 changes
.push_back(CreateSyncChange(
370 SyncChange::ACTION_DELETE
, CreateNotification(
371 kTitle3
, kText3
, kIconUrl3
, kImageUrl3
, kAppId3
, kKey3
, kDismissed
)));
373 // Simulate incoming new notifications at runtime.
374 notifier
.ProcessSyncChanges(FROM_HERE
, changes
);
376 // We should find notifications 1, 2, and 4, but not 3.
377 EXPECT_EQ(3U, notifier
.GetAllSyncData(SYNCED_NOTIFICATIONS
).size());
378 EXPECT_TRUE(notifier
.FindNotificationById(kKey1
));
379 EXPECT_TRUE(notifier
.FindNotificationById(kKey2
));
380 EXPECT_FALSE(notifier
.FindNotificationById(kKey3
));
381 EXPECT_TRUE(notifier
.FindNotificationById(kKey4
));
383 // Verify that the first run preference is now set to false.
384 bool first_run
= notifier
.profile()->GetPrefs()->GetBoolean(
385 prefs::kSyncedNotificationFirstRun
);
386 EXPECT_NE(true, first_run
);
389 // Process sync changes that arrive before the change they are supposed to
391 TEST_F(ChromeNotifierServiceTest
, ProcessSyncChangesOutOfOrder
) {
392 StubNotificationUIManager notification_manager
;
393 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
394 notifier
.set_avoid_bitmap_fetching_for_test(true);
396 // Create some local fake data.
397 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
398 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kUnread
));
399 notifier
.AddForTest(n1
.Pass());
400 scoped_ptr
<SyncedNotification
> n2(CreateNotification(
401 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kUnread
));
402 notifier
.AddForTest(n2
.Pass());
403 scoped_ptr
<SyncedNotification
> n3(CreateNotification(
404 kTitle3
, kText3
, kIconUrl3
, kImageUrl3
, kAppId3
, kKey3
, kUnread
));
405 notifier
.AddForTest(n3
.Pass());
407 notifier
.MergeDataAndStartSyncing(
408 SYNCED_NOTIFICATIONS
,
411 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
413 SyncChangeList changes
;
414 // UPDATE a notification we have not seen an add for.
415 changes
.push_back(CreateSyncChange(
416 SyncChange::ACTION_UPDATE
, CreateNotification(
417 kTitle4
, kText4
, kIconUrl4
, kImageUrl4
, kAppId4
, kKey4
, kUnread
)));
418 // ADD a notification that we already have.
419 changes
.push_back(CreateSyncChange(
420 SyncChange::ACTION_ADD
, CreateNotification(
421 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kRead
)));
422 // DELETE a notification we have not seen yet.
423 changes
.push_back(CreateSyncChange(
424 SyncChange::ACTION_DELETE
, CreateNotification(
425 kTitle5
, kText5
, kIconUrl5
, kImageUrl5
, kAppId5
, kKey5
, kDismissed
)));
427 // Simulate incoming new notifications at runtime.
428 notifier
.ProcessSyncChanges(FROM_HERE
, changes
);
430 // We should find notifications 1, 2, 3, and 4, but not 5.
431 EXPECT_EQ(4U, notifier
.GetAllSyncData(SYNCED_NOTIFICATIONS
).size());
432 EXPECT_TRUE(notifier
.FindNotificationById(kKey1
));
433 EXPECT_TRUE(notifier
.FindNotificationById(kKey2
));
434 EXPECT_TRUE(notifier
.FindNotificationById(kKey3
));
435 EXPECT_TRUE(notifier
.FindNotificationById(kKey4
));
436 EXPECT_FALSE(notifier
.FindNotificationById(kKey5
));
440 // Model has some notifications, some of them are local only. Sync has some
441 // notifications. No items match up.
442 TEST_F(ChromeNotifierServiceTest
, LocalRemoteBothNonEmptyNoOverlap
) {
443 StubNotificationUIManager notification_manager
;
444 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
445 notifier
.set_avoid_bitmap_fetching_for_test(true);
447 // Create some local fake data.
448 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
449 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kUnread
));
450 notifier
.AddForTest(n1
.Pass());
451 scoped_ptr
<SyncedNotification
> n2(CreateNotification(
452 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kUnread
));
453 notifier
.AddForTest(n2
.Pass());
454 scoped_ptr
<SyncedNotification
> n3(CreateNotification(
455 kTitle3
, kText3
, kIconUrl3
, kImageUrl3
, kAppId3
, kKey3
, kUnread
));
456 notifier
.AddForTest(n3
.Pass());
458 // Create some remote fake data.
459 SyncDataList initial_data
;
460 initial_data
.push_back(CreateSyncData(kTitle4
, kText4
, kIconUrl4
, kImageUrl4
,
461 kAppId4
, kKey4
, kUnread
));
462 initial_data
.push_back(CreateSyncData(kTitle5
, kText5
, kIconUrl5
, kImageUrl5
,
463 kAppId5
, kKey5
, kUnread
));
464 initial_data
.push_back(CreateSyncData(kTitle6
, kText6
, kIconUrl6
, kImageUrl6
,
465 kAppId6
, kKey6
, kUnread
));
466 initial_data
.push_back(CreateSyncData(kTitle7
, kText7
, kIconUrl7
, kImageUrl7
,
467 kAppId7
, kKey7
, kUnread
));
469 // Merge the local and remote data.
470 notifier
.MergeDataAndStartSyncing(
471 SYNCED_NOTIFICATIONS
,
474 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
476 // Ensure the local store now has all local and remote notifications.
477 EXPECT_EQ(7U, notifier
.GetAllSyncData(SYNCED_NOTIFICATIONS
).size());
478 EXPECT_TRUE(notifier
.FindNotificationById(kKey1
));
479 EXPECT_TRUE(notifier
.FindNotificationById(kKey2
));
480 EXPECT_TRUE(notifier
.FindNotificationById(kKey3
));
481 EXPECT_TRUE(notifier
.FindNotificationById(kKey4
));
482 EXPECT_TRUE(notifier
.FindNotificationById(kKey5
));
483 EXPECT_TRUE(notifier
.FindNotificationById(kKey6
));
484 EXPECT_TRUE(notifier
.FindNotificationById(kKey7
));
486 // Test the type conversion and construction functions.
487 for (SyncDataList::const_iterator iter
= initial_data
.begin();
488 iter
!= initial_data
.end(); ++iter
) {
489 scoped_ptr
<SyncedNotification
> notification1(
490 ChromeNotifierService::CreateNotificationFromSyncData(*iter
));
491 // TODO(petewil): Revisit this when we add version info to notifications.
492 const std::string
& key
= notification1
->GetKey();
493 const SyncedNotification
* notification2
=
494 notifier
.FindNotificationById(key
);
495 EXPECT_TRUE(NULL
!= notification2
);
496 EXPECT_TRUE(notification1
->EqualsIgnoringReadState(*notification2
));
497 EXPECT_EQ(notification1
->GetReadState(), notification2
->GetReadState());
499 EXPECT_TRUE(notifier
.FindNotificationById(kKey1
));
500 EXPECT_TRUE(notifier
.FindNotificationById(kKey2
));
501 EXPECT_TRUE(notifier
.FindNotificationById(kKey3
));
504 // Test the local store having the read bit unset, the remote store having
506 TEST_F(ChromeNotifierServiceTest
, ModelAssocBothNonEmptyReadMismatch1
) {
507 StubNotificationUIManager notification_manager
;
508 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
509 notifier
.set_avoid_bitmap_fetching_for_test(true);
511 // Create some local fake data.
512 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
513 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kUnread
));
514 notifier
.AddForTest(n1
.Pass());
515 scoped_ptr
<SyncedNotification
> n2(CreateNotification(
516 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kUnread
));
517 notifier
.AddForTest(n2
.Pass());
519 // Create some remote fake data, item 1 matches except for the read state.
520 syncer::SyncDataList initial_data
;
521 initial_data
.push_back(CreateSyncData(kTitle1
, kText1
, kIconUrl1
, kImageUrl1
,
522 kAppId1
, kKey1
, kDismissed
));
523 // Merge the local and remote data.
524 notifier
.MergeDataAndStartSyncing(
525 syncer::SYNCED_NOTIFICATIONS
,
528 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
530 // Ensure the local store still has only two notifications, and the read
531 // state of the first is now read.
532 EXPECT_EQ(2U, notifier
.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS
).size());
533 SyncedNotification
* notification1
=
534 notifier
.FindNotificationById(kKey1
);
535 EXPECT_FALSE(NULL
== notification1
);
536 EXPECT_EQ(SyncedNotification::kDismissed
, notification1
->GetReadState());
537 EXPECT_TRUE(notifier
.FindNotificationById(kKey2
));
538 EXPECT_FALSE(notifier
.FindNotificationById(kKey3
));
540 // Make sure that the notification manager was told to dismiss the
542 EXPECT_EQ(std::string(kKey1
), notification_manager
.dismissed_id());
544 // Ensure no new data will be sent to the remote store for notification1.
545 EXPECT_EQ(0U, processor()->change_list_size());
546 EXPECT_FALSE(processor()->ContainsId(kKey1
));
549 // Test when the local store has the read bit set, and the remote store has
551 TEST_F(ChromeNotifierServiceTest
, ModelAssocBothNonEmptyReadMismatch2
) {
552 StubNotificationUIManager notification_manager
;
553 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
554 notifier
.set_avoid_bitmap_fetching_for_test(true);
556 // Create some local fake data.
557 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
558 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kDismissed
));
559 notifier
.AddForTest(n1
.Pass());
560 scoped_ptr
<SyncedNotification
> n2(CreateNotification(
561 kTitle2
, kText2
, kIconUrl2
, kImageUrl2
, kAppId2
, kKey2
, kUnread
));
562 notifier
.AddForTest(n2
.Pass());
564 // Create some remote fake data, item 1 matches except for the read state.
565 syncer::SyncDataList initial_data
;
566 initial_data
.push_back(CreateSyncData(kTitle1
, kText1
, kIconUrl1
, kImageUrl1
,
567 kAppId1
, kKey1
, kUnread
));
568 // Merge the local and remote data.
569 notifier
.MergeDataAndStartSyncing(
570 syncer::SYNCED_NOTIFICATIONS
,
573 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
575 // Ensure the local store still has only two notifications, and the read
576 // state of the first is now read.
577 EXPECT_EQ(2U, notifier
.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS
).size());
578 SyncedNotification
* notification1
=
579 notifier
.FindNotificationById(kKey1
);
580 EXPECT_FALSE(NULL
== notification1
);
581 EXPECT_EQ(SyncedNotification::kDismissed
, notification1
->GetReadState());
582 EXPECT_TRUE(notifier
.FindNotificationById(kKey2
));
583 EXPECT_FALSE(notifier
.FindNotificationById(kKey3
));
585 // Ensure the new data will be sent to the remote store for notification1.
586 EXPECT_EQ(1U, processor()->change_list_size());
587 EXPECT_TRUE(processor()->ContainsId(kKey1
));
588 EXPECT_EQ(SyncChange::ACTION_UPDATE
, processor()->GetChangeById(
589 kKey1
).change_type());
592 // We have a notification in the local store, we get an updated version
593 // of the same notification remotely, it should take precedence.
594 TEST_F(ChromeNotifierServiceTest
, ModelAssocBothNonEmptyWithUpdate
) {
595 StubNotificationUIManager notification_manager
;
596 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
598 // Create some local fake data.
599 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
600 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kDismissed
));
601 notifier
.AddForTest(n1
.Pass());
603 // Create some remote fake data, item 1 matches the ID, but has different data
604 syncer::SyncDataList initial_data
;
605 initial_data
.push_back(CreateSyncData(kTitle2
, kText2
, kIconUrl2
, kImageUrl2
,
606 kAppId1
, kKey1
, kUnread
));
607 // Merge the local and remote data.
608 notifier
.MergeDataAndStartSyncing(
609 syncer::SYNCED_NOTIFICATIONS
,
612 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
614 // Ensure the local store still has only one notification
615 EXPECT_EQ(1U, notifier
.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS
).size());
616 SyncedNotification
* notification1
=
617 notifier
.FindNotificationById(kKey1
);
619 EXPECT_FALSE(NULL
== notification1
);
620 EXPECT_EQ(SyncedNotification::kUnread
, notification1
->GetReadState());
621 EXPECT_EQ(std::string(kTitle2
), notification1
->GetTitle());
623 // Ensure no new data will be sent to the remote store for notification1.
624 EXPECT_EQ(0U, processor()->change_list_size());
625 EXPECT_FALSE(processor()->ContainsId(kKey1
));
628 TEST_F(ChromeNotifierServiceTest
, ServiceEnabledTest
) {
629 StubNotificationUIManager notification_manager
;
630 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
631 std::set
<std::string
>::iterator iter
;
632 std::string
first_synced_notification_service_id(
633 kFirstSyncedNotificationServiceId
);
635 // Create some local fake data.
636 scoped_ptr
<SyncedNotification
> n1(CreateNotification(
637 kTitle1
, kText1
, kIconUrl1
, kImageUrl1
, kAppId1
, kKey1
, kUnread
));
638 notifier
.AddForTest(n1
.Pass());
640 // Enable the service and ensure the service is in the list.
641 // Initially the service starts in the disabled state.
642 notifier
.OnSyncedNotificationServiceEnabled(kFirstSyncedNotificationServiceId
,
644 iter
= find(notifier
.enabled_sending_services_
.begin(),
645 notifier
.enabled_sending_services_
.end(),
646 first_synced_notification_service_id
);
647 EXPECT_NE(notifier
.enabled_sending_services_
.end(), iter
);
648 // TODO(petewil): Verify Display gets called too.
650 // Disable the service and ensure it is gone from the list and the
651 // notification_manager.
652 notifier
.OnSyncedNotificationServiceEnabled(kFirstSyncedNotificationServiceId
,
654 iter
= find(notifier
.enabled_sending_services_
.begin(),
655 notifier
.enabled_sending_services_
.end(),
656 first_synced_notification_service_id
);
657 EXPECT_EQ(notifier
.enabled_sending_services_
.end(), iter
);
658 EXPECT_EQ(notification_manager
.dismissed_id(), std::string(kKey1
));
662 TEST_F(ChromeNotifierServiceTest
, InitializePrefsTest
) {
663 StubNotificationUIManager notification_manager
;
664 // The CTOR will call InitializePrefs().
665 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
667 // Verify the first synced notification service ID is set to enabled in
669 std::string
service_name(kFirstSyncedNotificationServiceId
);
670 base::StringValue
service_name_value(service_name
);
671 const base::ListValue
* enabled_set
= notifier
.profile()->GetPrefs()->GetList(
672 prefs::kEnabledSyncedNotificationSendingServices
);
673 base::ValueVector::const_iterator iter
=
674 enabled_set
->Find(service_name_value
);
675 EXPECT_NE(enabled_set
->end(), iter
);
677 // Verify the first synced notification service ID is set to initialized in
679 const base::ListValue
* initialized_set
=
680 notifier
.profile()->GetPrefs()->GetList(
681 prefs::kInitializedSyncedNotificationSendingServices
);
682 iter
= initialized_set
->Find(service_name_value
);
683 EXPECT_NE(initialized_set
->end(), iter
);
685 // Verify that synced notification first run pref is set to "true".
686 bool first_run
= notifier
.profile()->GetPrefs()->GetBoolean(
687 prefs::kSyncedNotificationFirstRun
);
688 EXPECT_EQ(true, first_run
);
691 TEST_F(ChromeNotifierServiceTest
,
692 AddNewSendingServicesTest
) {
693 StubNotificationUIManager notification_manager
;
694 std::string
first_synced_notification_service_id(
695 kFirstSyncedNotificationServiceId
);
696 // The CTOR will call AddnewSendingServices()
697 ChromeNotifierService
notifier(profile_
.get(), ¬ification_manager
);
699 // Verify that the first synced notification service is enabled in memory.
700 std::set
<std::string
>::iterator iter
;
701 iter
= find(notifier
.enabled_sending_services_
.begin(),
702 notifier
.enabled_sending_services_
.end(),
703 first_synced_notification_service_id
);
705 EXPECT_NE(notifier
.enabled_sending_services_
.end(), iter
);
708 } // namespace notifier