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

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

Powered by Google App Engine
This is Rietveld 408576698