OLD | NEW |
| (Empty) |
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 "base/bind.h" | |
6 #include "base/memory/scoped_ptr.h" | |
7 #include "base/message_loop.h" | |
8 #include "base/strings/string_number_conversions.h" | |
9 #include "chrome/browser/extensions/app_notification.h" | |
10 #include "chrome/browser/extensions/app_notification_manager.h" | |
11 #include "chrome/test/base/testing_profile.h" | |
12 #include "content/public/test/test_browser_thread.h" | |
13 #include "sync/api/sync_error_factory.h" | |
14 #include "sync/api/sync_error_factory_mock.h" | |
15 #include "sync/protocol/app_notification_specifics.pb.h" | |
16 #include "sync/protocol/sync.pb.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 using content::BrowserThread; | |
20 using ::testing::_; | |
21 using ::testing::Return; | |
22 | |
23 namespace { | |
24 | |
25 // Extract notification guid from syncer::SyncData. | |
26 std::string GetGuid(const syncer::SyncData& sync_data) { | |
27 return sync_data.GetSpecifics().app_notification().guid(); | |
28 } | |
29 | |
30 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed | |
31 // back up to Sync. | |
32 class TestChangeProcessor : public syncer::SyncChangeProcessor { | |
33 public: | |
34 TestChangeProcessor() { } | |
35 virtual ~TestChangeProcessor() { } | |
36 | |
37 // Store a copy of all the changes passed in so we can examine them later. | |
38 virtual syncer::SyncError ProcessSyncChanges( | |
39 const tracked_objects::Location& from_here, | |
40 const syncer::SyncChangeList& change_list) OVERRIDE { | |
41 // change_map_.erase(change_map_.begin(), change_map_.end()); | |
42 for (syncer::SyncChangeList::const_iterator iter = change_list.begin(); | |
43 iter != change_list.end(); ++iter) { | |
44 change_map_[GetGuid(iter->sync_data())] = *iter; | |
45 } | |
46 | |
47 return syncer::SyncError(); | |
48 } | |
49 | |
50 bool ContainsGuid(const std::string& guid) { | |
51 return change_map_.find(guid) != change_map_.end(); | |
52 } | |
53 | |
54 syncer::SyncChange GetChangeByGuid(const std::string& guid) { | |
55 DCHECK(ContainsGuid(guid)); | |
56 return change_map_[guid]; | |
57 } | |
58 | |
59 size_t change_list_size() { return change_map_.size(); } | |
60 | |
61 private: | |
62 // Track the changes received in ProcessSyncChanges. | |
63 std::map<std::string, syncer::SyncChange> change_map_; | |
64 | |
65 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor); | |
66 }; | |
67 | |
68 class SyncChangeProcessorDelegate : public syncer::SyncChangeProcessor { | |
69 public: | |
70 explicit SyncChangeProcessorDelegate(syncer::SyncChangeProcessor* recipient) | |
71 : recipient_(recipient) { | |
72 DCHECK(recipient_); | |
73 } | |
74 virtual ~SyncChangeProcessorDelegate() {} | |
75 | |
76 // syncer::SyncChangeProcessor implementation. | |
77 virtual syncer::SyncError ProcessSyncChanges( | |
78 const tracked_objects::Location& from_here, | |
79 const syncer::SyncChangeList& change_list) OVERRIDE { | |
80 return recipient_->ProcessSyncChanges(from_here, change_list); | |
81 } | |
82 | |
83 private: | |
84 // The recipient of all sync changes. | |
85 syncer::SyncChangeProcessor* recipient_; | |
86 | |
87 DISALLOW_COPY_AND_ASSIGN(SyncChangeProcessorDelegate); | |
88 }; | |
89 | |
90 } // namespace | |
91 | |
92 namespace extensions { | |
93 | |
94 class AppNotificationManagerSyncTest : public testing::Test { | |
95 public: | |
96 AppNotificationManagerSyncTest() | |
97 : ui_thread_(BrowserThread::UI, &ui_loop_), | |
98 file_thread_(BrowserThread::FILE), | |
99 sync_processor_(new TestChangeProcessor), | |
100 sync_processor_delegate_(new SyncChangeProcessorDelegate( | |
101 sync_processor_.get())) {} | |
102 | |
103 virtual ~AppNotificationManagerSyncTest() { | |
104 model_ = NULL; | |
105 } | |
106 | |
107 virtual void SetUp() { | |
108 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
109 file_thread_.Start(); | |
110 | |
111 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
112 profile_.reset(new TestingProfile(temp_dir_.path())); | |
113 model_ = new AppNotificationManager(profile_.get()); | |
114 model_->Init(); | |
115 | |
116 WaitForFileThread(); | |
117 ASSERT_TRUE(model_->loaded()); | |
118 } | |
119 | |
120 virtual void TearDown() { | |
121 WaitForFileThread(); | |
122 } | |
123 | |
124 static void PostQuitToUIThread() { | |
125 BrowserThread::PostTask(BrowserThread::UI, | |
126 FROM_HERE, | |
127 MessageLoop::QuitClosure()); | |
128 } | |
129 | |
130 static void WaitForFileThread() { | |
131 BrowserThread::PostTask(BrowserThread::FILE, | |
132 FROM_HERE, | |
133 base::Bind(&PostQuitToUIThread)); | |
134 MessageLoop::current()->Run(); | |
135 } | |
136 | |
137 AppNotificationManager* model() { return model_.get(); } | |
138 TestChangeProcessor* processor() { return sync_processor_.get(); } | |
139 | |
140 scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() { | |
141 return sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(); | |
142 } | |
143 | |
144 // Creates a notification whose properties are set from the given integer. | |
145 static AppNotification* CreateNotification(int suffix) { | |
146 return CreateNotification(false, suffix); | |
147 } | |
148 static AppNotification* CreateNotification(bool is_local, int suffix) { | |
149 std::string s = base::IntToString(suffix); | |
150 return CreateNotification( | |
151 is_local, suffix, "guid" + s, "ext" + s, "text" + s, "body" + s, | |
152 "http://www.url" + s + ".com", "link text " + s); | |
153 } | |
154 static AppNotification* CreateNotification( | |
155 bool is_local, int suffix, const std::string& extension_id) { | |
156 std::string s = base::IntToString(suffix); | |
157 return CreateNotification( | |
158 is_local, suffix, "guid" + s, extension_id, "text" + s, "body" + s, | |
159 "http://www.url" + s + ".com", "link text " + s); | |
160 } | |
161 | |
162 // Creates a notification whose properties are set from the given integer | |
163 // but does not set link url and link text. | |
164 static AppNotification* CreateNotificationNoLink(int suffix) { | |
165 return CreateNotificationNoLink(false, suffix); | |
166 } | |
167 static AppNotification* CreateNotificationNoLink(bool is_local, int suffix) { | |
168 std::string s = base::IntToString(suffix); | |
169 return CreateNotification( | |
170 is_local, suffix, | |
171 "guid" + s, "ext" + s, "text" + s, "body" + s, "", ""); | |
172 } | |
173 | |
174 // link_url and link_text are only set if the passed in values are not empty. | |
175 static AppNotification* CreateNotification(bool is_local, | |
176 int64 time, | |
177 const std::string& guid, | |
178 const std::string& extension_id, | |
179 const std::string& title, | |
180 const std::string& body, | |
181 const std::string& link_url, | |
182 const std::string& link_text) { | |
183 AppNotification* notif = new AppNotification( | |
184 is_local, base::Time::FromInternalValue(time), | |
185 guid, extension_id, title, body); | |
186 if (!link_url.empty()) | |
187 notif->set_link_url(GURL(link_url)); | |
188 if (!link_text.empty()) | |
189 notif->set_link_text(link_text); | |
190 return notif; | |
191 } | |
192 | |
193 static syncer::SyncData CreateSyncData(int suffix) { | |
194 scoped_ptr<AppNotification> notif(CreateNotification(suffix)); | |
195 return AppNotificationManager::CreateSyncDataFromNotification(*notif); | |
196 } | |
197 static syncer::SyncData CreateSyncData( | |
198 int suffix, const std::string& extension_id) { | |
199 scoped_ptr<AppNotification> notif( | |
200 CreateNotification(false, suffix, extension_id)); | |
201 return AppNotificationManager::CreateSyncDataFromNotification(*notif); | |
202 } | |
203 | |
204 // Helper to create syncer::SyncChange. Takes ownership of |notif|. | |
205 static syncer::SyncChange CreateSyncChange( | |
206 syncer::SyncChange::SyncChangeType type, | |
207 AppNotification* notif) { | |
208 // Take control of notif to clean it up after we create data out of it. | |
209 scoped_ptr<AppNotification> scoped_notif(notif); | |
210 return syncer::SyncChange( | |
211 FROM_HERE, | |
212 type, | |
213 AppNotificationManager::CreateSyncDataFromNotification(*notif)); | |
214 } | |
215 | |
216 void AssertSyncChange(const syncer::SyncChange& change, | |
217 syncer::SyncChange::SyncChangeType type, | |
218 const AppNotification& notif) { | |
219 ASSERT_EQ(type, change.change_type()); | |
220 scoped_ptr<AppNotification> notif2( | |
221 AppNotificationManager::CreateNotificationFromSyncData( | |
222 change.sync_data())); | |
223 ASSERT_TRUE(notif.Equals(*notif2)); | |
224 } | |
225 | |
226 protected: | |
227 MessageLoop ui_loop_; | |
228 content::TestBrowserThread ui_thread_; | |
229 content::TestBrowserThread file_thread_; | |
230 | |
231 // We keep two TemplateURLServices to test syncing between them. | |
232 base::ScopedTempDir temp_dir_; | |
233 scoped_ptr<TestingProfile> profile_; | |
234 scoped_refptr<AppNotificationManager> model_; | |
235 | |
236 scoped_ptr<TestChangeProcessor> sync_processor_; | |
237 scoped_ptr<SyncChangeProcessorDelegate> sync_processor_delegate_; | |
238 | |
239 DISALLOW_COPY_AND_ASSIGN(AppNotificationManagerSyncTest); | |
240 }; | |
241 | |
242 // Create an AppNotification, convert it to SyncData and convert it back. | |
243 TEST_F(AppNotificationManagerSyncTest, NotificationToSyncDataToNotification) { | |
244 { // Partial properties set. | |
245 scoped_ptr<AppNotification> notif1(CreateNotificationNoLink(1)); | |
246 syncer::SyncData sync_data = | |
247 AppNotificationManager::CreateSyncDataFromNotification(*notif1); | |
248 scoped_ptr<AppNotification> notif2( | |
249 AppNotificationManager::CreateNotificationFromSyncData(sync_data)); | |
250 EXPECT_TRUE(notif2.get()); | |
251 EXPECT_TRUE(notif1->Equals(*notif2)); | |
252 } | |
253 { // All properties set. | |
254 scoped_ptr<AppNotification> notif1(CreateNotification(1)); | |
255 syncer::SyncData sync_data = | |
256 AppNotificationManager::CreateSyncDataFromNotification(*notif1); | |
257 scoped_ptr<AppNotification> notif2( | |
258 AppNotificationManager::CreateNotificationFromSyncData(sync_data)); | |
259 EXPECT_TRUE(notif2.get()); | |
260 EXPECT_TRUE(notif1->Equals(*notif2)); | |
261 } | |
262 } | |
263 | |
264 // GetAllSyncData returns all notifications since none are marked local only. | |
265 TEST_F(AppNotificationManagerSyncTest, GetAllSyncDataNoLocal) { | |
266 model()->Add(CreateNotificationNoLink(1)); | |
267 model()->Add(CreateNotification(2)); | |
268 model()->Add(CreateNotification(3)); | |
269 syncer::SyncDataList all_sync_data = | |
270 model()->GetAllSyncData(syncer::APP_NOTIFICATIONS); | |
271 | |
272 EXPECT_EQ(3U, all_sync_data.size()); | |
273 | |
274 for (syncer::SyncDataList::const_iterator iter = all_sync_data.begin(); | |
275 iter != all_sync_data.end(); ++iter) { | |
276 scoped_ptr<AppNotification> notif1( | |
277 AppNotificationManager::CreateNotificationFromSyncData(*iter)); | |
278 | |
279 const std::string& guid = notif1->guid(); | |
280 const std::string& ext_id = notif1->extension_id(); | |
281 | |
282 const AppNotification* notif2 = model()->GetNotification(ext_id, guid); | |
283 ASSERT_TRUE(notif1->Equals(*notif2)); | |
284 } | |
285 } | |
286 | |
287 // GetAllSyncData should not return notifications marked as local only. | |
288 TEST_F(AppNotificationManagerSyncTest, GetAllSyncDataSomeLocal) { | |
289 model()->Add(CreateNotificationNoLink(1)); | |
290 model()->Add(CreateNotification(true, 2)); | |
291 model()->Add(CreateNotification(3)); | |
292 model()->Add(CreateNotification(true, 4)); | |
293 model()->Add(CreateNotification(5)); | |
294 syncer::SyncDataList all_sync_data = | |
295 model()->GetAllSyncData(syncer::APP_NOTIFICATIONS); | |
296 | |
297 EXPECT_EQ(3U, all_sync_data.size()); | |
298 | |
299 for (syncer::SyncDataList::const_iterator iter = all_sync_data.begin(); | |
300 iter != all_sync_data.end(); ++iter) { | |
301 scoped_ptr<AppNotification> notif1( | |
302 AppNotificationManager::CreateNotificationFromSyncData(*iter)); | |
303 const std::string& guid = notif1->guid(); | |
304 const std::string& ext_id = notif1->extension_id(); | |
305 | |
306 const AppNotification* notif2 = model()->GetNotification(ext_id, guid); | |
307 ASSERT_TRUE(notif1->Equals(*notif2)); | |
308 } | |
309 } | |
310 | |
311 // Model assocation: both models are empty. | |
312 TEST_F(AppNotificationManagerSyncTest, ModelAssocBothEmpty) { | |
313 model()->MergeDataAndStartSyncing( | |
314 syncer::APP_NOTIFICATIONS, | |
315 syncer::SyncDataList(), // Empty. | |
316 PassProcessor(), | |
317 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
318 | |
319 EXPECT_EQ(0U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
320 EXPECT_EQ(0U, processor()->change_list_size()); | |
321 } | |
322 | |
323 // Model assocation: empty sync model and non-empty local model. | |
324 TEST_F(AppNotificationManagerSyncTest, ModelAssocModelEmpty) { | |
325 syncer::SyncDataList initial_data; | |
326 initial_data.push_back(CreateSyncData(1)); | |
327 initial_data.push_back(CreateSyncData(2)); | |
328 initial_data.push_back(CreateSyncData(3)); | |
329 initial_data.push_back(CreateSyncData(4)); | |
330 | |
331 model()->MergeDataAndStartSyncing( | |
332 syncer::APP_NOTIFICATIONS, | |
333 initial_data, | |
334 PassProcessor(), | |
335 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
336 | |
337 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
338 // Model should all of the initial sync data. | |
339 for (syncer::SyncDataList::const_iterator iter = initial_data.begin(); | |
340 iter != initial_data.end(); ++iter) { | |
341 scoped_ptr<AppNotification> notif1( | |
342 AppNotificationManager::CreateNotificationFromSyncData(*iter)); | |
343 const std::string& ext_id = notif1->extension_id(); | |
344 const std::string& guid = notif1->guid(); | |
345 const AppNotification* notif2 = model()->GetNotification(ext_id, guid); | |
346 EXPECT_TRUE(notif2); | |
347 EXPECT_TRUE(notif1->Equals(*notif2)); | |
348 } | |
349 | |
350 EXPECT_EQ(0U, processor()->change_list_size()); | |
351 } | |
352 | |
353 // Model has some notifications, some of them are local only. Sync has some | |
354 // notifications. No items match up. | |
355 TEST_F(AppNotificationManagerSyncTest, ModelAssocBothNonEmptyNoOverlap) { | |
356 AppNotification* n1 = CreateNotification(1); | |
357 model()->Add(n1); | |
358 AppNotification* n2 = CreateNotification(true, 2); | |
359 model()->Add(n2); | |
360 AppNotification* n3 = CreateNotification(3); | |
361 model()->Add(n3); | |
362 | |
363 syncer::SyncDataList initial_data; | |
364 initial_data.push_back(CreateSyncData(4)); | |
365 initial_data.push_back(CreateSyncData(5)); | |
366 initial_data.push_back(CreateSyncData(6)); | |
367 initial_data.push_back(CreateSyncData(7)); | |
368 | |
369 model()->MergeDataAndStartSyncing( | |
370 syncer::APP_NOTIFICATIONS, | |
371 initial_data, | |
372 PassProcessor(), | |
373 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
374 | |
375 EXPECT_EQ(6U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
376 for (syncer::SyncDataList::const_iterator iter = initial_data.begin(); | |
377 iter != initial_data.end(); ++iter) { | |
378 scoped_ptr<AppNotification> notif1( | |
379 AppNotificationManager::CreateNotificationFromSyncData(*iter)); | |
380 const std::string& ext_id = notif1->extension_id(); | |
381 const std::string& guid = notif1->guid(); | |
382 const AppNotification* notif2 = model()->GetNotification(ext_id, guid); | |
383 EXPECT_TRUE(notif2); | |
384 EXPECT_TRUE(notif1->Equals(*notif2)); | |
385 } | |
386 EXPECT_TRUE(model()->GetNotification(n1->extension_id(), n1->guid())); | |
387 EXPECT_TRUE(model()->GetNotification(n2->extension_id(), n2->guid())); | |
388 EXPECT_TRUE(model()->GetNotification(n3->extension_id(), n3->guid())); | |
389 | |
390 EXPECT_EQ(2U, processor()->change_list_size()); | |
391 EXPECT_TRUE(processor()->ContainsGuid(n1->guid())); | |
392 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, | |
393 processor()->GetChangeByGuid(n1->guid()).change_type()); | |
394 EXPECT_FALSE(processor()->ContainsGuid(n2->guid())); | |
395 EXPECT_TRUE(processor()->ContainsGuid(n3->guid())); | |
396 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, | |
397 processor()->GetChangeByGuid(n3->guid()).change_type()); | |
398 } | |
399 | |
400 // Model has some notifications, some of them are local only. Sync has some | |
401 // notifications. Some items match up. | |
402 TEST_F(AppNotificationManagerSyncTest, ModelAssocBothNonEmptySomeOverlap) { | |
403 AppNotification* n1 = CreateNotification(1); | |
404 model()->Add(n1); | |
405 AppNotification* n2 = CreateNotification(true, 2); | |
406 model()->Add(n2); | |
407 AppNotification* n3 = CreateNotification(3); | |
408 model()->Add(n3); | |
409 AppNotification* n4 = CreateNotification(4); | |
410 model()->Add(n4); | |
411 | |
412 syncer::SyncDataList initial_data; | |
413 initial_data.push_back(CreateSyncData(5)); | |
414 initial_data.push_back( | |
415 AppNotificationManager::CreateSyncDataFromNotification(*n1)); | |
416 initial_data.push_back(CreateSyncData(6)); | |
417 initial_data.push_back( | |
418 AppNotificationManager::CreateSyncDataFromNotification(*n4)); | |
419 initial_data.push_back(CreateSyncData(7)); | |
420 | |
421 model()->MergeDataAndStartSyncing( | |
422 syncer::APP_NOTIFICATIONS, | |
423 initial_data, | |
424 PassProcessor(), | |
425 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
426 | |
427 EXPECT_EQ(6U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
428 for (syncer::SyncDataList::const_iterator iter = initial_data.begin(); | |
429 iter != initial_data.end(); ++iter) { | |
430 scoped_ptr<AppNotification> notif1( | |
431 AppNotificationManager::CreateNotificationFromSyncData(*iter)); | |
432 const std::string& ext_id = notif1->extension_id(); | |
433 const std::string& guid = notif1->guid(); | |
434 const AppNotification* notif2 = model()->GetNotification(ext_id, guid); | |
435 EXPECT_TRUE(notif2); | |
436 EXPECT_TRUE(notif1->Equals(*notif2)); | |
437 } | |
438 EXPECT_TRUE(model()->GetNotification(n1->extension_id(), n1->guid())); | |
439 EXPECT_TRUE(model()->GetNotification(n2->extension_id(), n2->guid())); | |
440 EXPECT_TRUE(model()->GetNotification(n3->extension_id(), n3->guid())); | |
441 EXPECT_TRUE(model()->GetNotification(n4->extension_id(), n4->guid())); | |
442 | |
443 EXPECT_EQ(1U, processor()->change_list_size()); | |
444 EXPECT_FALSE(processor()->ContainsGuid(n1->guid())); | |
445 EXPECT_FALSE(processor()->ContainsGuid(n2->guid())); | |
446 EXPECT_TRUE(processor()->ContainsGuid(n3->guid())); | |
447 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, | |
448 processor()->GetChangeByGuid(n3->guid()).change_type()); | |
449 EXPECT_FALSE(processor()->ContainsGuid(n4->guid())); | |
450 } | |
451 | |
452 // When an item that matches up in model and sync is different, an error | |
453 // should be returned. | |
454 TEST_F(AppNotificationManagerSyncTest, ModelAssocBothNonEmptyTitleMismatch) { | |
455 AppNotification* n1 = CreateNotification(1); | |
456 model()->Add(n1); | |
457 AppNotification* n2 = CreateNotification(true, 2); | |
458 model()->Add(n2); | |
459 | |
460 syncer::SyncDataList initial_data; | |
461 initial_data.push_back(CreateSyncData(1)); | |
462 scoped_ptr<AppNotification> n1_a(CreateNotification( | |
463 n1->is_local(), n1->creation_time().ToInternalValue(), | |
464 n1->guid(), n1->extension_id(), | |
465 n1->title() + "_changed", // different title | |
466 n1->body(), n1->link_url().spec(), n1->link_text())); | |
467 initial_data.push_back( | |
468 AppNotificationManager::CreateSyncDataFromNotification(*n1_a)); | |
469 | |
470 scoped_ptr<syncer::SyncErrorFactoryMock> error_handler( | |
471 new syncer::SyncErrorFactoryMock()); | |
472 EXPECT_CALL(*error_handler, CreateAndUploadError(_, _)). | |
473 WillOnce( | |
474 Return( | |
475 syncer::SyncError( | |
476 FROM_HERE, "error", syncer::APP_NOTIFICATIONS))); | |
477 | |
478 syncer::SyncError sync_error = model()->MergeDataAndStartSyncing( | |
479 syncer::APP_NOTIFICATIONS, | |
480 initial_data, | |
481 PassProcessor(), | |
482 error_handler.PassAs<syncer::SyncErrorFactory>()).error(); | |
483 | |
484 EXPECT_TRUE(sync_error.IsSet()); | |
485 EXPECT_EQ(syncer::APP_NOTIFICATIONS, sync_error.type()); | |
486 EXPECT_EQ(0U, processor()->change_list_size()); | |
487 } | |
488 | |
489 // When an item in sync matches with a local-only item in model, an error | |
490 // should be returned. | |
491 TEST_F(AppNotificationManagerSyncTest, ModelAssocBothNonEmptyMatchesLocal) { | |
492 AppNotification* n1 = CreateNotification(1); | |
493 model()->Add(n1); | |
494 AppNotification* n2 = CreateNotification(true, 2); | |
495 model()->Add(n2); | |
496 | |
497 syncer::SyncDataList initial_data; | |
498 initial_data.push_back(CreateSyncData(1)); | |
499 scoped_ptr<AppNotification> n2_a(CreateNotification(2)); | |
500 initial_data.push_back( | |
501 AppNotificationManager::CreateSyncDataFromNotification(*n2_a)); | |
502 | |
503 scoped_ptr<syncer::SyncErrorFactoryMock> error_handler( | |
504 new syncer::SyncErrorFactoryMock()); | |
505 EXPECT_CALL(*error_handler, CreateAndUploadError(_, _)). | |
506 WillOnce( | |
507 Return( | |
508 syncer::SyncError( | |
509 FROM_HERE, "error", syncer::APP_NOTIFICATIONS))); | |
510 | |
511 syncer::SyncError sync_error = model()->MergeDataAndStartSyncing( | |
512 syncer::APP_NOTIFICATIONS, | |
513 initial_data, | |
514 PassProcessor(), | |
515 error_handler.PassAs<syncer::SyncErrorFactory>()).error(); | |
516 | |
517 EXPECT_TRUE(sync_error.IsSet()); | |
518 EXPECT_EQ(syncer::APP_NOTIFICATIONS, sync_error.type()); | |
519 EXPECT_EQ(0U, processor()->change_list_size()); | |
520 } | |
521 | |
522 // Process sync changes when model is empty. | |
523 TEST_F(AppNotificationManagerSyncTest, ProcessSyncChangesEmptyModel) { | |
524 // We initially have no data. | |
525 model()->MergeDataAndStartSyncing( | |
526 syncer::APP_NOTIFICATIONS, | |
527 syncer::SyncDataList(), | |
528 PassProcessor(), | |
529 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
530 | |
531 // Set up a bunch of ADDs. | |
532 syncer::SyncChangeList changes; | |
533 changes.push_back(CreateSyncChange( | |
534 syncer::SyncChange::ACTION_ADD, CreateNotification(1))); | |
535 changes.push_back(CreateSyncChange( | |
536 syncer::SyncChange::ACTION_ADD, CreateNotification(2))); | |
537 changes.push_back(CreateSyncChange( | |
538 syncer::SyncChange::ACTION_ADD, CreateNotification(3))); | |
539 | |
540 model()->ProcessSyncChanges(FROM_HERE, changes); | |
541 | |
542 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
543 EXPECT_EQ(0U, processor()->change_list_size()); | |
544 } | |
545 | |
546 // Process sync changes when model is not empty. | |
547 TEST_F(AppNotificationManagerSyncTest, ProcessSyncChangesNonEmptyModel) { | |
548 AppNotification* n1 = CreateNotification(1); | |
549 model()->Add(n1); | |
550 AppNotification* n2 = CreateNotification(2); | |
551 model()->Add(n2); | |
552 model()->MergeDataAndStartSyncing( | |
553 syncer::APP_NOTIFICATIONS, | |
554 syncer::SyncDataList(), | |
555 PassProcessor(), | |
556 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
557 | |
558 // Some adds and some deletes. | |
559 syncer::SyncChangeList changes; | |
560 changes.push_back(CreateSyncChange( | |
561 syncer::SyncChange::ACTION_ADD, CreateNotification(3))); | |
562 changes.push_back(CreateSyncChange( | |
563 syncer::SyncChange::ACTION_DELETE, n1->Copy())); | |
564 changes.push_back(CreateSyncChange( | |
565 syncer::SyncChange::ACTION_ADD, CreateNotification(4))); | |
566 | |
567 model()->ProcessSyncChanges(FROM_HERE, changes); | |
568 | |
569 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
570 EXPECT_EQ(2U, processor()->change_list_size()); | |
571 } | |
572 | |
573 // Process sync changes should ignore a bad ADD. | |
574 // Hangs: http://crbug.com/149712 | |
575 TEST_F(AppNotificationManagerSyncTest, | |
576 DISABLED_ProcessSyncChangesIgnoreBadAdd) { | |
577 AppNotification* n1 = CreateNotification(1); | |
578 model()->Add(n1); | |
579 AppNotification* n2 = CreateNotification(2); | |
580 model()->Add(n2); | |
581 model()->MergeDataAndStartSyncing( | |
582 syncer::APP_NOTIFICATIONS, | |
583 syncer::SyncDataList(), | |
584 PassProcessor(), | |
585 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
586 | |
587 // Some adds and some deletes. | |
588 syncer::SyncChangeList changes; | |
589 changes.push_back(CreateSyncChange( | |
590 syncer::SyncChange::ACTION_ADD, CreateNotification(1))); | |
591 | |
592 syncer::SyncError error = model()->ProcessSyncChanges(FROM_HERE, changes); | |
593 EXPECT_FALSE(error.IsSet()); | |
594 | |
595 EXPECT_EQ(2U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
596 EXPECT_EQ(2U, processor()->change_list_size()); | |
597 } | |
598 | |
599 // Process sync changes should ignore a bad DELETE. | |
600 TEST_F(AppNotificationManagerSyncTest, ProcessSyncChangesIgnoreBadDelete) { | |
601 AppNotification* n1 = CreateNotification(1); | |
602 model()->Add(n1); | |
603 AppNotification* n2 = CreateNotification(2); | |
604 model()->Add(n2); | |
605 model()->MergeDataAndStartSyncing( | |
606 syncer::APP_NOTIFICATIONS, | |
607 syncer::SyncDataList(), | |
608 PassProcessor(), | |
609 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
610 | |
611 // Some adds and some deletes. | |
612 syncer::SyncChangeList changes; | |
613 changes.push_back(CreateSyncChange( | |
614 syncer::SyncChange::ACTION_DELETE, CreateNotification(3))); | |
615 | |
616 syncer::SyncError error = model()->ProcessSyncChanges(FROM_HERE, changes); | |
617 EXPECT_FALSE(error.IsSet()); | |
618 | |
619 EXPECT_EQ(2U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
620 EXPECT_EQ(2U, processor()->change_list_size()); | |
621 } | |
622 | |
623 // Process sync changes should ignore bad UPDATEs. | |
624 // Hangs: http://crbug.com/149712 | |
625 TEST_F(AppNotificationManagerSyncTest, | |
626 DISABLED_ProcessSyncChangesIgnoreBadUpdates) { | |
627 AppNotification* n1 = CreateNotification(1); | |
628 model()->Add(n1); | |
629 AppNotification* n2 = CreateNotification(2); | |
630 model()->Add(n2); | |
631 model()->MergeDataAndStartSyncing( | |
632 syncer::APP_NOTIFICATIONS, | |
633 syncer::SyncDataList(), | |
634 PassProcessor(), | |
635 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
636 | |
637 // Some adds and some deletes. | |
638 syncer::SyncChangeList changes; | |
639 changes.push_back(CreateSyncChange( | |
640 syncer::SyncChange::ACTION_UPDATE, CreateNotification(3))); | |
641 AppNotification* n2_changed = n2->Copy(); | |
642 n2_changed->set_link_text(n2_changed->link_text() + "-changed"); | |
643 changes.push_back(CreateSyncChange( | |
644 syncer::SyncChange::ACTION_UPDATE, n2_changed)); | |
645 | |
646 syncer::SyncError error = model()->ProcessSyncChanges(FROM_HERE, changes); | |
647 EXPECT_FALSE(error.IsSet()); | |
648 | |
649 EXPECT_EQ(2U, model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
650 EXPECT_EQ(2U, processor()->change_list_size()); | |
651 } | |
652 | |
653 // Process over 15 changes when model is not empty. | |
654 TEST_F(AppNotificationManagerSyncTest, ProcessSyncChangesEmptyModelWithMax) { | |
655 const std::string& ext_id = "e1"; | |
656 model()->MergeDataAndStartSyncing( | |
657 syncer::APP_NOTIFICATIONS, | |
658 syncer::SyncDataList(), | |
659 PassProcessor(), | |
660 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
661 for (unsigned int i = 0; | |
662 i < AppNotificationManager::kMaxNotificationPerApp * 2; i++) { | |
663 syncer::SyncChangeList changes; | |
664 changes.push_back(CreateSyncChange( | |
665 syncer::SyncChange::ACTION_ADD, CreateNotification(false, i, ext_id))); | |
666 model()->ProcessSyncChanges(FROM_HERE, changes); | |
667 if (i < AppNotificationManager::kMaxNotificationPerApp) { | |
668 EXPECT_EQ(i + 1, | |
669 model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
670 } else { | |
671 EXPECT_EQ(AppNotificationManager::kMaxNotificationPerApp, | |
672 model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
673 for (unsigned int j = i; j > i - 5; j--) { | |
674 EXPECT_EQ( | |
675 AppNotificationManager::kMaxNotificationPerApp, | |
676 model()->GetAllSyncData(syncer::APP_NOTIFICATIONS).size()); | |
677 } | |
678 } | |
679 } | |
680 } | |
681 | |
682 // Stop syncing sets state correctly. | |
683 TEST_F(AppNotificationManagerSyncTest, StopSyncing) { | |
684 EXPECT_FALSE(model()->sync_processor_.get()); | |
685 EXPECT_FALSE(model()->models_associated_); | |
686 | |
687 model()->MergeDataAndStartSyncing( | |
688 syncer::APP_NOTIFICATIONS, | |
689 syncer::SyncDataList(), | |
690 PassProcessor(), | |
691 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
692 | |
693 EXPECT_TRUE(model()->sync_processor_.get()); | |
694 EXPECT_TRUE(model()->models_associated_); | |
695 | |
696 model()->StopSyncing(syncer::APP_NOTIFICATIONS); | |
697 EXPECT_FALSE(model()->sync_processor_.get()); | |
698 EXPECT_FALSE(model()->models_associated_); | |
699 } | |
700 | |
701 // Adds get pushed to sync but local only are skipped. | |
702 TEST_F(AppNotificationManagerSyncTest, AddsGetsSynced) { | |
703 model()->MergeDataAndStartSyncing( | |
704 syncer::APP_NOTIFICATIONS, | |
705 syncer::SyncDataList(), | |
706 PassProcessor(), | |
707 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
708 | |
709 AppNotification* n1 = CreateNotification(1); | |
710 model()->Add(n1); | |
711 AppNotification* n2 = CreateNotification(2); | |
712 model()->Add(n2); | |
713 AppNotification* n3 = CreateNotification(true, 2); | |
714 model()->Add(n3); | |
715 | |
716 EXPECT_EQ(2U, processor()->change_list_size()); | |
717 EXPECT_TRUE(processor()->ContainsGuid(n1->guid())); | |
718 syncer::SyncChange c1 = processor()->GetChangeByGuid(n1->guid()); | |
719 AssertSyncChange(c1, syncer::SyncChange::ACTION_ADD, *n1); | |
720 syncer::SyncChange c2 = processor()->GetChangeByGuid(n2->guid()); | |
721 AssertSyncChange(c2, syncer::SyncChange::ACTION_ADD, *n2); | |
722 } | |
723 | |
724 // Clear all gets pushed to sync. | |
725 TEST_F(AppNotificationManagerSyncTest, ClearAllGetsSynced) { | |
726 const std::string& ext_id = "e1"; | |
727 scoped_ptr<AppNotification> n1(CreateNotification(false, 1, ext_id)); | |
728 scoped_ptr<AppNotification> n2(CreateNotification(false, 2, ext_id)); | |
729 scoped_ptr<AppNotification> n3(CreateNotification(false, 3, ext_id)); | |
730 scoped_ptr<AppNotification> n4(CreateNotification(4)); | |
731 | |
732 syncer::SyncDataList initial_data; | |
733 initial_data.push_back( | |
734 AppNotificationManager::CreateSyncDataFromNotification(*n1)); | |
735 initial_data.push_back( | |
736 AppNotificationManager::CreateSyncDataFromNotification(*n2)); | |
737 initial_data.push_back( | |
738 AppNotificationManager::CreateSyncDataFromNotification(*n3)); | |
739 initial_data.push_back( | |
740 AppNotificationManager::CreateSyncDataFromNotification(*n4)); | |
741 model()->MergeDataAndStartSyncing( | |
742 syncer::APP_NOTIFICATIONS, | |
743 initial_data, | |
744 PassProcessor(), | |
745 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
746 | |
747 model()->ClearAll(ext_id); | |
748 | |
749 EXPECT_EQ(3U, processor()->change_list_size()); | |
750 EXPECT_TRUE(processor()->ContainsGuid(n1->guid())); | |
751 syncer::SyncChange c1 = processor()->GetChangeByGuid(n1->guid()); | |
752 AssertSyncChange(c1, syncer::SyncChange::ACTION_DELETE, *n1); | |
753 syncer::SyncChange c2 = processor()->GetChangeByGuid(n2->guid()); | |
754 AssertSyncChange(c2, syncer::SyncChange::ACTION_DELETE, *n2); | |
755 syncer::SyncChange c3 = processor()->GetChangeByGuid(n3->guid()); | |
756 AssertSyncChange(c3, syncer::SyncChange::ACTION_DELETE, *n3); | |
757 } | |
758 | |
759 } // namespace extensions | |
OLD | NEW |