Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: chrome/browser/search_engines/template_url_service_sync_unittest.cc

Issue 7566036: Implement SyncableServices in TemplateURLService. Add related unittests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Initial upload Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/memory/scoped_ptr.h"
6 #include "base/string_util.h"
7 #include "base/time.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/search_engines/template_url.h"
10 #include "chrome/browser/search_engines/template_url_service.h"
11 #include "chrome/test/base/testing_profile.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 using base::Time;
15
16 // Extract the GUID from a search engine SyncData.
17 static std::string GetGUID(const SyncData& sync_data) {
18 return sync_data.GetSpecifics().GetExtension(
19 sync_pb::search_engine).sync_guid();
20 }
21
22 // Extract the keyword from a search engine SyncData.
23 static std::string GetURL(const SyncData& sync_data) {
24 return sync_data.GetSpecifics().GetExtension(
25 sync_pb::search_engine).url();
26 }
27
28 // Extract the keyword from a search engine SyncData.
29 static std::string GetKeyword(const SyncData& sync_data) {
30 return sync_data.GetSpecifics().GetExtension(
31 sync_pb::search_engine).keyword();
32 }
33
34 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
35 // back up to Sync.
36 class TestChangeProcessor : public SyncChangeProcessor {
37 public:
38 TestChangeProcessor() {
39 }
40 virtual ~TestChangeProcessor() { }
41
42 // Store a copy of all the changes passed in so we can examine them later.
43 virtual SyncError ProcessSyncChanges(
44 const tracked_objects::Location& from_here,
45 const SyncChangeList& change_list) {
46 change_map_.erase(change_map_.begin(), change_map_.end());
47 for (SyncChangeList::const_iterator iter = change_list.begin();
48 iter != change_list.end(); ++iter) {
49 change_map_[GetGUID(iter->sync_data())] = *iter;
50 }
51
52 return SyncError();
53 }
54
55 bool ContainsGUID(const std::string& guid) {
56 return change_map_.find(guid) != change_map_.end();
57 }
58
59 SyncChange GetChangeByGUID(const std::string& guid) {
60 DCHECK(ContainsGUID(guid));
61 return change_map_[guid];
62 }
63
64 int change_list_size() { return change_map_.size(); }
65
66 private:
67 // Track the changes received in ProcessSyncChanges.
68 std::map<std::string, SyncChange> change_map_;
69
70 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
71 };
72
73 class TemplateURLServiceSyncTest : public testing::Test {
74 public:
75 TemplateURLServiceSyncTest() {}
76
77 virtual void SetUp() {
78 profile_a_.reset(new TestingProfile);
79 model_a_.reset(new TemplateURLService(profile_a_.get()));
80 model_a_->Load();
81 profile_b_.reset(new TestingProfile);
82 model_b_.reset(new TemplateURLService(profile_b_.get()));
83 model_b_->Load();
84 }
85
86 virtual void TearDown() { }
87
88 TemplateURLService* model() { return model_a_.get(); }
89 // For readability, we redefine an accessor for Model A for use in tests that
90 // involve syncing two models.
91 TemplateURLService* model_a() { return model_a_.get(); }
92 TemplateURLService* model_b() { return model_b_.get(); }
93 TestChangeProcessor* processor() { return &processor_; }
94
95 // Create a TemplateURL with some test values. The caller owns the returned
96 // TemplateURL*.
97 TemplateURL* CreateTestTemplateURL() const {
98 TemplateURL* turl = new TemplateURL();
99 turl->SetURL("http://www.unittest.com/", 0, 0);
100 turl->set_keyword(ASCIIToUTF16("unittest"));
101 turl->set_short_name(ASCIIToUTF16("unittest"));
102 turl->set_safe_for_autoreplace(true);
103 GURL favicon_url("http://favicon.url");
104 turl->SetFaviconURL(favicon_url);
105 turl->set_date_created(Time::FromTimeT(100));
106 turl->set_last_modified(Time::FromTimeT(100));
107 turl->SetPrepopulateId(999999);
108 return turl;
109 }
110
111 // Convenience helpers for creating TemplateURLs with specific fields.
112 TemplateURL* CreateTestTemplateURL(std::string keyword,
113 std::string url) const {
114 TemplateURL* turl = CreateTestTemplateURL();
115 turl->set_keyword(UTF8ToUTF16(keyword));
116 turl->SetURL(url, 0, 0);
117 return turl;
118 }
119
120 TemplateURL* CreateTestTemplateURL(std::string keyword,
121 std::string url,
122 std::string guid) const {
123 TemplateURL* turl = CreateTestTemplateURL(keyword, url);
124 if (!guid.empty())
125 turl->set_sync_guid(guid);
126 return turl;
127 }
128
129 TemplateURL* CreateTestTemplateURL(std::string keyword,
130 std::string url,
131 std::string guid,
132 time_t last_mod) const {
133 TemplateURL* turl = CreateTestTemplateURL(keyword, url, guid);
134 turl->set_last_modified(Time::FromTimeT(last_mod));
135 return turl;
136 }
137
138 // Verifies the two TemplateURLs are equal.
139 // TODO(stevet): Share this with TemplateURLServiceTest.
140 void AssertEquals(const TemplateURL& expected,
141 const TemplateURL& actual) const {
142 ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.url(), actual.url()));
143 ASSERT_TRUE(TemplateURLRef::SameUrlRefs(expected.suggestions_url(),
144 actual.suggestions_url()));
145 ASSERT_EQ(expected.keyword(), actual.keyword());
146 ASSERT_EQ(expected.short_name(), actual.short_name());
147 ASSERT_EQ(JoinString(expected.input_encodings(), ';'),
148 JoinString(actual.input_encodings(), ';'));
149 ASSERT_TRUE(expected.GetFaviconURL() == actual.GetFaviconURL());
150 ASSERT_EQ(expected.id(), actual.id());
151 ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
152 ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
153 ASSERT_TRUE(expected.date_created() == actual.date_created());
154 ASSERT_TRUE(expected.last_modified() == actual.last_modified());
155 }
156
157 // Expect that two SyncDataLists have equal contents, in terms of the
158 // sync_guid, keyword, and url fields.
159 void AssertEquals(const SyncDataList& data1,
160 const SyncDataList& data2) const {
161 SyncDataMap map1 = TemplateURLService::CreateGUIDToSyncDataMap(data1);
162 SyncDataMap map2 = TemplateURLService::CreateGUIDToSyncDataMap(data2);
163
164 for (SyncDataMap::const_iterator iter1 = map1.begin();
165 iter1 != map1.end(); iter1++) {
166 SyncDataMap::iterator iter2 = map2.find(iter1->first);
167 if (iter2 != map2.end()) {
168 EXPECT_EQ(GetKeyword(iter1->second), GetKeyword(iter2->second));
169 EXPECT_EQ(GetURL(iter1->second), GetURL(iter2->second));
170 map2.erase(iter2);
171 }
172 }
173 EXPECT_EQ(0, static_cast<int>(map2.size()));
174 }
175
176 // Convenience helper for creating SyncData.
177 SyncData CreateTestSyncData(TemplateURL* turl) const {
178 SyncData data;
179 EXPECT_TRUE(TemplateURLService::CreateSearchEngineSyncData(*turl, &data));
180 return data;
181 }
182
183 // Convenience helper for creating SyncChanges.
184 SyncChange CreateTestSyncChange(SyncChange::SyncChangeType type,
185 TemplateURL* turl) const {
186 return SyncChange(type, CreateTestSyncData(turl));
187 }
188
189 // Helper that creates some initial sync data. We cheat a little by specifying
190 // GUIDs for easy identification later. We also make the last_modified times
191 // slightly older than CreateTestTemplateURL's default, to test conflict
192 // resolution.
193 SyncDataList CreateInitialSyncData() const {
194 SyncDataList list;
195
196 TemplateURL* turl =
197 CreateTestTemplateURL("key1", "http://key1.com", "key1", 90);
198 list.push_back(CreateTestSyncData(turl));
199 turl = CreateTestTemplateURL("key2", "http://key2.com", "key2", 90);
200 list.push_back(CreateTestSyncData(turl));
201 turl = CreateTestTemplateURL("key3", "http://key3.com", "key3", 90);
202 list.push_back(CreateTestSyncData(turl));
203
204 return list;
205 }
206
207 protected:
208 // We keep two TemplateURLServices to test syncing between them.
209 scoped_ptr<TestingProfile> profile_a_;
210 scoped_ptr<TemplateURLService> model_a_;
211 scoped_ptr<TestingProfile> profile_b_;
212 scoped_ptr<TemplateURLService> model_b_;
213
214 // Our dummy ChangeProcessor used to inspect changes pushed to Sync.
215 TestChangeProcessor processor_;
216
217 DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceSyncTest);
218 };
219
220 TEST_F(TemplateURLServiceSyncTest, SerializeDeserialize) {
221 // Create a TemplateURL and convert it into a sync specific type.
222 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL());
223 SyncData sync_data;
224 EXPECT_TRUE(TemplateURLService::CreateSearchEngineSyncData(*turl,
225 &sync_data));
226 // Convert the specifics back to a TemplateURL.
227 scoped_ptr<TemplateURL> deserialized(
228 TemplateURLService::ReadSearchEngineSyncData(sync_data));
229 EXPECT_TRUE(deserialized.get());
230 // Ensure that the original and the deserialized TURLs are equal in values.
231 AssertEquals(*turl, *deserialized);
232 }
233
234 TEST_F(TemplateURLServiceSyncTest, GetAllSyncDataBasic) {
235 model()->Add(CreateTestTemplateURL("key1", "http://key1.com"));
236 model()->Add(CreateTestTemplateURL("key2", "http://key2.com"));
237 model()->Add(CreateTestTemplateURL("key3", "http://key3.com"));
238 SyncDataList all_sync_data =
239 model()->GetAllSyncData(syncable::SEARCH_ENGINES);
240
241 EXPECT_EQ(3, static_cast<int>(all_sync_data.size()));
242
243 for (SyncDataList::const_iterator iter = all_sync_data.begin();
244 iter != all_sync_data.end(); ++iter) {
245 std::string guid = GetGUID(*iter);
246 const TemplateURL* service_turl = model()->GetTemplateURLForGUID(guid);
247 const TemplateURL* deserialized =
248 TemplateURLService::ReadSearchEngineSyncData(*iter);
249 AssertEquals(*service_turl, *deserialized);
250 }
251 }
252
253 TEST_F(TemplateURLServiceSyncTest, GetAllSyncDataNoExtensions) {
254 model()->Add(CreateTestTemplateURL("key1", "http://key1.com"));
255 model()->Add(CreateTestTemplateURL("key2", "http://key2.com"));
256 model()->Add(CreateTestTemplateURL(
257 "key3", "chrome-extension://blahblahblah"));
258 SyncDataList all_sync_data =
259 model()->GetAllSyncData(syncable::SEARCH_ENGINES);
260
261 EXPECT_EQ(2, static_cast<int>(all_sync_data.size()));
262
263 for (SyncDataList::const_iterator iter = all_sync_data.begin();
264 iter != all_sync_data.end(); ++iter) {
265 std::string guid = GetGUID(*iter);
266 const TemplateURL* service_turl = model()->GetTemplateURLForGUID(guid);
267 const TemplateURL* deserialized =
268 TemplateURLService::ReadSearchEngineSyncData(*iter);
269 AssertEquals(*service_turl, *deserialized);
270 }
271 }
272
273 TEST_F(TemplateURLServiceSyncTest, UniquifyKeyword) {
274 model()->Add(CreateTestTemplateURL("key1", "http://key1.com"));
275 // Create a key that conflicts with something in the model.
276 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL("key1",
277 "http://new.com",
278 "xyz"));
279 string16 new_keyword = model()->UniquifyKeyword(*turl);
280
281 EXPECT_EQ(UTF8ToUTF16("new.com"), new_keyword);
282 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
283
284 turl->set_keyword(new_keyword);
285 model()->Add(turl.release());
286 // Test a second collision. This time it should be resolved by actually
287 // modifying the original keyword, since the autogenerated keyword is already
288 // used.
289 turl.reset(CreateTestTemplateURL("key1", "http://new.com"));
290 new_keyword = model()->UniquifyKeyword(*turl);
291
292 EXPECT_EQ(UTF8ToUTF16("key1_"), new_keyword);
293 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
294
295 turl->set_keyword(new_keyword);
296 model()->Add(turl.release());
297 // Test a third collision. This should collide on both the autogenerated
298 // keyword and the first uniquification attempt.
299 turl.reset(CreateTestTemplateURL("key1", "http://new.com"));
300 new_keyword = model()->UniquifyKeyword(*turl);
301
302 EXPECT_EQ(UTF8ToUTF16("key1__"), new_keyword);
303 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
304 }
305
306 TEST_F(TemplateURLServiceSyncTest, ResolveSyncKeywordConflict) {
307 TemplateURL* original_turl =
308 CreateTestTemplateURL("key1", "http://key1.com", "", 9000);
309 string16 original_turl_keyword = original_turl->keyword();
310 model()->Add(original_turl);
311
312 // Create a key that does not conflict with something in the model.
313 scoped_ptr<TemplateURL> sync_turl(CreateTestTemplateURL("unique",
314 "http://new.com"));
315 string16 sync_keyword = sync_turl->keyword();
316 SyncChangeList changes;
317
318 // No conflict, no TURLs changed, no changes.
319 EXPECT_FALSE(model()->ResolveSyncKeywordConflict(sync_turl.get(), changes));
320 EXPECT_EQ(original_turl_keyword, original_turl->keyword());
321 EXPECT_EQ(sync_keyword, sync_turl->keyword());
322 EXPECT_EQ(0, static_cast<int>(changes.size()));
323
324 // Change sync keyword to something that conflicts, and make it older.
325 // Conflict, sync keyword is uniquified, and a SyncChange is added.
326 sync_turl->set_keyword(original_turl->keyword());
327 sync_turl->set_last_modified(Time::FromTimeT(8999));
328 EXPECT_TRUE(model()->ResolveSyncKeywordConflict(sync_turl.get(), changes));
329 EXPECT_NE(sync_keyword, sync_turl->keyword());
330 EXPECT_EQ(original_turl_keyword, original_turl->keyword());
331 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(sync_turl->keyword()));
332 EXPECT_EQ(1, static_cast<int>(changes.size()));
333 changes.erase(changes.begin());
334
335 // Sync is newer. Original TemplateURL keyword is uniquified, no SyncChange
336 // is added.
337 sync_turl->set_keyword(original_turl->keyword());
338 sync_keyword = sync_turl->keyword();
339 sync_turl->set_last_modified(Time::FromTimeT(9001));
340 EXPECT_TRUE(model()->ResolveSyncKeywordConflict(sync_turl.get(), changes));
341 EXPECT_EQ(sync_keyword, sync_turl->keyword());
342 EXPECT_NE(original_turl_keyword, original_turl->keyword());
343 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(sync_turl->keyword()));
344 EXPECT_EQ(0, static_cast<int>(changes.size()));
345
346 // Equal times. Same result as above. Sync left alone, original uniquified so
347 // sync_turl can fit.
348 sync_turl->set_keyword(original_turl->keyword());
349 sync_keyword = sync_turl->keyword();
350 // Note that we have to reset original_turl's last_modified time as it was
351 // modified above.
352 original_turl->set_last_modified(Time::FromTimeT(9000));
353 sync_turl->set_last_modified(Time::FromTimeT(9000));
354 EXPECT_TRUE(model()->ResolveSyncKeywordConflict(sync_turl.get(), changes));
355 EXPECT_EQ(sync_keyword, sync_turl->keyword());
356 EXPECT_NE(original_turl_keyword, original_turl->keyword());
357 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(sync_turl->keyword()));
358 EXPECT_EQ(0, static_cast<int>(changes.size()));
359 }
360
361 TEST_F(TemplateURLServiceSyncTest, FindDuplicateOfSyncTemplateURL) {
362 TemplateURL* original_turl =
363 CreateTestTemplateURL("key1", "http://key1.com");
364 model()->Add(original_turl);
365
366 // No matches at all.
367 scoped_ptr<TemplateURL> sync_turl(
368 CreateTestTemplateURL("key2", "http://key2.com"));
369 EXPECT_EQ(NULL, model()->FindDuplicateOfSyncTemplateURL(*sync_turl));
370
371 // URL matches, but not keyword. No dupe.
372 sync_turl->SetURL("http://key1.com", 0 , 0);
373 EXPECT_EQ(NULL, model()->FindDuplicateOfSyncTemplateURL(*sync_turl));
374
375 // Keyword matches, but not URL. No dupe.
376 sync_turl->SetURL("http://key2.com", 0 , 0);
377 sync_turl->set_keyword(UTF8ToUTF16("key1"));
378 EXPECT_EQ(NULL, model()->FindDuplicateOfSyncTemplateURL(*sync_turl));
379
380 // Duplicate.
381 sync_turl->SetURL("http://key1.com", 0 , 0);
382 const TemplateURL* dupe_turl =
383 model()->FindDuplicateOfSyncTemplateURL(*sync_turl);
384 EXPECT_EQ(dupe_turl->keyword(), sync_turl->keyword());
385 EXPECT_EQ(dupe_turl->url()->url(), sync_turl->url()->url());
386 }
387
388 TEST_F(TemplateURLServiceSyncTest, MergeSyncAndLocalURLDuplicates) {
389 TemplateURL* original_turl =
390 CreateTestTemplateURL("key1", "http://key1.com", "", 9000);
391 model()->Add(original_turl);
392 TemplateURL* sync_turl =
393 CreateTestTemplateURL("key1", "http://key1.com", "", 9001);
394 SyncChangeList changes;
395
396 // The sync TemplateURL is newer. It should replace the original TemplateURL.
397 model()->MergeSyncAndLocalURLDuplicates(sync_turl, original_turl, changes);
398 EXPECT_EQ(sync_turl, model()->GetTemplateURLForKeyword(sync_turl->keyword()));
399 EXPECT_EQ(0, static_cast<int>(changes.size()));
400
401 // The sync TemplateURL is older. The existing TemplateURL should win and a
402 // SyncChange should be added to the list.
403 TemplateURL* sync_turl2 =
404 CreateTestTemplateURL("key1", "http://key1.com", "", 8999);
405 model()->MergeSyncAndLocalURLDuplicates(sync_turl2, sync_turl, changes);
406 EXPECT_EQ(sync_turl,
407 model()->GetTemplateURLForKeyword(sync_turl2->keyword()));
408 EXPECT_EQ(1, static_cast<int>(changes.size()));
409 }
410
411 TEST_F(TemplateURLServiceSyncTest, StartSyncEmpty) {
412 model()->MergeDataAndStartSyncing(
413 syncable::SEARCH_ENGINES,
414 SyncDataList(), // Empty.
415 processor());
416
417 EXPECT_EQ(0, static_cast<int>(
418 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
419 EXPECT_EQ(0, processor()->change_list_size());
420 }
421
422 TEST_F(TemplateURLServiceSyncTest, MergeIntoEmpty) {
423 SyncDataList initial_data = CreateInitialSyncData();
424
425 model()->MergeDataAndStartSyncing(
426 syncable::SEARCH_ENGINES,
427 initial_data,
428 processor());
429
430 EXPECT_EQ(3, static_cast<int>(
431 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
432 // We expect the model to have accepted all of the initial sync data. Search
433 // through the model using the GUIDs to ensure that they're present.
434 for (SyncDataList::const_iterator iter = initial_data.begin();
435 iter != initial_data.end(); ++iter) {
436 std::string guid = GetGUID(*iter);
437 EXPECT_TRUE(model()->GetTemplateURLForGUID(guid));
438 }
439
440 EXPECT_EQ(0, processor()->change_list_size());
441 }
442
443 TEST_F(TemplateURLServiceSyncTest, MergeInAllNewData) {
444 model()->Add(CreateTestTemplateURL(
445 "google.com", "http://google.com", "abc"));
446 model()->Add(CreateTestTemplateURL("yahoo.com", "http://yahoo.com", "def"));
447 model()->Add(CreateTestTemplateURL("bing.com", "http://bing.com", "xyz"));
448 SyncDataList initial_data = CreateInitialSyncData();
449
450 model()->MergeDataAndStartSyncing(
451 syncable::SEARCH_ENGINES,
452 initial_data,
453 processor());
454
455 EXPECT_EQ(6, static_cast<int>(
456 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
457 // We expect the model to have accepted all of the initial sync data. Search
458 // through the model using the GUIDs to ensure that they're present.
459 for (SyncDataList::const_iterator iter = initial_data.begin();
460 iter != initial_data.end(); ++iter) {
461 std::string guid = GetGUID(*iter);
462 EXPECT_TRUE(model()->GetTemplateURLForGUID(guid));
463 }
464 // All the original TemplateURLs should also remain in the model.
465 EXPECT_TRUE(model()->GetTemplateURLForKeyword(UTF8ToUTF16("google.com")));
466 EXPECT_TRUE(model()->GetTemplateURLForKeyword(UTF8ToUTF16("yahoo.com")));
467 EXPECT_TRUE(model()->GetTemplateURLForKeyword(UTF8ToUTF16("bing.com")));
468 // Ensure that Sync received the expected changes.
469 EXPECT_EQ(3, processor()->change_list_size());
470 EXPECT_TRUE(processor()->ContainsGUID("abc"));
471 EXPECT_TRUE(processor()->ContainsGUID("def"));
472 EXPECT_TRUE(processor()->ContainsGUID("xyz"));
473 }
474
475 TEST_F(TemplateURLServiceSyncTest, MergeSyncIsTheSame) {
476 // The local data is the same as the sync data merged in. i.e. - There have
477 // been no changes since the last time we synced. Even the last_modified
478 // timestamps are the same.
479 SyncDataList initial_data = CreateInitialSyncData();
480 for (SyncDataList::const_iterator iter = initial_data.begin();
481 iter != initial_data.end(); ++iter) {
482 TemplateURL* converted =
483 TemplateURLService::ReadSearchEngineSyncData(*iter);
484 model()->Add(converted);
485 }
486
487 model()->MergeDataAndStartSyncing(
488 syncable::SEARCH_ENGINES,
489 initial_data,
490 processor());
491
492 EXPECT_EQ(3, static_cast<int>(
493 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
494 for (SyncDataList::const_iterator iter = initial_data.begin();
495 iter != initial_data.end(); ++iter) {
496 std::string guid = GetGUID(*iter);
497 EXPECT_TRUE(model()->GetTemplateURLForGUID(guid));
498 }
499 EXPECT_EQ(0, processor()->change_list_size());
500 }
501
502 TEST_F(TemplateURLServiceSyncTest, MergeUpdateFromSync) {
503 // The local data is the same as the sync data merged in, but timestamps have
504 // changed. Ensure the right fields are merged in.
505 SyncDataList initial_data;
506 TemplateURL* turl1 = CreateTestTemplateURL(
507 "google.com", "http://google.com", "abc", 9000);
508 model()->Add(turl1);
509 TemplateURL* turl2 = CreateTestTemplateURL(
510 "bing.com", "http://bing.com", "xyz", 9000);
511 model()->Add(turl2);
512
513 TemplateURL turl1_newer(*turl1);
514 turl1_newer.set_last_modified(Time::FromTimeT(9999));
515 turl1_newer.SetURL("http://google.ca", 0, 0);
516 SyncData data1;
517 TemplateURLService::CreateSearchEngineSyncData(turl1_newer, &data1);
518 initial_data.push_back(data1);
519
520 TemplateURL turl2_older(*turl2);
521 turl2_older.set_last_modified(Time::FromTimeT(8888));
522 turl2_older.SetURL("http://bing.ca", 0, 0);
523 SyncData data2;
524 TemplateURLService::CreateSearchEngineSyncData(turl2_older, &data2);
525 initial_data.push_back(data2);
526
527 model()->MergeDataAndStartSyncing(
528 syncable::SEARCH_ENGINES,
529 initial_data,
530 processor());
531
532 // Both were local updates, so we expect the same count.
533 EXPECT_EQ(2, static_cast<int>(
534 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
535
536 // Check that the first replaced the initial Google TemplateURL.
537 EXPECT_EQ(turl1, model()->GetTemplateURLForGUID("abc"));
538 EXPECT_EQ("http://google.ca", turl1->url()->url());
539
540 // Check that the second produced an upstream update to the Bing TemplateURL.
541 EXPECT_EQ(1, processor()->change_list_size());
542 EXPECT_TRUE(processor()->ContainsGUID("xyz"));
543 SyncChange change = processor()->GetChangeByGUID("xyz");
544 EXPECT_TRUE(change.change_type() == SyncChange::ACTION_UPDATE);
545 EXPECT_EQ("http://bing.com", GetURL(change.sync_data()));
546 }
547
548 TEST_F(TemplateURLServiceSyncTest, MergeAddFromOlderSyncData) {
549 // GUIDs all differ, so this is data to be added from Sync, but the timestamps
550 // from Sync are older. Set up the local data so that one is a dupe, one has a
551 // conflicting keyword, and the last has no conflicts (a clean ADD).
552 model()->Add(CreateTestTemplateURL(
553 "key1", "http://key1.com", "aaa")); // dupe
554 model()->Add(CreateTestTemplateURL(
555 "key2", "http://expected.com", "bbb")); // keyword conflict
556 model()->Add(CreateTestTemplateURL(
557 "unique", "http://unique.com", "ccc")); // add
558
559 model()->MergeDataAndStartSyncing(
560 syncable::SEARCH_ENGINES,
561 CreateInitialSyncData(),
562 processor());
563
564 // The dupe results in a merge. The other two should be added to the model.
565 EXPECT_EQ(5, static_cast<int>(
566 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
567
568 // The key1 duplicate results in the local copy winning. Ensure that Sync's
569 // copy was not added, and the local copy is pushed upstream to Sync as an
570 // update. The local copy should have received the sync data's GUID.
571 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
572 // Check changes for the UPDATE.
573 EXPECT_TRUE(processor()->ContainsGUID("key1"));
574 SyncChange key1_change = processor()->GetChangeByGUID("key1");
575 EXPECT_EQ(SyncChange::ACTION_UPDATE, key1_change.change_type());
576 EXPECT_FALSE(model()->GetTemplateURLForGUID("aaa"));
577
578 // The key2 keyword conflict results in the local copy winning, so ensure it
579 // retains the original keyword, and that an update to the sync copy is pushed
580 // upstream to Sync. Both TemplateURLs should be found locally, however.
581 const TemplateURL* key2 = model()->GetTemplateURLForGUID("bbb");
582 EXPECT_TRUE(key2);
583 EXPECT_EQ(UTF8ToUTF16("key2"), key2->keyword());
584 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
585 // Check changes for the UPDATE.
586 EXPECT_TRUE(processor()->ContainsGUID("key2"));
587 SyncChange key2_change = processor()->GetChangeByGUID("key2");
588 EXPECT_EQ(SyncChange::ACTION_UPDATE, key2_change.change_type());
589 EXPECT_EQ("key2.com", GetKeyword(key2_change.sync_data()));
590
591 // The last TemplateURL should have had no conflicts and was just added. It
592 // should not have replaced the third local TemplateURL.
593 EXPECT_TRUE(model()->GetTemplateURLForGUID("ccc"));
594 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
595
596 // Two UPDATEs and two ADDs.
597 EXPECT_EQ(4, processor()->change_list_size());
598 // Two ADDs should be pushed up to Sync.
599 EXPECT_TRUE(processor()->ContainsGUID("bbb"));
600 EXPECT_EQ(SyncChange::ACTION_ADD,
601 processor()->GetChangeByGUID("bbb").change_type());
602 EXPECT_TRUE(processor()->ContainsGUID("ccc"));
603 EXPECT_EQ(SyncChange::ACTION_ADD,
604 processor()->GetChangeByGUID("ccc").change_type());
605 }
606
607 TEST_F(TemplateURLServiceSyncTest, MergeAddFromNewerSyncData) {
608 // GUIDs all differ, so this is data to be added from Sync, but the timestamps
609 // from Sync are newer. Set up the local data so that one is a dupe, one has a
610 // conflicting keyword, and the last has no conflicts (a clean ADD).
611 model()->Add(CreateTestTemplateURL(
612 "key1", "http://key1.com", "aaa", 10)); // dupe
613 model()->Add(CreateTestTemplateURL(
614 "key2", "http://expected.com", "bbb", 10)); // keyword conflict
615 model()->Add(CreateTestTemplateURL(
616 "unique", "http://unique.com", "ccc", 10)); // add
617
618 model()->MergeDataAndStartSyncing(
619 syncable::SEARCH_ENGINES,
620 CreateInitialSyncData(),
621 processor());
622
623 // The dupe results in a merge. The other two should be added to the model.
624 EXPECT_EQ(5, static_cast<int>(
625 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
626
627 // The key1 duplicate results in Sync's copy winning. Ensure that Sync's
628 // copy replaced the local copy.
629 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
630 EXPECT_FALSE(model()->GetTemplateURLForGUID("aaa"));
631
632 // The key2 keyword conflict results in Sync's copy winning, so ensure it
633 // retains the original keyword. The local copy should get a uniquified
634 // keyword. Both TemplateURLs should be found locally.
635 const TemplateURL* key2_sync = model()->GetTemplateURLForGUID("key2");
636 EXPECT_TRUE(key2_sync);
637 EXPECT_EQ(UTF8ToUTF16("key2"), key2_sync->keyword());
638 const TemplateURL* key2_local = model()->GetTemplateURLForGUID("bbb");
639 EXPECT_TRUE(key2_local);
640 EXPECT_EQ(UTF8ToUTF16("expected.com"), key2_local->keyword());
641
642 // The last TemplateURL should have had no conflicts and was just added. It
643 // should not have replaced the third local TemplateURL.
644 EXPECT_TRUE(model()->GetTemplateURLForGUID("ccc"));
645 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
646
647 // Two ADDs.
648 EXPECT_EQ(2, processor()->change_list_size());
649 // Two ADDs should be pushed up to Sync.
650 EXPECT_TRUE(processor()->ContainsGUID("bbb"));
651 EXPECT_EQ(SyncChange::ACTION_ADD,
652 processor()->GetChangeByGUID("bbb").change_type());
653 EXPECT_TRUE(processor()->ContainsGUID("ccc"));
654 EXPECT_EQ(SyncChange::ACTION_ADD,
655 processor()->GetChangeByGUID("ccc").change_type());
656 }
657
658 TEST_F(TemplateURLServiceSyncTest, ProcessChangesEmptyModel) {
659 // We initially have no data.
660 model()->MergeDataAndStartSyncing(
661 syncable::SEARCH_ENGINES,
662 SyncDataList(),
663 processor());
664
665 // Set up a bunch of ADDs.
666 SyncChangeList changes;
667 changes.push_back(CreateTestSyncChange(
668 SyncChange::ACTION_ADD,
669 CreateTestTemplateURL("key1", "http://key1.com", "key1")));
670 changes.push_back(CreateTestSyncChange(
671 SyncChange::ACTION_ADD,
672 CreateTestTemplateURL("key2", "http://key2.com", "key2")));
673 changes.push_back(CreateTestSyncChange(
674 SyncChange::ACTION_ADD,
675 CreateTestTemplateURL("key3", "http://key3.com", "key3")));
676
677 model()->ProcessSyncChanges(FROM_HERE, changes);
678
679 EXPECT_EQ(3, static_cast<int>(
680 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
681 EXPECT_EQ(0, processor()->change_list_size());
682 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
683 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
684 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
685 }
686
687 TEST_F(TemplateURLServiceSyncTest, ProcessChangesNoConflicts) {
688 model()->MergeDataAndStartSyncing(
689 syncable::SEARCH_ENGINES,
690 CreateInitialSyncData(),
691 processor());
692
693 // Process different types of changes, without conflicts.
694 SyncChangeList changes;
695 changes.push_back(CreateTestSyncChange(
696 SyncChange::ACTION_ADD,
697 CreateTestTemplateURL("key4", "http://key4.com", "key4")));
698 changes.push_back(CreateTestSyncChange(
699 SyncChange::ACTION_UPDATE,
700 CreateTestTemplateURL("newkeyword", "http://new.com", "key2")));
701 changes.push_back(CreateTestSyncChange(
702 SyncChange::ACTION_DELETE,
703 CreateTestTemplateURL("key3", "http://key3.com", "key3")));
704
705 model()->ProcessSyncChanges(FROM_HERE, changes);
706
707 // Add one, remove one, update one, so the number shouldn't change.
708 EXPECT_EQ(3, static_cast<int>(
709 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
710 EXPECT_EQ(0, processor()->change_list_size());
711 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
712 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
713 const TemplateURL* turl = model()->GetTemplateURLForGUID("key2");
714 EXPECT_TRUE(turl);
715 EXPECT_EQ(UTF8ToUTF16("newkeyword"), turl->keyword());
716 EXPECT_EQ("http://new.com", turl->url()->url());
717 EXPECT_FALSE(model()->GetTemplateURLForGUID("key3"));
718 EXPECT_TRUE(model()->GetTemplateURLForGUID("key4"));
719 }
720
721 TEST_F(TemplateURLServiceSyncTest, ProcessChangesWithConflictsSyncWins) {
722 model()->MergeDataAndStartSyncing(
723 syncable::SEARCH_ENGINES,
724 CreateInitialSyncData(),
725 processor());
726
727 // Process different types of changes, with conflicts. Note that all this data
728 // has a newer timestamp, so Sync will win in these scenarios.
729 SyncChangeList changes;
730 changes.push_back(CreateTestSyncChange(
731 SyncChange::ACTION_ADD,
732 CreateTestTemplateURL("key2", "http://new.com", "aaa")));
733 changes.push_back(CreateTestSyncChange(
734 SyncChange::ACTION_UPDATE,
735 CreateTestTemplateURL("key3", "http://key3.com", "key1")));
736
737 model()->ProcessSyncChanges(FROM_HERE, changes);
738
739 // Add one, update one, so we're up to 4.
740 EXPECT_EQ(4, static_cast<int>(
741 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
742 // Sync is always newer here, so it should always win (i.e. - local changes,
743 // nothing pushed to Sync).
744 EXPECT_EQ(0, processor()->change_list_size());
745
746 // aaa conflicts with key2 and wins, forcing key2's keyword to update.
747 EXPECT_TRUE(model()->GetTemplateURLForGUID("aaa"));
748 EXPECT_EQ(model()->GetTemplateURLForGUID("aaa"),
749 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key2")));
750 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
751 EXPECT_EQ(model()->GetTemplateURLForGUID("key2"),
752 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key2.com")));
753 // key1 update conflicts with key3 and wins, forcing key3's keyword to update.
754 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
755 EXPECT_EQ(model()->GetTemplateURLForGUID("key1"),
756 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key3")));
757 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
758 EXPECT_EQ(model()->GetTemplateURLForGUID("key3"),
759 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key3.com")));
760 }
761
762 TEST_F(TemplateURLServiceSyncTest, ProcessChangesWithConflictsLocalWins) {
763 model()->MergeDataAndStartSyncing(
764 syncable::SEARCH_ENGINES,
765 CreateInitialSyncData(),
766 processor());
767
768 // Process different types of changes, with conflicts. Note that all this data
769 // has an older timestamp, so the local data will win in these scenarios.
770 SyncChangeList changes;
771 changes.push_back(CreateTestSyncChange(
772 SyncChange::ACTION_ADD,
773 CreateTestTemplateURL("key2", "http://new.com", "aaa", 10)));
774 changes.push_back(CreateTestSyncChange(
775 SyncChange::ACTION_UPDATE,
776 CreateTestTemplateURL("key3", "http://key3.com", "key1", 10)));
777
778 model()->ProcessSyncChanges(FROM_HERE, changes);
779
780 // Add one, update one, so we're up to 4.
781 EXPECT_EQ(4, static_cast<int>(
782 model()->GetAllSyncData(syncable::SEARCH_ENGINES).size()));
783 // Local data wins twice so two updates are pushed up to Sync.
784 EXPECT_EQ(2, processor()->change_list_size());
785
786 // aaa conflicts with key2 and loses, forcing it's keyword to update.
787 EXPECT_TRUE(model()->GetTemplateURLForGUID("aaa"));
788 EXPECT_EQ(model()->GetTemplateURLForGUID("aaa"),
789 model()->GetTemplateURLForKeyword(UTF8ToUTF16("new.com")));
790 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
791 EXPECT_EQ(model()->GetTemplateURLForGUID("key2"),
792 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key2")));
793 // key1 update conflicts with key3 and loses, forcing key1's keyword to
794 // update.
795 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
796 EXPECT_EQ(model()->GetTemplateURLForGUID("key1"),
797 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key3.com")));
798 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
799 EXPECT_EQ(model()->GetTemplateURLForGUID("key3"),
800 model()->GetTemplateURLForKeyword(UTF8ToUTF16("key3")));
801
802 EXPECT_EQ(SyncChange::ACTION_UPDATE,
803 processor()->GetChangeByGUID("aaa").change_type());
804 EXPECT_EQ(SyncChange::ACTION_UPDATE,
805 processor()->GetChangeByGUID("key1").change_type());
806 }
807
808 TEST_F(TemplateURLServiceSyncTest, ProcessTemplateURLChange) {
809 // Ensure that ProcessTemplateURLChange is called and pushes the correct
810 // changes to Sync whenever local changes are made to TemplateURLs.
811 model()->MergeDataAndStartSyncing(
812 syncable::SEARCH_ENGINES,
813 CreateInitialSyncData(),
814 processor());
815
816 // Add a new search engine.
817 TemplateURL* new_turl =
818 CreateTestTemplateURL("baidu", "http://baidu.cn", "new");
819 model()->Add(new_turl);
820 EXPECT_EQ(1, processor()->change_list_size());
821 SyncChange change = processor()->GetChangeByGUID("new");
822 EXPECT_EQ(SyncChange::ACTION_ADD, change.change_type());
823 EXPECT_EQ("baidu", GetKeyword(change.sync_data()));
824 EXPECT_EQ("http://baidu.cn", GetURL(change.sync_data()));
825
826 // Change a keyword.
827 const TemplateURL* existing_turl = model()->GetTemplateURLForGUID("key1");
828 model()->ResetTemplateURL(existing_turl,
829 existing_turl->short_name(),
830 UTF8ToUTF16("k"),
831 existing_turl->url()->url());
832 EXPECT_EQ(1, processor()->change_list_size());
833 change = processor()->GetChangeByGUID("key1");
834 EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
835 EXPECT_EQ("k", GetKeyword(change.sync_data()));
836
837 // Remove an existing search engine.
838 existing_turl = model()->GetTemplateURLForGUID("key2");
839 model()->Remove(existing_turl);
840 EXPECT_EQ(1, processor()->change_list_size());
841 change = processor()->GetChangeByGUID("key2");
842 EXPECT_EQ(SyncChange::ACTION_DELETE, change.change_type());
843 }
844
845 TEST_F(TemplateURLServiceSyncTest, MergeTwoClientsBasic) {
846 // Start off B with some empty data.
847 model_b()->MergeDataAndStartSyncing(
848 syncable::SEARCH_ENGINES,
849 CreateInitialSyncData(),
850 processor());
851
852 // Merge A and B. All of B's data should transfer over to A, which initially
853 // has no data.
854 model_a()->MergeDataAndStartSyncing(
855 syncable::SEARCH_ENGINES,
856 model_b()->GetAllSyncData(syncable::SEARCH_ENGINES),
857 model_b());
858
859 // They should be consistent.
860 AssertEquals(model_a()->GetAllSyncData(syncable::SEARCH_ENGINES),
861 model_b()->GetAllSyncData(syncable::SEARCH_ENGINES));
862 }
863
864 TEST_F(TemplateURLServiceSyncTest, MergeTwoClientsDupesAndConflicts) {
865 // Start off B with some empty data.
866 model_b()->MergeDataAndStartSyncing(
867 syncable::SEARCH_ENGINES,
868 CreateInitialSyncData(),
869 processor());
870
871 // Set up A so we have some interesting duplicates and conflicts.
872 model_a()->Add(CreateTestTemplateURL(
873 "key4", "http://key4.com", "key4")); // Added
874 model_a()->Add(CreateTestTemplateURL(
875 "key2", "http://key2.com", "key2")); // Merge - Copy of key2.
876 model_a()->Add(CreateTestTemplateURL(
877 "key3", "http://key3.com", "key5", 10)); // Merge - Dupe of key3.
878 model_a()->Add(CreateTestTemplateURL(
879 "key1", "http://key6.com", "key6", 10)); // Keyword conflict with key1
880
881 // Merge A and B.
882 model_a()->MergeDataAndStartSyncing(
883 syncable::SEARCH_ENGINES,
884 model_b()->GetAllSyncData(syncable::SEARCH_ENGINES),
885 model_b());
886
887 // They should be consistent.
888 AssertEquals(model_a()->GetAllSyncData(syncable::SEARCH_ENGINES),
889 model_b()->GetAllSyncData(syncable::SEARCH_ENGINES));
890 }
891
892 TEST_F(TemplateURLServiceSyncTest, StopSyncing) {
893 model()->MergeDataAndStartSyncing(
894 syncable::SEARCH_ENGINES,
895 CreateInitialSyncData(),
896 processor());
897 model()->StopSyncing(syncable::SEARCH_ENGINES);
898
899 SyncChangeList changes;
900 changes.push_back(CreateTestSyncChange(
901 SyncChange::ACTION_UPDATE,
902 CreateTestTemplateURL("newkeyword", "http://new.com", "key2")));
903 model()->ProcessSyncChanges(FROM_HERE, changes);
904
905 // Ensure that the sync changes were not accepted.
906 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
907 EXPECT_FALSE(model()->GetTemplateURLForKeyword(UTF8ToUTF16("newkeyword")));
908 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698