• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&notifier);
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