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/memory/scoped_ptr.h"
6 #include "base/memory/scoped_vector.h"
7 #include "base/run_loop.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h"
11 #include "chrome/browser/search_engines/template_url.h"
12 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
13 #include "chrome/browser/search_engines/template_url_service.h"
14 #include "chrome/browser/search_engines/template_url_service_factory.h"
15 #include "chrome/browser/search_engines/template_url_service_test_util.h"
16 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/test/base/testing_pref_service_syncable.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "extensions/common/constants.h"
22 #include "net/base/net_util.h"
23 #include "sync/api/sync_change_processor_wrapper_for_test.h"
24 #include "sync/api/sync_error_factory.h"
25 #include "sync/api/sync_error_factory_mock.h"
26 #include "sync/protocol/search_engine_specifics.pb.h"
27 #include "sync/protocol/sync.pb.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 using base::ASCIIToUTF16;
31 using base::UTF8ToUTF16;
32 using base::Time;
33
34 namespace {
35
36 // Extract the GUID from a search engine syncer::SyncData.
GetGUID(const syncer::SyncData & sync_data)37 std::string GetGUID(const syncer::SyncData& sync_data) {
38 return sync_data.GetSpecifics().search_engine().sync_guid();
39 }
40
41 // Extract the URL from a search engine syncer::SyncData.
GetURL(const syncer::SyncData & sync_data)42 std::string GetURL(const syncer::SyncData& sync_data) {
43 return sync_data.GetSpecifics().search_engine().url();
44 }
45
46 // Extract the keyword from a search engine syncer::SyncData.
GetKeyword(const syncer::SyncData & sync_data)47 std::string GetKeyword(const syncer::SyncData& sync_data) {
48 return sync_data.GetSpecifics().search_engine().keyword();
49 }
50
51 // Much like TemplateURLService::CreateSyncDataFromTemplateURL(), but allows the
52 // caller to override the keyword, URL, or GUID fields with empty strings, in
53 // order to create custom data that should be handled specially when synced to a
54 // client.
CreateCustomSyncData(const TemplateURL & turl,bool autogenerate_keyword,const std::string & url,const std::string & sync_guid)55 syncer::SyncData CreateCustomSyncData(const TemplateURL& turl,
56 bool autogenerate_keyword,
57 const std::string& url,
58 const std::string& sync_guid) {
59 sync_pb::EntitySpecifics specifics;
60 sync_pb::SearchEngineSpecifics* se_specifics =
61 specifics.mutable_search_engine();
62 se_specifics->set_short_name(base::UTF16ToUTF8(turl.short_name()));
63 se_specifics->set_keyword(
64 autogenerate_keyword ? std::string() : base::UTF16ToUTF8(turl.keyword()));
65 se_specifics->set_favicon_url(turl.favicon_url().spec());
66 se_specifics->set_url(url);
67 se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace());
68 se_specifics->set_originating_url(turl.originating_url().spec());
69 se_specifics->set_date_created(turl.date_created().ToInternalValue());
70 se_specifics->set_input_encodings(JoinString(turl.input_encodings(), ';'));
71 se_specifics->set_show_in_default_list(turl.show_in_default_list());
72 se_specifics->set_suggestions_url(turl.suggestions_url());
73 se_specifics->set_prepopulate_id(turl.prepopulate_id());
74 se_specifics->set_autogenerate_keyword(autogenerate_keyword);
75 se_specifics->set_instant_url(turl.instant_url());
76 se_specifics->set_last_modified(turl.last_modified().ToInternalValue());
77 se_specifics->set_sync_guid(sync_guid);
78 return syncer::SyncData::CreateLocalData(turl.sync_guid(), // Must be valid!
79 se_specifics->keyword(), specifics);
80 }
81
82
83 // TestChangeProcessor --------------------------------------------------------
84
85 // Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
86 // back up to Sync.
87 class TestChangeProcessor : public syncer::SyncChangeProcessor {
88 public:
89 TestChangeProcessor();
90 virtual ~TestChangeProcessor();
91
92 // Store a copy of all the changes passed in so we can examine them later.
93 virtual syncer::SyncError ProcessSyncChanges(
94 const tracked_objects::Location& from_here,
95 const syncer::SyncChangeList& change_list) OVERRIDE;
96
GetAllSyncData(syncer::ModelType type) const97 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
98 OVERRIDE {
99 return syncer::SyncDataList();
100 }
101
contains_guid(const std::string & guid) const102 bool contains_guid(const std::string& guid) const {
103 return change_map_.count(guid) != 0;
104 }
105
change_for_guid(const std::string & guid) const106 syncer::SyncChange change_for_guid(const std::string& guid) const {
107 DCHECK(contains_guid(guid));
108 return change_map_.find(guid)->second;
109 }
110
change_list_size()111 size_t change_list_size() { return change_map_.size(); }
112
set_erroneous(bool erroneous)113 void set_erroneous(bool erroneous) { erroneous_ = erroneous; }
114
115 private:
116 // Track the changes received in ProcessSyncChanges.
117 std::map<std::string, syncer::SyncChange> change_map_;
118 bool erroneous_;
119
120 DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
121 };
122
TestChangeProcessor()123 TestChangeProcessor::TestChangeProcessor() : erroneous_(false) {
124 }
125
~TestChangeProcessor()126 TestChangeProcessor::~TestChangeProcessor() {
127 }
128
ProcessSyncChanges(const tracked_objects::Location & from_here,const syncer::SyncChangeList & change_list)129 syncer::SyncError TestChangeProcessor::ProcessSyncChanges(
130 const tracked_objects::Location& from_here,
131 const syncer::SyncChangeList& change_list) {
132 if (erroneous_)
133 return syncer::SyncError(
134 FROM_HERE,
135 syncer::SyncError::DATATYPE_ERROR,
136 "Some error.",
137 syncer::SEARCH_ENGINES);
138
139 change_map_.erase(change_map_.begin(), change_map_.end());
140 for (syncer::SyncChangeList::const_iterator iter = change_list.begin();
141 iter != change_list.end(); ++iter)
142 change_map_[GetGUID(iter->sync_data())] = *iter;
143 return syncer::SyncError();
144 }
145
146
147 } // namespace
148
149
150 // TemplateURLServiceSyncTest -------------------------------------------------
151
152 class TemplateURLServiceSyncTest : public testing::Test {
153 public:
154 typedef TemplateURLService::SyncDataMap SyncDataMap;
155
156 TemplateURLServiceSyncTest();
157
158 virtual void SetUp() OVERRIDE;
159 virtual void TearDown() OVERRIDE;
160
model()161 TemplateURLService* model() { return test_util_a_.model(); }
162 // For readability, we redefine an accessor for Model A for use in tests that
163 // involve syncing two models.
model_a()164 TemplateURLService* model_a() { return test_util_a_.model(); }
model_b()165 TemplateURLService* model_b() { return model_b_.get(); }
profile_a()166 TestingProfile* profile_a() { return test_util_a_.profile(); }
processor()167 TestChangeProcessor* processor() { return sync_processor_.get(); }
168 scoped_ptr<syncer::SyncChangeProcessor> PassProcessor();
169 scoped_ptr<syncer::SyncErrorFactory> CreateAndPassSyncErrorFactory();
170
171 // Create a TemplateURL with some test values. The caller owns the returned
172 // TemplateURL*.
173 TemplateURL* CreateTestTemplateURL(const base::string16& keyword,
174 const std::string& url,
175 const std::string& guid = std::string(),
176 time_t last_mod = 100,
177 bool safe_for_autoreplace = false,
178 bool created_by_policy = false) const;
179
180 // Verifies the two TemplateURLs are equal.
181 // TODO(stevet): Share this with TemplateURLServiceTest.
182 void AssertEquals(const TemplateURL& expected,
183 const TemplateURL& actual) const;
184
185 // Expect that two syncer::SyncDataLists have equal contents, in terms of the
186 // sync_guid, keyword, and url fields.
187 void AssertEquals(const syncer::SyncDataList& data1,
188 const syncer::SyncDataList& data2) const;
189
190 // Convenience helper for creating SyncChanges. Takes ownership of |turl|.
191 syncer::SyncChange CreateTestSyncChange(
192 syncer::SyncChange::SyncChangeType type,
193 TemplateURL* turl) const;
194
195 // Helper that creates some initial sync data. We cheat a little by specifying
196 // GUIDs for easy identification later. We also make the last_modified times
197 // slightly older than CreateTestTemplateURL's default, to test conflict
198 // resolution.
199 syncer::SyncDataList CreateInitialSyncData() const;
200
201 // Syntactic sugar.
202 TemplateURL* Deserialize(const syncer::SyncData& sync_data);
203
204 // Creates a new TemplateURL copying the fields of |turl| but replacing
205 // the |url| and |guid| and initializing the date_created and last_modified
206 // timestamps to a default value of 100. The caller owns the returned
207 // TemplateURL*.
208 TemplateURL* CopyTemplateURL(const TemplateURLData* turl,
209 const std::string& url,
210 const std::string& guid);
211
212 protected:
213 // We keep two TemplateURLServices to test syncing between them.
214 TemplateURLServiceTestUtil test_util_a_;
215 scoped_ptr<TestingProfile> profile_b_;
216 scoped_ptr<TemplateURLService> model_b_;
217
218 // Our dummy ChangeProcessor used to inspect changes pushed to Sync.
219 scoped_ptr<TestChangeProcessor> sync_processor_;
220 scoped_ptr<syncer::SyncChangeProcessorWrapperForTest> sync_processor_wrapper_;
221
222 DISALLOW_COPY_AND_ASSIGN(TemplateURLServiceSyncTest);
223 };
224
TemplateURLServiceSyncTest()225 TemplateURLServiceSyncTest::TemplateURLServiceSyncTest()
226 : sync_processor_(new TestChangeProcessor),
227 sync_processor_wrapper_(new syncer::SyncChangeProcessorWrapperForTest(
228 sync_processor_.get())) {}
229
SetUp()230 void TemplateURLServiceSyncTest::SetUp() {
231 DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(true);
232 test_util_a_.SetUp();
233 // Use ChangeToLoadState() instead of VerifyLoad() so we don't actually pull
234 // in the prepopulate data, which the sync tests don't care about (and would
235 // just foul them up).
236 test_util_a_.ChangeModelToLoadState();
237 profile_b_.reset(new TestingProfile);
238 TemplateURLServiceFactory::GetInstance()->
239 RegisterUserPrefsOnBrowserContextForTest(profile_b_.get());
240 model_b_.reset(new TemplateURLService(profile_b_.get()));
241 model_b_->Load();
242 }
243
TearDown()244 void TemplateURLServiceSyncTest::TearDown() {
245 test_util_a_.TearDown();
246 DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(false);
247 }
248
249 scoped_ptr<syncer::SyncChangeProcessor>
PassProcessor()250 TemplateURLServiceSyncTest::PassProcessor() {
251 return sync_processor_wrapper_.PassAs<syncer::SyncChangeProcessor>();
252 }
253
254 scoped_ptr<syncer::SyncErrorFactory> TemplateURLServiceSyncTest::
CreateAndPassSyncErrorFactory()255 CreateAndPassSyncErrorFactory() {
256 return scoped_ptr<syncer::SyncErrorFactory>(
257 new syncer::SyncErrorFactoryMock());
258 }
259
CreateTestTemplateURL(const base::string16 & keyword,const std::string & url,const std::string & guid,time_t last_mod,bool safe_for_autoreplace,bool created_by_policy) const260 TemplateURL* TemplateURLServiceSyncTest::CreateTestTemplateURL(
261 const base::string16& keyword,
262 const std::string& url,
263 const std::string& guid,
264 time_t last_mod,
265 bool safe_for_autoreplace,
266 bool created_by_policy) const {
267 TemplateURLData data;
268 data.short_name = ASCIIToUTF16("unittest");
269 data.SetKeyword(keyword);
270 data.SetURL(url);
271 data.favicon_url = GURL("http://favicon.url");
272 data.safe_for_autoreplace = safe_for_autoreplace;
273 data.date_created = Time::FromTimeT(100);
274 data.last_modified = Time::FromTimeT(last_mod);
275 data.created_by_policy = created_by_policy;
276 data.prepopulate_id = 999999;
277 if (!guid.empty())
278 data.sync_guid = guid;
279 return new TemplateURL(data);
280 }
281
AssertEquals(const TemplateURL & expected,const TemplateURL & actual) const282 void TemplateURLServiceSyncTest::AssertEquals(const TemplateURL& expected,
283 const TemplateURL& actual) const {
284 ASSERT_EQ(expected.short_name(), actual.short_name());
285 ASSERT_EQ(expected.keyword(), actual.keyword());
286 ASSERT_EQ(expected.url(), actual.url());
287 ASSERT_EQ(expected.suggestions_url(), actual.suggestions_url());
288 ASSERT_EQ(expected.favicon_url(), actual.favicon_url());
289 ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list());
290 ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace());
291 ASSERT_EQ(expected.input_encodings(), actual.input_encodings());
292 ASSERT_EQ(expected.date_created(), actual.date_created());
293 ASSERT_EQ(expected.last_modified(), actual.last_modified());
294 }
295
AssertEquals(const syncer::SyncDataList & data1,const syncer::SyncDataList & data2) const296 void TemplateURLServiceSyncTest::AssertEquals(
297 const syncer::SyncDataList& data1,
298 const syncer::SyncDataList& data2) const {
299 SyncDataMap map1 = TemplateURLService::CreateGUIDToSyncDataMap(data1);
300 SyncDataMap map2 = TemplateURLService::CreateGUIDToSyncDataMap(data2);
301
302 for (SyncDataMap::const_iterator iter1 = map1.begin();
303 iter1 != map1.end(); iter1++) {
304 SyncDataMap::iterator iter2 = map2.find(iter1->first);
305 if (iter2 != map2.end()) {
306 ASSERT_EQ(GetKeyword(iter1->second), GetKeyword(iter2->second));
307 ASSERT_EQ(GetURL(iter1->second), GetURL(iter2->second));
308 map2.erase(iter2);
309 }
310 }
311 EXPECT_EQ(0U, map2.size());
312 }
313
CreateTestSyncChange(syncer::SyncChange::SyncChangeType type,TemplateURL * turl) const314 syncer::SyncChange TemplateURLServiceSyncTest::CreateTestSyncChange(
315 syncer::SyncChange::SyncChangeType type,
316 TemplateURL* turl) const {
317 // We take control of the TemplateURL so make sure it's cleaned up after
318 // we create data out of it.
319 scoped_ptr<TemplateURL> scoped_turl(turl);
320 return syncer::SyncChange(
321 FROM_HERE,
322 type,
323 TemplateURLService::CreateSyncDataFromTemplateURL(*scoped_turl));
324 }
325
CreateInitialSyncData() const326 syncer::SyncDataList TemplateURLServiceSyncTest::CreateInitialSyncData() const {
327 syncer::SyncDataList list;
328
329 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("key1"),
330 "http://key1.com", "key1", 90));
331 list.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(*turl));
332 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com",
333 "key2", 90));
334 list.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(*turl));
335 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com",
336 "key3", 90));
337 list.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(*turl));
338
339 return list;
340 }
341
Deserialize(const syncer::SyncData & sync_data)342 TemplateURL* TemplateURLServiceSyncTest::Deserialize(
343 const syncer::SyncData& sync_data) {
344 syncer::SyncChangeList dummy;
345 return TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(NULL,
346 NULL, sync_data, &dummy);
347 }
348
CopyTemplateURL(const TemplateURLData * turl,const std::string & url,const std::string & guid)349 TemplateURL* TemplateURLServiceSyncTest::CopyTemplateURL(
350 const TemplateURLData* turl,
351 const std::string& url,
352 const std::string& guid) {
353 TemplateURLData data = *turl;
354 data.SetURL(url);
355 data.date_created = Time::FromTimeT(100);
356 data.last_modified = Time::FromTimeT(100);
357 data.sync_guid = guid;
358 return new TemplateURL(data);
359 }
360
361 // Actual tests ---------------------------------------------------------------
362
TEST_F(TemplateURLServiceSyncTest,SerializeDeserialize)363 TEST_F(TemplateURLServiceSyncTest, SerializeDeserialize) {
364 // Create a TemplateURL and convert it into a sync specific type.
365 scoped_ptr<TemplateURL> turl(
366 CreateTestTemplateURL(
367 ASCIIToUTF16("unittest"), "http://www.unittest.com/"));
368 syncer::SyncData sync_data =
369 TemplateURLService::CreateSyncDataFromTemplateURL(*turl);
370 // Convert the specifics back to a TemplateURL.
371 scoped_ptr<TemplateURL> deserialized(Deserialize(sync_data));
372 EXPECT_TRUE(deserialized.get());
373 // Ensure that the original and the deserialized TURLs are equal in values.
374 AssertEquals(*turl, *deserialized);
375 }
376
TEST_F(TemplateURLServiceSyncTest,GetAllSyncDataBasic)377 TEST_F(TemplateURLServiceSyncTest, GetAllSyncDataBasic) {
378 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com"));
379 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com"));
380 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com"));
381 syncer::SyncDataList all_sync_data =
382 model()->GetAllSyncData(syncer::SEARCH_ENGINES);
383
384 EXPECT_EQ(3U, all_sync_data.size());
385
386 for (syncer::SyncDataList::const_iterator iter = all_sync_data.begin();
387 iter != all_sync_data.end(); ++iter) {
388 std::string guid = GetGUID(*iter);
389 const TemplateURL* service_turl = model()->GetTemplateURLForGUID(guid);
390 scoped_ptr<TemplateURL> deserialized(Deserialize(*iter));
391 AssertEquals(*service_turl, *deserialized);
392 }
393 }
394
TEST_F(TemplateURLServiceSyncTest,GetAllSyncDataWithExtension)395 TEST_F(TemplateURLServiceSyncTest, GetAllSyncDataWithExtension) {
396 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com"));
397 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com"));
398 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key3"),
399 std::string(extensions::kExtensionScheme) + "://blahblahblah"));
400 syncer::SyncDataList all_sync_data =
401 model()->GetAllSyncData(syncer::SEARCH_ENGINES);
402
403 EXPECT_EQ(3U, all_sync_data.size());
404
405 for (syncer::SyncDataList::const_iterator iter = all_sync_data.begin();
406 iter != all_sync_data.end(); ++iter) {
407 std::string guid = GetGUID(*iter);
408 const TemplateURL* service_turl = model()->GetTemplateURLForGUID(guid);
409 scoped_ptr<TemplateURL> deserialized(Deserialize(*iter));
410 AssertEquals(*service_turl, *deserialized);
411 }
412 }
413
TEST_F(TemplateURLServiceSyncTest,GetAllSyncDataNoManagedEngines)414 TEST_F(TemplateURLServiceSyncTest, GetAllSyncDataNoManagedEngines) {
415 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com"));
416 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com"));
417 TemplateURL* managed_turl = CreateTestTemplateURL(ASCIIToUTF16("key3"),
418 "http://key3.com", std::string(), 100, false, true);
419 model()->Add(managed_turl);
420 syncer::SyncDataList all_sync_data =
421 model()->GetAllSyncData(syncer::SEARCH_ENGINES);
422
423 EXPECT_EQ(2U, all_sync_data.size());
424
425 for (syncer::SyncDataList::const_iterator iter = all_sync_data.begin();
426 iter != all_sync_data.end(); ++iter) {
427 std::string guid = GetGUID(*iter);
428 TemplateURL* service_turl = model()->GetTemplateURLForGUID(guid);
429 scoped_ptr<TemplateURL> deserialized(Deserialize(*iter));
430 ASSERT_FALSE(service_turl->created_by_policy());
431 AssertEquals(*service_turl, *deserialized);
432 }
433 }
434
TEST_F(TemplateURLServiceSyncTest,UniquifyKeyword)435 TEST_F(TemplateURLServiceSyncTest, UniquifyKeyword) {
436 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com"));
437 // Create a key that conflicts with something in the model.
438 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("key1"),
439 "http://new.com", "xyz"));
440 base::string16 new_keyword = model()->UniquifyKeyword(*turl, false);
441 EXPECT_EQ(ASCIIToUTF16("new.com"), new_keyword);
442 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
443 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("new.com"), "http://new.com",
444 "xyz"));
445
446 // Test a second collision. This time it should be resolved by actually
447 // modifying the original keyword, since the autogenerated keyword is already
448 // used.
449 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://new.com"));
450 new_keyword = model()->UniquifyKeyword(*turl, false);
451 EXPECT_EQ(ASCIIToUTF16("key1_"), new_keyword);
452 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
453 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1_"), "http://new.com"));
454
455 // Test a third collision. This should collide on both the autogenerated
456 // keyword and the first uniquification attempt.
457 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://new.com"));
458 new_keyword = model()->UniquifyKeyword(*turl, false);
459 EXPECT_EQ(ASCIIToUTF16("key1__"), new_keyword);
460 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
461
462 // If we force the method, it should uniquify the keyword even if it is
463 // currently unique, and skip the host-based autogenerated keyword.
464 turl.reset(
465 CreateTestTemplateURL(ASCIIToUTF16("unique"), "http://unique.com"));
466 new_keyword = model()->UniquifyKeyword(*turl, true);
467 EXPECT_EQ(ASCIIToUTF16("unique_"), new_keyword);
468 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(new_keyword));
469 }
470
TEST_F(TemplateURLServiceSyncTest,IsLocalTemplateURLBetter)471 TEST_F(TemplateURLServiceSyncTest, IsLocalTemplateURLBetter) {
472 // Test some edge cases of this function.
473 const struct {
474 time_t local_time;
475 time_t sync_time;
476 bool local_is_default;
477 bool local_created_by_policy;
478 bool expected_result;
479 } test_cases[] = {
480 // Sync is better by timestamp but local is Default.
481 {10, 100, true, false, true},
482 // Sync is better by timestamp but local is Create by Policy.
483 {10, 100, false, true, true},
484 // Tie. Sync wins.
485 {100, 100, false, false, false},
486 };
487
488 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
489 TemplateURL* local_turl = CreateTestTemplateURL(
490 ASCIIToUTF16("localkey"), "www.local.com", "localguid",
491 test_cases[i].local_time, true, test_cases[i].local_created_by_policy);
492 model()->Add(local_turl);
493 if (test_cases[i].local_is_default)
494 model()->SetUserSelectedDefaultSearchProvider(local_turl);
495
496 scoped_ptr<TemplateURL> sync_turl(CreateTestTemplateURL(
497 ASCIIToUTF16("synckey"), "www.sync.com", "syncguid",
498 test_cases[i].sync_time));
499 EXPECT_EQ(test_cases[i].expected_result,
500 model()->IsLocalTemplateURLBetter(local_turl, sync_turl.get()));
501
502 // Undo the changes.
503 if (test_cases[i].local_is_default)
504 model()->SetUserSelectedDefaultSearchProvider(NULL);
505 model()->Remove(local_turl);
506 }
507 }
508
TEST_F(TemplateURLServiceSyncTest,ResolveSyncKeywordConflict)509 TEST_F(TemplateURLServiceSyncTest, ResolveSyncKeywordConflict) {
510 // This tests cases where neither the sync nor the local TemplateURL are
511 // marked safe_for_autoreplace.
512
513 // Create a keyword that conflicts, and make it older. Sync keyword is
514 // uniquified, and a syncer::SyncChange is added.
515 base::string16 original_turl_keyword = ASCIIToUTF16("key1");
516 TemplateURL* original_turl = CreateTestTemplateURL(original_turl_keyword,
517 "http://key1.com", std::string(), 9000);
518 model()->Add(original_turl);
519 scoped_ptr<TemplateURL> sync_turl(CreateTestTemplateURL(original_turl_keyword,
520 "http://new.com", "remote", 8999));
521 syncer::SyncChangeList changes;
522 model()->ResolveSyncKeywordConflict(sync_turl.get(), original_turl, &changes);
523 EXPECT_NE(original_turl_keyword, sync_turl->keyword());
524 EXPECT_EQ(original_turl_keyword, original_turl->keyword());
525 ASSERT_EQ(1U, changes.size());
526 EXPECT_EQ("remote", GetGUID(changes[0].sync_data()));
527 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
528 changes.clear();
529 model()->Remove(original_turl);
530
531 // Sync is newer. Original TemplateURL keyword is uniquified. A SyncChange
532 // is added (which in a normal run would be deleted by PruneSyncChanges() when
533 // the local GUID doesn't appear in the sync GUID list). Also ensure that
534 // this does not change the safe_for_autoreplace flag or the TemplateURLID in
535 // the original.
536 original_turl = CreateTestTemplateURL(original_turl_keyword,
537 "http://key1.com", "local", 9000);
538 model()->Add(original_turl);
539 TemplateURLID original_id = original_turl->id();
540 sync_turl.reset(CreateTestTemplateURL(original_turl_keyword, "http://new.com",
541 std::string(), 9001));
542 model()->ResolveSyncKeywordConflict(sync_turl.get(), original_turl, &changes);
543 EXPECT_EQ(original_turl_keyword, sync_turl->keyword());
544 EXPECT_NE(original_turl_keyword, original_turl->keyword());
545 EXPECT_FALSE(original_turl->safe_for_autoreplace());
546 EXPECT_EQ(original_id, original_turl->id());
547 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(original_turl_keyword));
548 ASSERT_EQ(1U, changes.size());
549 EXPECT_EQ("local", GetGUID(changes[0].sync_data()));
550 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
551 changes.clear();
552 model()->Remove(original_turl);
553
554 // Equal times. Same result as above. Sync left alone, original uniquified so
555 // sync_turl can fit.
556 original_turl = CreateTestTemplateURL(original_turl_keyword,
557 "http://key1.com", "local2", 9000);
558 model()->Add(original_turl);
559 sync_turl.reset(CreateTestTemplateURL(original_turl_keyword, "http://new.com",
560 std::string(), 9000));
561 model()->ResolveSyncKeywordConflict(sync_turl.get(), original_turl, &changes);
562 EXPECT_EQ(original_turl_keyword, sync_turl->keyword());
563 EXPECT_NE(original_turl_keyword, original_turl->keyword());
564 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(original_turl_keyword));
565 ASSERT_EQ(1U, changes.size());
566 EXPECT_EQ("local2", GetGUID(changes[0].sync_data()));
567 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
568 changes.clear();
569 model()->Remove(original_turl);
570
571 // Sync is newer, but original TemplateURL is created by policy, so it wins.
572 // Sync keyword is uniquified, and a syncer::SyncChange is added.
573 original_turl = CreateTestTemplateURL(original_turl_keyword,
574 "http://key1.com", std::string(), 9000, false, true);
575 model()->Add(original_turl);
576 sync_turl.reset(CreateTestTemplateURL(original_turl_keyword, "http://new.com",
577 "remote2", 9999));
578 model()->ResolveSyncKeywordConflict(sync_turl.get(), original_turl, &changes);
579 EXPECT_NE(original_turl_keyword, sync_turl->keyword());
580 EXPECT_EQ(original_turl_keyword, original_turl->keyword());
581 EXPECT_EQ(NULL, model()->GetTemplateURLForKeyword(sync_turl->keyword()));
582 ASSERT_EQ(1U, changes.size());
583 EXPECT_EQ("remote2", GetGUID(changes[0].sync_data()));
584 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, changes[0].change_type());
585 changes.clear();
586 model()->Remove(original_turl);
587 }
588
TEST_F(TemplateURLServiceSyncTest,StartSyncEmpty)589 TEST_F(TemplateURLServiceSyncTest, StartSyncEmpty) {
590 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
591 syncer::SEARCH_ENGINES, syncer::SyncDataList(),
592 PassProcessor(), CreateAndPassSyncErrorFactory());
593
594 EXPECT_EQ(0U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
595 EXPECT_EQ(0U, processor()->change_list_size());
596 EXPECT_EQ(0, merge_result.num_items_added());
597 EXPECT_EQ(0, merge_result.num_items_modified());
598 EXPECT_EQ(0, merge_result.num_items_deleted());
599 EXPECT_EQ(0, merge_result.num_items_before_association());
600 EXPECT_EQ(0, merge_result.num_items_after_association());
601 }
602
TEST_F(TemplateURLServiceSyncTest,MergeIntoEmpty)603 TEST_F(TemplateURLServiceSyncTest, MergeIntoEmpty) {
604 syncer::SyncDataList initial_data = CreateInitialSyncData();
605
606 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
607 syncer::SEARCH_ENGINES, initial_data,
608 PassProcessor(), CreateAndPassSyncErrorFactory());
609
610 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
611 // We expect the model to have accepted all of the initial sync data. Search
612 // through the model using the GUIDs to ensure that they're present.
613 for (syncer::SyncDataList::const_iterator iter = initial_data.begin();
614 iter != initial_data.end(); ++iter) {
615 std::string guid = GetGUID(*iter);
616 EXPECT_TRUE(model()->GetTemplateURLForGUID(guid));
617 }
618
619 EXPECT_EQ(0U, processor()->change_list_size());
620
621 // Locally the three new TemplateURL's should have been added.
622 EXPECT_EQ(3, merge_result.num_items_added());
623 EXPECT_EQ(0, merge_result.num_items_modified());
624 EXPECT_EQ(0, merge_result.num_items_deleted());
625 EXPECT_EQ(0, merge_result.num_items_before_association());
626 EXPECT_EQ(3, merge_result.num_items_after_association());
627 }
628
TEST_F(TemplateURLServiceSyncTest,MergeInAllNewData)629 TEST_F(TemplateURLServiceSyncTest, MergeInAllNewData) {
630 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("abc.com"), "http://abc.com",
631 "abc"));
632 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("def.com"), "http://def.com",
633 "def"));
634 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("xyz.com"), "http://xyz.com",
635 "xyz"));
636 syncer::SyncDataList initial_data = CreateInitialSyncData();
637
638 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
639 syncer::SEARCH_ENGINES, initial_data,
640 PassProcessor(), CreateAndPassSyncErrorFactory());
641
642 EXPECT_EQ(6U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
643 // We expect the model to have accepted all of the initial sync data. Search
644 // through the model using the GUIDs to ensure that they're present.
645 for (syncer::SyncDataList::const_iterator iter = initial_data.begin();
646 iter != initial_data.end(); ++iter) {
647 std::string guid = GetGUID(*iter);
648 EXPECT_TRUE(model()->GetTemplateURLForGUID(guid));
649 }
650 // All the original TemplateURLs should also remain in the model.
651 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("abc.com")));
652 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("def.com")));
653 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("xyz.com")));
654 // Ensure that Sync received the expected changes.
655 EXPECT_EQ(3U, processor()->change_list_size());
656 EXPECT_TRUE(processor()->contains_guid("abc"));
657 EXPECT_TRUE(processor()->contains_guid("def"));
658 EXPECT_TRUE(processor()->contains_guid("xyz"));
659
660 // Locally the three new TemplateURL's should have been added.
661 EXPECT_EQ(3, merge_result.num_items_added());
662 EXPECT_EQ(0, merge_result.num_items_modified());
663 EXPECT_EQ(0, merge_result.num_items_deleted());
664 EXPECT_EQ(3, merge_result.num_items_before_association());
665 EXPECT_EQ(6, merge_result.num_items_after_association());
666 }
667
TEST_F(TemplateURLServiceSyncTest,MergeSyncIsTheSame)668 TEST_F(TemplateURLServiceSyncTest, MergeSyncIsTheSame) {
669 // The local data is the same as the sync data merged in. i.e. - There have
670 // been no changes since the last time we synced. Even the last_modified
671 // timestamps are the same.
672 syncer::SyncDataList initial_data = CreateInitialSyncData();
673 for (syncer::SyncDataList::const_iterator iter = initial_data.begin();
674 iter != initial_data.end(); ++iter) {
675 TemplateURL* converted = Deserialize(*iter);
676 model()->Add(converted);
677 }
678
679 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
680 syncer::SEARCH_ENGINES, initial_data,
681 PassProcessor(), CreateAndPassSyncErrorFactory());
682
683 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
684 for (syncer::SyncDataList::const_iterator iter = initial_data.begin();
685 iter != initial_data.end(); ++iter) {
686 std::string guid = GetGUID(*iter);
687 EXPECT_TRUE(model()->GetTemplateURLForGUID(guid));
688 }
689 EXPECT_EQ(0U, processor()->change_list_size());
690
691 // Locally everything should remain the same.
692 EXPECT_EQ(0, merge_result.num_items_added());
693 EXPECT_EQ(0, merge_result.num_items_modified());
694 EXPECT_EQ(0, merge_result.num_items_deleted());
695 EXPECT_EQ(3, merge_result.num_items_before_association());
696 EXPECT_EQ(3, merge_result.num_items_after_association());
697 }
698
TEST_F(TemplateURLServiceSyncTest,MergeUpdateFromSync)699 TEST_F(TemplateURLServiceSyncTest, MergeUpdateFromSync) {
700 // The local data is the same as the sync data merged in, but timestamps have
701 // changed. Ensure the right fields are merged in.
702 syncer::SyncDataList initial_data;
703 TemplateURL* turl1 = CreateTestTemplateURL(ASCIIToUTF16("abc.com"),
704 "http://abc.com", "abc", 9000);
705 model()->Add(turl1);
706 TemplateURL* turl2 = CreateTestTemplateURL(ASCIIToUTF16("xyz.com"),
707 "http://xyz.com", "xyz", 9000);
708 model()->Add(turl2);
709
710 scoped_ptr<TemplateURL> turl1_newer(CreateTestTemplateURL(
711 ASCIIToUTF16("abc.com"), "http://abc.ca", "abc", 9999));
712 initial_data.push_back(
713 TemplateURLService::CreateSyncDataFromTemplateURL(*turl1_newer));
714
715 scoped_ptr<TemplateURL> turl2_older(CreateTestTemplateURL(
716 ASCIIToUTF16("xyz.com"), "http://xyz.ca", "xyz", 8888));
717 initial_data.push_back(
718 TemplateURLService::CreateSyncDataFromTemplateURL(*turl2_older));
719
720 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
721 syncer::SEARCH_ENGINES, initial_data,
722 PassProcessor(), CreateAndPassSyncErrorFactory());
723
724 // Both were local updates, so we expect the same count.
725 EXPECT_EQ(2U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
726
727 // Check that the first replaced the initial abc TemplateURL.
728 EXPECT_EQ(turl1, model()->GetTemplateURLForGUID("abc"));
729 EXPECT_EQ("http://abc.ca", turl1->url());
730
731 // Check that the second produced an upstream update to the xyz TemplateURL.
732 EXPECT_EQ(1U, processor()->change_list_size());
733 ASSERT_TRUE(processor()->contains_guid("xyz"));
734 syncer::SyncChange change = processor()->change_for_guid("xyz");
735 EXPECT_TRUE(change.change_type() == syncer::SyncChange::ACTION_UPDATE);
736 EXPECT_EQ("http://xyz.com", GetURL(change.sync_data()));
737
738 // Locally only the older item should have been modified.
739 EXPECT_EQ(0, merge_result.num_items_added());
740 EXPECT_EQ(1, merge_result.num_items_modified());
741 EXPECT_EQ(0, merge_result.num_items_deleted());
742 EXPECT_EQ(2, merge_result.num_items_before_association());
743 EXPECT_EQ(2, merge_result.num_items_after_association());
744 }
745
TEST_F(TemplateURLServiceSyncTest,MergeAddFromOlderSyncData)746 TEST_F(TemplateURLServiceSyncTest, MergeAddFromOlderSyncData) {
747 // GUIDs all differ, so this is data to be added from Sync, but the timestamps
748 // from Sync are older. Set up the local data so that one is a dupe, one has a
749 // conflicting keyword, and the last has no conflicts (a clean ADD).
750 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com",
751 "aaa", 100)); // dupe
752
753 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key2"),
754 "http://expected.com", "bbb", 100)); // keyword conflict
755
756 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("unique"),
757 "http://unique.com", "ccc")); // add
758
759 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
760 syncer::SEARCH_ENGINES,
761 CreateInitialSyncData(), PassProcessor(),
762 CreateAndPassSyncErrorFactory());
763
764 // The dupe and conflict results in merges, as local values are always merged
765 // with sync values if there is a keyword conflict. The unique keyword should
766 // be added.
767 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
768
769 // The key1 duplicate results in the local copy winning. Ensure that Sync's
770 // copy was not added, and the local copy is pushed upstream to Sync as an
771 // update. The local copy should have received the sync data's GUID.
772 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
773 // Check changes for the UPDATE.
774 ASSERT_TRUE(processor()->contains_guid("key1"));
775 syncer::SyncChange key1_change = processor()->change_for_guid("key1");
776 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, key1_change.change_type());
777 // The local sync_guid should no longer be found.
778 EXPECT_FALSE(model()->GetTemplateURLForGUID("aaa"));
779
780 // The key2 keyword conflict results in a merge, with the values of the local
781 // copy winning, so ensure it retains the original URL, and that an update to
782 // the sync guid is pushed upstream to Sync.
783 const TemplateURL* key2 = model()->GetTemplateURLForGUID("key2");
784 ASSERT_TRUE(key2);
785 EXPECT_EQ(ASCIIToUTF16("key2"), key2->keyword());
786 EXPECT_EQ("http://expected.com", key2->url());
787 // Check changes for the UPDATE.
788 ASSERT_TRUE(processor()->contains_guid("key2"));
789 syncer::SyncChange key2_change = processor()->change_for_guid("key2");
790 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, key2_change.change_type());
791 EXPECT_EQ("key2", GetKeyword(key2_change.sync_data()));
792 EXPECT_EQ("http://expected.com", GetURL(key2_change.sync_data()));
793 // The local sync_guid should no longer be found.
794 EXPECT_FALSE(model()->GetTemplateURLForGUID("bbb"));
795
796 // The last TemplateURL should have had no conflicts and was just added. It
797 // should not have replaced the third local TemplateURL.
798 EXPECT_TRUE(model()->GetTemplateURLForGUID("ccc"));
799 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
800
801 // Two UPDATEs and one ADD.
802 EXPECT_EQ(3U, processor()->change_list_size());
803 // One ADDs should be pushed up to Sync.
804 ASSERT_TRUE(processor()->contains_guid("ccc"));
805 EXPECT_EQ(syncer::SyncChange::ACTION_ADD,
806 processor()->change_for_guid("ccc").change_type());
807
808 // All the sync items had new guids, but only one doesn't conflict and is
809 // added. The other two conflicting cases result in local modifications
810 // to override the local guids but preserve the local data.
811 EXPECT_EQ(1, merge_result.num_items_added());
812 EXPECT_EQ(2, merge_result.num_items_modified());
813 EXPECT_EQ(0, merge_result.num_items_deleted());
814 EXPECT_EQ(3, merge_result.num_items_before_association());
815 EXPECT_EQ(4, merge_result.num_items_after_association());
816 }
817
TEST_F(TemplateURLServiceSyncTest,MergeAddFromNewerSyncData)818 TEST_F(TemplateURLServiceSyncTest, MergeAddFromNewerSyncData) {
819 // GUIDs all differ, so Sync may overtake some entries, but the timestamps
820 // from Sync are newer. Set up the local data so that one is a dupe, one has a
821 // conflicting keyword, and the last has no conflicts (a clean ADD).
822 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com",
823 "aaa", 10)); // dupe
824
825 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key2"),
826 "http://expected.com", "bbb", 10)); // keyword conflict
827
828 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("unique"),
829 "http://unique.com", "ccc", 10)); // add
830
831 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
832 syncer::SEARCH_ENGINES,
833 CreateInitialSyncData(), PassProcessor(),
834 CreateAndPassSyncErrorFactory());
835
836 // The dupe and keyword conflict results in merges. The unique keyword be
837 // added to the model.
838 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
839
840 // The key1 duplicate results in Sync's copy winning. Ensure that Sync's
841 // copy replaced the local copy.
842 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
843 EXPECT_FALSE(model()->GetTemplateURLForGUID("aaa"));
844 EXPECT_FALSE(processor()->contains_guid("key1"));
845 EXPECT_FALSE(processor()->contains_guid("aaa"));
846
847 // The key2 keyword conflict results in Sync's copy winning, so ensure it
848 // retains the original keyword and is added. The local copy should be
849 // removed.
850 const TemplateURL* key2_sync = model()->GetTemplateURLForGUID("key2");
851 ASSERT_TRUE(key2_sync);
852 EXPECT_EQ(ASCIIToUTF16("key2"), key2_sync->keyword());
853 EXPECT_FALSE(model()->GetTemplateURLForGUID("bbb"));
854
855 // The last TemplateURL should have had no conflicts and was just added. It
856 // should not have replaced the third local TemplateURL.
857 EXPECT_TRUE(model()->GetTemplateURLForGUID("ccc"));
858 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
859
860 // One ADD.
861 EXPECT_EQ(1U, processor()->change_list_size());
862 // One ADDs should be pushed up to Sync.
863 ASSERT_TRUE(processor()->contains_guid("ccc"));
864 EXPECT_EQ(syncer::SyncChange::ACTION_ADD,
865 processor()->change_for_guid("ccc").change_type());
866
867 // One of the sync items is added directly without conflict. The other two
868 // conflict but are newer than the local items so are added while the local
869 // is deleted.
870 EXPECT_EQ(3, merge_result.num_items_added());
871 EXPECT_EQ(0, merge_result.num_items_modified());
872 EXPECT_EQ(2, merge_result.num_items_deleted());
873 EXPECT_EQ(3, merge_result.num_items_before_association());
874 EXPECT_EQ(4, merge_result.num_items_after_association());
875 }
876
TEST_F(TemplateURLServiceSyncTest,ProcessChangesEmptyModel)877 TEST_F(TemplateURLServiceSyncTest, ProcessChangesEmptyModel) {
878 // We initially have no data.
879 model()->MergeDataAndStartSyncing(
880 syncer::SEARCH_ENGINES, syncer::SyncDataList(),
881 PassProcessor(), CreateAndPassSyncErrorFactory());
882
883 // Set up a bunch of ADDs.
884 syncer::SyncChangeList changes;
885 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
886 CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com", "key1")));
887 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
888 CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com", "key2")));
889 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
890 CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com", "key3")));
891
892 model()->ProcessSyncChanges(FROM_HERE, changes);
893
894 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
895 EXPECT_EQ(0U, processor()->change_list_size());
896 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
897 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
898 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
899 }
900
TEST_F(TemplateURLServiceSyncTest,ProcessChangesNoConflicts)901 TEST_F(TemplateURLServiceSyncTest, ProcessChangesNoConflicts) {
902 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
903 CreateInitialSyncData(), PassProcessor(),
904 CreateAndPassSyncErrorFactory());
905
906 // Process different types of changes, without conflicts.
907 syncer::SyncChangeList changes;
908 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
909 CreateTestTemplateURL(ASCIIToUTF16("key4"), "http://key4.com", "key4")));
910 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
911 CreateTestTemplateURL(ASCIIToUTF16("newkeyword"), "http://new.com",
912 "key2")));
913 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_DELETE,
914 CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com", "key3")));
915
916 model()->ProcessSyncChanges(FROM_HERE, changes);
917
918 // Add one, remove one, update one, so the number shouldn't change.
919 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
920 EXPECT_EQ(0U, processor()->change_list_size());
921 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
922 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
923 const TemplateURL* turl = model()->GetTemplateURLForGUID("key2");
924 EXPECT_TRUE(turl);
925 EXPECT_EQ(ASCIIToUTF16("newkeyword"), turl->keyword());
926 EXPECT_EQ("http://new.com", turl->url());
927 EXPECT_FALSE(model()->GetTemplateURLForGUID("key3"));
928 EXPECT_TRUE(model()->GetTemplateURLForGUID("key4"));
929 }
930
TEST_F(TemplateURLServiceSyncTest,ProcessChangesWithConflictsSyncWins)931 TEST_F(TemplateURLServiceSyncTest, ProcessChangesWithConflictsSyncWins) {
932 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
933 CreateInitialSyncData(), PassProcessor(),
934 CreateAndPassSyncErrorFactory());
935
936 // Process different types of changes, with conflicts. Note that all this data
937 // has a newer timestamp, so Sync will win in these scenarios.
938 syncer::SyncChangeList changes;
939 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
940 CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://new.com", "aaa")));
941 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
942 CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com", "key1")));
943
944 model()->ProcessSyncChanges(FROM_HERE, changes);
945
946 // Add one, update one, so we're up to 4.
947 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
948 // Sync is always newer here, so it should always win. We should create
949 // SyncChanges for the changes to the local entities, since they're synced
950 // too.
951 EXPECT_EQ(2U, processor()->change_list_size());
952 ASSERT_TRUE(processor()->contains_guid("key2"));
953 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
954 processor()->change_for_guid("key2").change_type());
955 ASSERT_TRUE(processor()->contains_guid("key3"));
956 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
957 processor()->change_for_guid("key3").change_type());
958
959 // aaa conflicts with key2 and wins, forcing key2's keyword to update.
960 EXPECT_TRUE(model()->GetTemplateURLForGUID("aaa"));
961 EXPECT_EQ(model()->GetTemplateURLForGUID("aaa"),
962 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key2")));
963 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
964 EXPECT_EQ(model()->GetTemplateURLForGUID("key2"),
965 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key2.com")));
966 // key1 update conflicts with key3 and wins, forcing key3's keyword to update.
967 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
968 EXPECT_EQ(model()->GetTemplateURLForGUID("key1"),
969 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key3")));
970 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
971 EXPECT_EQ(model()->GetTemplateURLForGUID("key3"),
972 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key3.com")));
973 }
974
TEST_F(TemplateURLServiceSyncTest,ProcessChangesWithConflictsLocalWins)975 TEST_F(TemplateURLServiceSyncTest, ProcessChangesWithConflictsLocalWins) {
976 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
977 CreateInitialSyncData(), PassProcessor(),
978 CreateAndPassSyncErrorFactory());
979
980 // Process different types of changes, with conflicts. Note that all this data
981 // has an older timestamp, so the local data will win in these scenarios.
982 syncer::SyncChangeList changes;
983 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
984 CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://new.com", "aaa",
985 10)));
986 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
987 CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com", "key1",
988 10)));
989
990 model()->ProcessSyncChanges(FROM_HERE, changes);
991
992 // Add one, update one, so we're up to 4.
993 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
994 // Local data wins twice so two updates are pushed up to Sync.
995 EXPECT_EQ(2U, processor()->change_list_size());
996
997 // aaa conflicts with key2 and loses, forcing it's keyword to update.
998 EXPECT_TRUE(model()->GetTemplateURLForGUID("aaa"));
999 EXPECT_EQ(model()->GetTemplateURLForGUID("aaa"),
1000 model()->GetTemplateURLForKeyword(ASCIIToUTF16("new.com")));
1001 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
1002 EXPECT_EQ(model()->GetTemplateURLForGUID("key2"),
1003 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key2")));
1004 // key1 update conflicts with key3 and loses, forcing key1's keyword to
1005 // update.
1006 EXPECT_TRUE(model()->GetTemplateURLForGUID("key1"));
1007 EXPECT_EQ(model()->GetTemplateURLForGUID("key1"),
1008 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key3.com")));
1009 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
1010 EXPECT_EQ(model()->GetTemplateURLForGUID("key3"),
1011 model()->GetTemplateURLForKeyword(ASCIIToUTF16("key3")));
1012
1013 ASSERT_TRUE(processor()->contains_guid("aaa"));
1014 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
1015 processor()->change_for_guid("aaa").change_type());
1016 ASSERT_TRUE(processor()->contains_guid("key1"));
1017 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
1018 processor()->change_for_guid("key1").change_type());
1019 }
1020
TEST_F(TemplateURLServiceSyncTest,ProcessTemplateURLChange)1021 TEST_F(TemplateURLServiceSyncTest, ProcessTemplateURLChange) {
1022 // Ensure that ProcessTemplateURLChange is called and pushes the correct
1023 // changes to Sync whenever local changes are made to TemplateURLs.
1024 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
1025 CreateInitialSyncData(), PassProcessor(),
1026 CreateAndPassSyncErrorFactory());
1027
1028 // Add a new search engine.
1029 TemplateURL* new_turl =
1030 CreateTestTemplateURL(ASCIIToUTF16("baidu"), "http://baidu.cn", "new");
1031 model()->Add(new_turl);
1032 EXPECT_EQ(1U, processor()->change_list_size());
1033 ASSERT_TRUE(processor()->contains_guid("new"));
1034 syncer::SyncChange change = processor()->change_for_guid("new");
1035 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type());
1036 EXPECT_EQ("baidu", GetKeyword(change.sync_data()));
1037 EXPECT_EQ("http://baidu.cn", GetURL(change.sync_data()));
1038
1039 // Change a keyword.
1040 TemplateURL* existing_turl = model()->GetTemplateURLForGUID("key1");
1041 model()->ResetTemplateURL(existing_turl, existing_turl->short_name(),
1042 ASCIIToUTF16("k"), existing_turl->url());
1043 EXPECT_EQ(1U, processor()->change_list_size());
1044 ASSERT_TRUE(processor()->contains_guid("key1"));
1045 change = processor()->change_for_guid("key1");
1046 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type());
1047 EXPECT_EQ("k", GetKeyword(change.sync_data()));
1048
1049 // Remove an existing search engine.
1050 existing_turl = model()->GetTemplateURLForGUID("key2");
1051 model()->Remove(existing_turl);
1052 EXPECT_EQ(1U, processor()->change_list_size());
1053 ASSERT_TRUE(processor()->contains_guid("key2"));
1054 change = processor()->change_for_guid("key2");
1055 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, change.change_type());
1056 }
1057
TEST_F(TemplateURLServiceSyncTest,ProcessChangesWithLocalExtensions)1058 TEST_F(TemplateURLServiceSyncTest, ProcessChangesWithLocalExtensions) {
1059 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
1060 CreateInitialSyncData(), PassProcessor(),
1061 CreateAndPassSyncErrorFactory());
1062
1063 // Add some extension keywords locally.
1064 TemplateURL* extension1 = CreateTestTemplateURL(ASCIIToUTF16("keyword1"),
1065 std::string(extensions::kExtensionScheme) + "://extension1");
1066 model()->Add(extension1);
1067 EXPECT_EQ(1U, processor()->change_list_size());
1068 TemplateURL* extension2 = CreateTestTemplateURL(ASCIIToUTF16("keyword2"),
1069 std::string(extensions::kExtensionScheme) + "://extension2");
1070 model()->Add(extension2);
1071 EXPECT_EQ(1U, processor()->change_list_size());
1072
1073 // Create some sync changes that will conflict with the extension keywords.
1074 syncer::SyncChangeList changes;
1075 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
1076 CreateTestTemplateURL(ASCIIToUTF16("keyword1"), "http://aaa.com",
1077 std::string(), 100, true)));
1078 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
1079 CreateTestTemplateURL(ASCIIToUTF16("keyword2"), "http://bbb.com")));
1080 model()->ProcessSyncChanges(FROM_HERE, changes);
1081
1082 // The existing extension keywords should be uniquified.
1083 EXPECT_FALSE(model()->GetTemplateURLForHost("aaa.com") == NULL);
1084 EXPECT_EQ(model()->GetTemplateURLForHost("aaa.com"),
1085 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword1")));
1086 TemplateURL* url_for_keyword2 =
1087 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword2"));
1088 EXPECT_NE(extension2, url_for_keyword2);
1089 EXPECT_EQ("http://bbb.com", url_for_keyword2->url());
1090
1091 // Replaced extension keywords should be uniquified.
1092 EXPECT_EQ(extension1,
1093 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword1_")));
1094 EXPECT_EQ(extension2,
1095 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword2_")));
1096 }
1097
TEST_F(TemplateURLServiceSyncTest,AutogeneratedKeywordMigrated)1098 TEST_F(TemplateURLServiceSyncTest, AutogeneratedKeywordMigrated) {
1099 // Create a couple of sync entries with autogenerated keywords.
1100 syncer::SyncDataList initial_data;
1101 scoped_ptr<TemplateURL> turl(
1102 CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com", "key1"));
1103 initial_data.push_back(
1104 CreateCustomSyncData(*turl, true, turl->url(), turl->sync_guid()));
1105 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key2"),
1106 "{google:baseURL}search?q={searchTerms}", "key2"));
1107 initial_data.push_back(
1108 CreateCustomSyncData(*turl, true, turl->url(), turl->sync_guid()));
1109
1110 // Now try to sync the data locally.
1111 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1112 PassProcessor(), CreateAndPassSyncErrorFactory());
1113
1114 // Both entries should have been added, with explicit keywords.
1115 TemplateURL* key1 = model()->GetTemplateURLForHost("key1.com");
1116 ASSERT_FALSE(key1 == NULL);
1117 EXPECT_EQ(ASCIIToUTF16("key1.com"), key1->keyword());
1118 GURL google_url(UIThreadSearchTermsData(profile_a()).GoogleBaseURLValue());
1119 TemplateURL* key2 = model()->GetTemplateURLForHost(google_url.host());
1120 ASSERT_FALSE(key2 == NULL);
1121 base::string16 google_keyword(net::StripWWWFromHost(google_url));
1122 EXPECT_EQ(google_keyword, key2->keyword());
1123
1124 // We should also have gotten some corresponding UPDATEs pushed upstream.
1125 EXPECT_GE(processor()->change_list_size(), 2U);
1126 ASSERT_TRUE(processor()->contains_guid("key1"));
1127 syncer::SyncChange key1_change = processor()->change_for_guid("key1");
1128 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, key1_change.change_type());
1129 EXPECT_EQ("key1.com", GetKeyword(key1_change.sync_data()));
1130 ASSERT_TRUE(processor()->contains_guid("key2"));
1131 syncer::SyncChange key2_change = processor()->change_for_guid("key2");
1132 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, key2_change.change_type());
1133 EXPECT_EQ(google_keyword, UTF8ToUTF16(GetKeyword(key2_change.sync_data())));
1134 }
1135
TEST_F(TemplateURLServiceSyncTest,AutogeneratedKeywordConflicts)1136 TEST_F(TemplateURLServiceSyncTest, AutogeneratedKeywordConflicts) {
1137 // Sync brings in some autogenerated keywords, but the generated keywords we
1138 // try to create conflict with ones in the model.
1139 base::string16 google_keyword(net::StripWWWFromHost(GURL(
1140 UIThreadSearchTermsData(profile_a()).GoogleBaseURLValue())));
1141 const std::string local_google_url =
1142 "{google:baseURL}1/search?q={searchTerms}";
1143 TemplateURL* google = CreateTestTemplateURL(google_keyword, local_google_url);
1144 model()->Add(google);
1145 TemplateURL* other =
1146 CreateTestTemplateURL(ASCIIToUTF16("other.com"), "http://other.com/foo");
1147 model()->Add(other);
1148 syncer::SyncDataList initial_data;
1149 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("sync1"),
1150 "{google:baseURL}2/search?q={searchTerms}", "sync1", 50));
1151 initial_data.push_back(
1152 CreateCustomSyncData(*turl, true, turl->url(), turl->sync_guid()));
1153 const std::string synced_other_url =
1154 "http://other.com/search?q={searchTerms}";
1155 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("sync2"),
1156 synced_other_url, "sync2", 150));
1157 initial_data.push_back(
1158 CreateCustomSyncData(*turl, true, turl->url(), turl->sync_guid()));
1159
1160 // Before we merge the data, grab the local sync_guids so we can ensure that
1161 // they've been replaced.
1162 const std::string local_google_guid = google->sync_guid();
1163 const std::string local_other_guid = other->sync_guid();
1164
1165 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1166 PassProcessor(), CreateAndPassSyncErrorFactory());
1167
1168 // In this case, the conflicts should be handled just like any other keyword
1169 // conflicts -- the later-modified TemplateURL is assumed to be authoritative.
1170 // Since the initial TemplateURLs were local only, they should be merged with
1171 // the sync TemplateURLs (GUIDs transferred over).
1172 EXPECT_FALSE(model()->GetTemplateURLForGUID(local_google_guid));
1173 ASSERT_TRUE(model()->GetTemplateURLForGUID("sync1"));
1174 EXPECT_EQ(google_keyword, model()->GetTemplateURLForGUID("sync1")->keyword());
1175 EXPECT_FALSE(model()->GetTemplateURLForGUID(local_other_guid));
1176 ASSERT_TRUE(model()->GetTemplateURLForGUID("sync2"));
1177 EXPECT_EQ(ASCIIToUTF16("other.com"),
1178 model()->GetTemplateURLForGUID("sync2")->keyword());
1179
1180 // Both synced URLs should have associated UPDATEs, since both needed their
1181 // keywords to be generated.
1182 EXPECT_EQ(processor()->change_list_size(), 2U);
1183 ASSERT_TRUE(processor()->contains_guid("sync1"));
1184 syncer::SyncChange sync1_change = processor()->change_for_guid("sync1");
1185 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, sync1_change.change_type());
1186 EXPECT_EQ(google_keyword, UTF8ToUTF16(GetKeyword(sync1_change.sync_data())));
1187 EXPECT_EQ(local_google_url, GetURL(sync1_change.sync_data()));
1188 ASSERT_TRUE(processor()->contains_guid("sync2"));
1189 syncer::SyncChange sync2_change = processor()->change_for_guid("sync2");
1190 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, sync2_change.change_type());
1191 EXPECT_EQ("other.com", GetKeyword(sync2_change.sync_data()));
1192 EXPECT_EQ(synced_other_url, GetURL(sync2_change.sync_data()));
1193 }
1194
TEST_F(TemplateURLServiceSyncTest,TwoAutogeneratedKeywordsUsingGoogleBaseURL)1195 TEST_F(TemplateURLServiceSyncTest, TwoAutogeneratedKeywordsUsingGoogleBaseURL) {
1196 // Sync brings in two autogenerated keywords and both use Google base URLs.
1197 // We make the first older so that it will get renamed once before the second
1198 // and then again once after (when we resolve conflicts for the second).
1199 syncer::SyncDataList initial_data;
1200 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("key1"),
1201 "{google:baseURL}1/search?q={searchTerms}", "key1", 50));
1202 initial_data.push_back(
1203 CreateCustomSyncData(*turl, true, turl->url(), turl->sync_guid()));
1204 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key2"),
1205 "{google:baseURL}2/search?q={searchTerms}", "key2"));
1206 initial_data.push_back(
1207 CreateCustomSyncData(*turl, true, turl->url(), turl->sync_guid()));
1208 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1209 PassProcessor(), CreateAndPassSyncErrorFactory());
1210
1211 // We should still have coalesced the updates to one each.
1212 base::string16 google_keyword(net::StripWWWFromHost(GURL(
1213 UIThreadSearchTermsData(profile_a()).GoogleBaseURLValue())));
1214 TemplateURL* keyword1 =
1215 model()->GetTemplateURLForKeyword(google_keyword + ASCIIToUTF16("_"));
1216 ASSERT_FALSE(keyword1 == NULL);
1217 EXPECT_EQ("key1", keyword1->sync_guid());
1218 TemplateURL* keyword2 = model()->GetTemplateURLForKeyword(google_keyword);
1219 ASSERT_FALSE(keyword2 == NULL);
1220 EXPECT_EQ("key2", keyword2->sync_guid());
1221
1222 EXPECT_GE(processor()->change_list_size(), 2U);
1223 ASSERT_TRUE(processor()->contains_guid("key1"));
1224 syncer::SyncChange key1_change = processor()->change_for_guid("key1");
1225 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, key1_change.change_type());
1226 EXPECT_EQ(keyword1->keyword(),
1227 base::UTF8ToUTF16(GetKeyword(key1_change.sync_data())));
1228 ASSERT_TRUE(processor()->contains_guid("key2"));
1229 syncer::SyncChange key2_change = processor()->change_for_guid("key2");
1230 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, key2_change.change_type());
1231 EXPECT_EQ(keyword2->keyword(),
1232 base::UTF8ToUTF16(GetKeyword(key2_change.sync_data())));
1233 }
1234
TEST_F(TemplateURLServiceSyncTest,DuplicateEncodingsRemoved)1235 TEST_F(TemplateURLServiceSyncTest, DuplicateEncodingsRemoved) {
1236 // Create a sync entry with duplicate encodings.
1237 syncer::SyncDataList initial_data;
1238
1239 TemplateURLData data;
1240 data.short_name = ASCIIToUTF16("test");
1241 data.SetKeyword(ASCIIToUTF16("keyword"));
1242 data.SetURL("http://test/%s");
1243 data.input_encodings.push_back("UTF-8");
1244 data.input_encodings.push_back("UTF-8");
1245 data.input_encodings.push_back("UTF-16");
1246 data.input_encodings.push_back("UTF-8");
1247 data.input_encodings.push_back("Big5");
1248 data.input_encodings.push_back("UTF-16");
1249 data.input_encodings.push_back("Big5");
1250 data.input_encodings.push_back("Windows-1252");
1251 data.date_created = Time::FromTimeT(100);
1252 data.last_modified = Time::FromTimeT(100);
1253 data.sync_guid = "keyword";
1254 scoped_ptr<TemplateURL> turl(new TemplateURL(data));
1255 initial_data.push_back(
1256 TemplateURLService::CreateSyncDataFromTemplateURL(*turl));
1257
1258 // Now try to sync the data locally.
1259 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1260 PassProcessor(), CreateAndPassSyncErrorFactory());
1261
1262 // The entry should have been added, with duplicate encodings removed.
1263 TemplateURL* keyword =
1264 model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword"));
1265 ASSERT_FALSE(keyword == NULL);
1266 EXPECT_EQ(4U, keyword->input_encodings().size());
1267
1268 // We should also have gotten a corresponding UPDATE pushed upstream.
1269 EXPECT_GE(processor()->change_list_size(), 1U);
1270 ASSERT_TRUE(processor()->contains_guid("keyword"));
1271 syncer::SyncChange keyword_change = processor()->change_for_guid("keyword");
1272 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, keyword_change.change_type());
1273 EXPECT_EQ("UTF-8;UTF-16;Big5;Windows-1252", keyword_change.sync_data().
1274 GetSpecifics().search_engine().input_encodings());
1275 }
1276
TEST_F(TemplateURLServiceSyncTest,MergeTwoClientsBasic)1277 TEST_F(TemplateURLServiceSyncTest, MergeTwoClientsBasic) {
1278 // Start off B with some empty data.
1279 model_b()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
1280 CreateInitialSyncData(), PassProcessor(),
1281 CreateAndPassSyncErrorFactory());
1282
1283 // Merge A and B. All of B's data should transfer over to A, which initially
1284 // has no data.
1285 scoped_ptr<syncer::SyncChangeProcessorWrapperForTest> delegate_b(
1286 new syncer::SyncChangeProcessorWrapperForTest(model_b()));
1287 model_a()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
1288 model_b()->GetAllSyncData(syncer::SEARCH_ENGINES),
1289 delegate_b.PassAs<syncer::SyncChangeProcessor>(),
1290 CreateAndPassSyncErrorFactory());
1291
1292 // They should be consistent.
1293 AssertEquals(model_a()->GetAllSyncData(syncer::SEARCH_ENGINES),
1294 model_b()->GetAllSyncData(syncer::SEARCH_ENGINES));
1295 }
1296
TEST_F(TemplateURLServiceSyncTest,MergeTwoClientsDupesAndConflicts)1297 TEST_F(TemplateURLServiceSyncTest, MergeTwoClientsDupesAndConflicts) {
1298 // Start off B with some empty data.
1299 model_b()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
1300 CreateInitialSyncData(), PassProcessor(),
1301 CreateAndPassSyncErrorFactory());
1302
1303 // Set up A so we have some interesting duplicates and conflicts.
1304 model_a()->Add(CreateTestTemplateURL(ASCIIToUTF16("key4"), "http://key4.com",
1305 "key4")); // Added
1306 model_a()->Add(CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com",
1307 "key2")); // Merge - Copy of key2.
1308 model_a()->Add(CreateTestTemplateURL(ASCIIToUTF16("key3"), "http://key3.com",
1309 "key5", 10)); // Merge - Dupe of key3.
1310 model_a()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key6.com",
1311 "key6", 10)); // Conflict with key1
1312
1313 // Merge A and B.
1314 scoped_ptr<syncer::SyncChangeProcessorWrapperForTest> delegate_b(
1315 new syncer::SyncChangeProcessorWrapperForTest(model_b()));
1316 model_a()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES,
1317 model_b()->GetAllSyncData(syncer::SEARCH_ENGINES),
1318 delegate_b.PassAs<syncer::SyncChangeProcessor>(),
1319 CreateAndPassSyncErrorFactory());
1320
1321 // They should be consistent.
1322 AssertEquals(model_a()->GetAllSyncData(syncer::SEARCH_ENGINES),
1323 model_b()->GetAllSyncData(syncer::SEARCH_ENGINES));
1324 }
1325
TEST_F(TemplateURLServiceSyncTest,StopSyncing)1326 TEST_F(TemplateURLServiceSyncTest, StopSyncing) {
1327 syncer::SyncError error =
1328 model()->MergeDataAndStartSyncing(
1329 syncer::SEARCH_ENGINES,
1330 CreateInitialSyncData(),
1331 PassProcessor(),
1332 CreateAndPassSyncErrorFactory()).error();
1333 ASSERT_FALSE(error.IsSet());
1334 model()->StopSyncing(syncer::SEARCH_ENGINES);
1335
1336 syncer::SyncChangeList changes;
1337 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
1338 CreateTestTemplateURL(ASCIIToUTF16("newkeyword"), "http://new.com",
1339 "key2")));
1340 error = model()->ProcessSyncChanges(FROM_HERE, changes);
1341 EXPECT_TRUE(error.IsSet());
1342
1343 // Ensure that the sync changes were not accepted.
1344 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
1345 EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("newkeyword")));
1346 }
1347
TEST_F(TemplateURLServiceSyncTest,SyncErrorOnInitialSync)1348 TEST_F(TemplateURLServiceSyncTest, SyncErrorOnInitialSync) {
1349 processor()->set_erroneous(true);
1350 syncer::SyncError error =
1351 model()->MergeDataAndStartSyncing(
1352 syncer::SEARCH_ENGINES,
1353 CreateInitialSyncData(),
1354 PassProcessor(),
1355 CreateAndPassSyncErrorFactory()).error();
1356 EXPECT_TRUE(error.IsSet());
1357
1358 // Ensure that if the initial merge was erroneous, then subsequence attempts
1359 // to push data into the local model are rejected, since the model was never
1360 // successfully associated with Sync in the first place.
1361 syncer::SyncChangeList changes;
1362 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
1363 CreateTestTemplateURL(ASCIIToUTF16("newkeyword"), "http://new.com",
1364 "key2")));
1365 processor()->set_erroneous(false);
1366 error = model()->ProcessSyncChanges(FROM_HERE, changes);
1367 EXPECT_TRUE(error.IsSet());
1368
1369 // Ensure that the sync changes were not accepted.
1370 EXPECT_TRUE(model()->GetTemplateURLForGUID("key2"));
1371 EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("newkeyword")));
1372 }
1373
TEST_F(TemplateURLServiceSyncTest,SyncErrorOnLaterSync)1374 TEST_F(TemplateURLServiceSyncTest, SyncErrorOnLaterSync) {
1375 // Ensure that if the SyncProcessor succeeds in the initial merge, but fails
1376 // in future ProcessSyncChanges, we still return an error.
1377 syncer::SyncError error =
1378 model()->MergeDataAndStartSyncing(
1379 syncer::SEARCH_ENGINES,
1380 CreateInitialSyncData(),
1381 PassProcessor(),
1382 CreateAndPassSyncErrorFactory()).error();
1383 ASSERT_FALSE(error.IsSet());
1384
1385 syncer::SyncChangeList changes;
1386 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
1387 CreateTestTemplateURL(ASCIIToUTF16("newkeyword"), "http://new.com",
1388 "key2")));
1389 processor()->set_erroneous(true);
1390 error = model()->ProcessSyncChanges(FROM_HERE, changes);
1391 EXPECT_TRUE(error.IsSet());
1392 }
1393
TEST_F(TemplateURLServiceSyncTest,MergeTwiceWithSameSyncData)1394 TEST_F(TemplateURLServiceSyncTest, MergeTwiceWithSameSyncData) {
1395 // Ensure that a second merge with the same data as the first does not
1396 // actually update the local data.
1397 syncer::SyncDataList initial_data;
1398 initial_data.push_back(CreateInitialSyncData()[0]);
1399
1400 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com",
1401 "key1", 10)); // earlier
1402
1403 syncer::SyncError error =
1404 model()->MergeDataAndStartSyncing(
1405 syncer::SEARCH_ENGINES,
1406 initial_data,
1407 PassProcessor(),
1408 CreateAndPassSyncErrorFactory()).error();
1409 ASSERT_FALSE(error.IsSet());
1410
1411 // We should have updated the original TemplateURL with Sync's version.
1412 // Keep a copy of it so we can compare it after we re-merge.
1413 TemplateURL* key1_url = model()->GetTemplateURLForGUID("key1");
1414 ASSERT_TRUE(key1_url);
1415 scoped_ptr<TemplateURL> updated_turl(new TemplateURL(key1_url->data()));
1416 EXPECT_EQ(Time::FromTimeT(90), updated_turl->last_modified());
1417
1418 // Modify a single field of the initial data. This should not be updated in
1419 // the second merge, as the last_modified timestamp remains the same.
1420 scoped_ptr<TemplateURL> temp_turl(Deserialize(initial_data[0]));
1421 TemplateURLData data(temp_turl->data());
1422 data.short_name = ASCIIToUTF16("SomethingDifferent");
1423 temp_turl.reset(new TemplateURL(data));
1424 initial_data.clear();
1425 initial_data.push_back(
1426 TemplateURLService::CreateSyncDataFromTemplateURL(*temp_turl));
1427
1428 // Remerge the data again. This simulates shutting down and syncing again
1429 // at a different time, but the cloud data has not changed.
1430 model()->StopSyncing(syncer::SEARCH_ENGINES);
1431 sync_processor_wrapper_.reset(
1432 new syncer::SyncChangeProcessorWrapperForTest(sync_processor_.get()));
1433 error = model()->MergeDataAndStartSyncing(
1434 syncer::SEARCH_ENGINES,
1435 initial_data,
1436 PassProcessor(),
1437 CreateAndPassSyncErrorFactory()).error();
1438 ASSERT_FALSE(error.IsSet());
1439
1440 // Check that the TemplateURL was not modified.
1441 const TemplateURL* reupdated_turl = model()->GetTemplateURLForGUID("key1");
1442 ASSERT_TRUE(reupdated_turl);
1443 AssertEquals(*updated_turl, *reupdated_turl);
1444 }
1445
TEST_F(TemplateURLServiceSyncTest,SyncedDefaultGUIDArrivesFirst)1446 TEST_F(TemplateURLServiceSyncTest, SyncedDefaultGUIDArrivesFirst) {
1447 syncer::SyncDataList initial_data = CreateInitialSyncData();
1448 // The default search provider should support replacement.
1449 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("key2"),
1450 "http://key2.com/{searchTerms}", "key2", 90));
1451 initial_data[1] = TemplateURLService::CreateSyncDataFromTemplateURL(*turl);
1452 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1453 PassProcessor(), CreateAndPassSyncErrorFactory());
1454 model()->SetUserSelectedDefaultSearchProvider(
1455 model()->GetTemplateURLForGUID("key2"));
1456
1457 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1458 const TemplateURL* default_search = model()->GetDefaultSearchProvider();
1459 ASSERT_TRUE(default_search);
1460
1461 // Change kSyncedDefaultSearchProviderGUID to a GUID that does not exist in
1462 // the model yet. Ensure that the default has not changed in any way.
1463 profile_a()->GetTestingPrefService()->SetString(
1464 prefs::kSyncedDefaultSearchProviderGUID, "newdefault");
1465
1466 ASSERT_EQ(default_search, model()->GetDefaultSearchProvider());
1467
1468 // Bring in a random new search engine with a different GUID. Ensure that
1469 // it doesn't change the default.
1470 syncer::SyncChangeList changes1;
1471 changes1.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
1472 CreateTestTemplateURL(ASCIIToUTF16("random"), "http://random.com",
1473 "random")));
1474 model()->ProcessSyncChanges(FROM_HERE, changes1);
1475
1476 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1477 ASSERT_EQ(default_search, model()->GetDefaultSearchProvider());
1478
1479 // Finally, bring in the expected entry with the right GUID. Ensure that
1480 // the default has changed to the new search engine.
1481 syncer::SyncChangeList changes2;
1482 changes2.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
1483 CreateTestTemplateURL(ASCIIToUTF16("new"), "http://new.com/{searchTerms}",
1484 "newdefault")));
1485 model()->ProcessSyncChanges(FROM_HERE, changes2);
1486
1487 EXPECT_EQ(5U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1488 ASSERT_NE(default_search, model()->GetDefaultSearchProvider());
1489 ASSERT_EQ("newdefault", model()->GetDefaultSearchProvider()->sync_guid());
1490 }
1491
TEST_F(TemplateURLServiceSyncTest,DefaultGuidDeletedBeforeNewDSPArrives)1492 TEST_F(TemplateURLServiceSyncTest, DefaultGuidDeletedBeforeNewDSPArrives) {
1493 syncer::SyncDataList initial_data;
1494 // The default search provider should support replacement.
1495 scoped_ptr<TemplateURL> turl1(CreateTestTemplateURL(ASCIIToUTF16("key1"),
1496 "http://key1.com/{searchTerms}", "key1", 90));
1497 // Create a second default search provider for the
1498 // FindNewDefaultSearchProvider method to find.
1499 TemplateURLData data;
1500 data.short_name = ASCIIToUTF16("unittest");
1501 data.SetKeyword(ASCIIToUTF16("key2"));
1502 data.SetURL("http://key2.com/{searchTerms}");
1503 data.favicon_url = GURL("http://favicon.url");
1504 data.safe_for_autoreplace = false;
1505 data.date_created = Time::FromTimeT(100);
1506 data.last_modified = Time::FromTimeT(100);
1507 data.created_by_policy = false;
1508 data.prepopulate_id = 999999;
1509 data.sync_guid = "key2";
1510 data.show_in_default_list = true;
1511 scoped_ptr<TemplateURL> turl2(new TemplateURL(data));
1512 initial_data.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(
1513 *turl1));
1514 initial_data.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(
1515 *turl2));
1516 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1517 PassProcessor(), CreateAndPassSyncErrorFactory());
1518 model()->SetUserSelectedDefaultSearchProvider(
1519 model()->GetTemplateURLForGUID("key1"));
1520 ASSERT_EQ("key1", model()->GetDefaultSearchProvider()->sync_guid());
1521
1522 EXPECT_EQ(2U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1523 const TemplateURL* default_search = model()->GetDefaultSearchProvider();
1524 ASSERT_TRUE(default_search);
1525
1526 // Change kSyncedDefaultSearchProviderGUID to a GUID that does not exist in
1527 // the model yet. Ensure that the default has not changed in any way.
1528 profile_a()->GetTestingPrefService()->SetString(
1529 prefs::kSyncedDefaultSearchProviderGUID, "newdefault");
1530
1531 ASSERT_EQ("key1", model()->GetDefaultSearchProvider()->sync_guid());
1532 EXPECT_EQ("newdefault", profile_a()->GetTestingPrefService()->GetString(
1533 prefs::kSyncedDefaultSearchProviderGUID));
1534
1535 // Simulate a situation where an ACTION_DELETE on the default arrives before
1536 // the new default search provider entry. This should fail to delete the
1537 // target entry, and instead send up an "undelete" to the server, after
1538 // further uniquifying the keyword to avoid infinite sync loops. The synced
1539 // default GUID should not be changed so that when the expected default entry
1540 // arrives, it can still be set as the default.
1541 syncer::SyncChangeList changes1;
1542 changes1.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_DELETE,
1543 turl1.release()));
1544 model()->ProcessSyncChanges(FROM_HERE, changes1);
1545
1546 EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("key1_")));
1547 EXPECT_EQ(2U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1548 EXPECT_EQ("key1", model()->GetDefaultSearchProvider()->sync_guid());
1549 EXPECT_EQ("newdefault", profile_a()->GetTestingPrefService()->GetString(
1550 prefs::kSyncedDefaultSearchProviderGUID));
1551 syncer::SyncChange undelete = processor()->change_for_guid("key1");
1552 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, undelete.change_type());
1553 EXPECT_EQ("key1_",
1554 undelete.sync_data().GetSpecifics().search_engine().keyword());
1555
1556 // Finally, bring in the expected entry with the right GUID. Ensure that
1557 // the default has changed to the new search engine.
1558 syncer::SyncChangeList changes2;
1559 changes2.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
1560 CreateTestTemplateURL(ASCIIToUTF16("new"), "http://new.com/{searchTerms}",
1561 "newdefault")));
1562 model()->ProcessSyncChanges(FROM_HERE, changes2);
1563
1564 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1565 EXPECT_EQ("newdefault", model()->GetDefaultSearchProvider()->sync_guid());
1566 EXPECT_EQ("newdefault", profile_a()->GetTestingPrefService()->GetString(
1567 prefs::kSyncedDefaultSearchProviderGUID));
1568 }
1569
TEST_F(TemplateURLServiceSyncTest,SyncedDefaultArrivesAfterStartup)1570 TEST_F(TemplateURLServiceSyncTest, SyncedDefaultArrivesAfterStartup) {
1571 // Start with the default set to something in the model before we start
1572 // syncing.
1573 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("what"),
1574 "http://thewhat.com/{searchTerms}",
1575 "initdefault"));
1576 model()->SetUserSelectedDefaultSearchProvider(
1577 model()->GetTemplateURLForGUID("initdefault"));
1578
1579 const TemplateURL* default_search = model()->GetDefaultSearchProvider();
1580 ASSERT_TRUE(default_search);
1581
1582 // Set kSyncedDefaultSearchProviderGUID to something that is not yet in
1583 // the model but is expected in the initial sync. Ensure that this doesn't
1584 // change our default since we're not quite syncing yet.
1585 profile_a()->GetTestingPrefService()->SetString(
1586 prefs::kSyncedDefaultSearchProviderGUID, "key2");
1587
1588 EXPECT_EQ(default_search, model()->GetDefaultSearchProvider());
1589
1590 // Now sync the initial data, which will include the search engine entry
1591 // destined to become the new default.
1592 syncer::SyncDataList initial_data = CreateInitialSyncData();
1593 // The default search provider should support replacement.
1594 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("key2"),
1595 "http://key2.com/{searchTerms}", "key2", 90));
1596 initial_data[1] = TemplateURLService::CreateSyncDataFromTemplateURL(*turl);
1597
1598 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1599 PassProcessor(), CreateAndPassSyncErrorFactory());
1600
1601 // Ensure that the new default has been set.
1602 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1603 ASSERT_NE(default_search, model()->GetDefaultSearchProvider());
1604 ASSERT_EQ("key2", model()->GetDefaultSearchProvider()->sync_guid());
1605 }
1606
TEST_F(TemplateURLServiceSyncTest,SyncedDefaultAlreadySetOnStartup)1607 TEST_F(TemplateURLServiceSyncTest, SyncedDefaultAlreadySetOnStartup) {
1608 // Start with the default set to something in the model before we start
1609 // syncing.
1610 const char kGUID[] = "initdefault";
1611 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("what"),
1612 "http://thewhat.com/{searchTerms}",
1613 kGUID));
1614 model()->SetUserSelectedDefaultSearchProvider(
1615 model()->GetTemplateURLForGUID(kGUID));
1616
1617 const TemplateURL* default_search = model()->GetDefaultSearchProvider();
1618 ASSERT_TRUE(default_search);
1619
1620 // Set kSyncedDefaultSearchProviderGUID to the current default.
1621 profile_a()->GetTestingPrefService()->SetString(
1622 prefs::kSyncedDefaultSearchProviderGUID, kGUID);
1623
1624 EXPECT_EQ(default_search, model()->GetDefaultSearchProvider());
1625
1626 // Now sync the initial data.
1627 syncer::SyncDataList initial_data = CreateInitialSyncData();
1628 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1629 PassProcessor(), CreateAndPassSyncErrorFactory());
1630
1631 // Ensure that the new entries were added and the default has not changed.
1632 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1633 ASSERT_EQ(default_search, model()->GetDefaultSearchProvider());
1634 }
1635
TEST_F(TemplateURLServiceSyncTest,SyncWithManagedDefaultSearch)1636 TEST_F(TemplateURLServiceSyncTest, SyncWithManagedDefaultSearch) {
1637 // First start off with a few entries and make sure we can set an unmanaged
1638 // default search provider.
1639 syncer::SyncDataList initial_data = CreateInitialSyncData();
1640 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1641 PassProcessor(), CreateAndPassSyncErrorFactory());
1642 model()->SetUserSelectedDefaultSearchProvider(
1643 model()->GetTemplateURLForGUID("key2"));
1644
1645 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1646 ASSERT_FALSE(model()->is_default_search_managed());
1647 ASSERT_TRUE(model()->GetDefaultSearchProvider());
1648
1649 // Change the default search provider to a managed one.
1650 const char kName[] = "manageddefault";
1651 const char kSearchURL[] = "http://manageddefault.com/search?t={searchTerms}";
1652 const char kIconURL[] = "http://manageddefault.com/icon.jpg";
1653 const char kEncodings[] = "UTF-16;UTF-32";
1654 const char kAlternateURL[] =
1655 "http://manageddefault.com/search#t={searchTerms}";
1656 const char kSearchTermsReplacementKey[] = "espv";
1657 test_util_a_.SetManagedDefaultSearchPreferences(true, kName, kName,
1658 kSearchURL, std::string(), kIconURL, kEncodings, kAlternateURL,
1659 kSearchTermsReplacementKey);
1660 const TemplateURL* dsp_turl = model()->GetDefaultSearchProvider();
1661
1662 EXPECT_TRUE(model()->is_default_search_managed());
1663
1664 // Add a new entry from Sync. It should still sync in despite the default
1665 // being managed.
1666 syncer::SyncChangeList changes;
1667 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
1668 CreateTestTemplateURL(ASCIIToUTF16("newkeyword"),
1669 "http://new.com/{searchTerms}",
1670 "newdefault")));
1671 model()->ProcessSyncChanges(FROM_HERE, changes);
1672
1673 EXPECT_EQ(4U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1674
1675 // Change kSyncedDefaultSearchProviderGUID to point to the new entry and
1676 // ensure that the DSP remains managed.
1677 profile_a()->GetTestingPrefService()->SetString(
1678 prefs::kSyncedDefaultSearchProviderGUID,
1679 "newdefault");
1680
1681 EXPECT_EQ(dsp_turl, model()->GetDefaultSearchProvider());
1682 EXPECT_TRUE(model()->is_default_search_managed());
1683
1684 // Go unmanaged. Ensure that the DSP changes to the expected pending entry
1685 // from Sync.
1686 const TemplateURL* expected_default =
1687 model()->GetTemplateURLForGUID("newdefault");
1688 test_util_a_.RemoveManagedDefaultSearchPreferences();
1689
1690 EXPECT_EQ(expected_default, model()->GetDefaultSearchProvider());
1691 }
1692
TEST_F(TemplateURLServiceSyncTest,SyncMergeDeletesDefault)1693 TEST_F(TemplateURLServiceSyncTest, SyncMergeDeletesDefault) {
1694 // If the value from Sync is a duplicate of the local default and is newer, it
1695 // should safely replace the local value and set as the new default.
1696 TemplateURL* default_turl = CreateTestTemplateURL(ASCIIToUTF16("key1"),
1697 "http://key1.com/{searchTerms}", "whateverguid", 10);
1698 model()->Add(default_turl);
1699 model()->SetUserSelectedDefaultSearchProvider(default_turl);
1700
1701 syncer::SyncDataList initial_data = CreateInitialSyncData();
1702 // The key1 entry should be a duplicate of the default.
1703 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(ASCIIToUTF16("key1"),
1704 "http://key1.com/{searchTerms}", "key1", 90));
1705 initial_data[0] = TemplateURLService::CreateSyncDataFromTemplateURL(*turl);
1706
1707 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1708 PassProcessor(), CreateAndPassSyncErrorFactory());
1709
1710 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1711 EXPECT_FALSE(model()->GetTemplateURLForGUID("whateverguid"));
1712 EXPECT_EQ(model()->GetDefaultSearchProvider(),
1713 model()->GetTemplateURLForGUID("key1"));
1714 }
1715
TEST_F(TemplateURLServiceSyncTest,LocalDefaultWinsConflict)1716 TEST_F(TemplateURLServiceSyncTest, LocalDefaultWinsConflict) {
1717 // We expect that the local default always wins keyword conflict resolution.
1718 const base::string16 keyword(ASCIIToUTF16("key1"));
1719 const std::string url("http://whatever.com/{searchTerms}");
1720 TemplateURL* default_turl = CreateTestTemplateURL(keyword,
1721 url,
1722 "whateverguid",
1723 10);
1724 model()->Add(default_turl);
1725 model()->SetUserSelectedDefaultSearchProvider(default_turl);
1726
1727 syncer::SyncDataList initial_data = CreateInitialSyncData();
1728 // The key1 entry should be different from the default but conflict in the
1729 // keyword.
1730 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(keyword,
1731 "http://key1.com/{searchTerms}", "key1", 90));
1732 initial_data[0] = TemplateURLService::CreateSyncDataFromTemplateURL(*turl);
1733
1734 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1735 PassProcessor(), CreateAndPassSyncErrorFactory());
1736
1737 // Since the local default was not yet synced, it should be merged with the
1738 // conflicting TemplateURL. However, its values should have been preserved
1739 // since it would have won conflict resolution due to being the default.
1740 EXPECT_EQ(3U, model()->GetAllSyncData(syncer::SEARCH_ENGINES).size());
1741 const TemplateURL* winner = model()->GetTemplateURLForGUID("key1");
1742 ASSERT_TRUE(winner);
1743 EXPECT_EQ(model()->GetDefaultSearchProvider(), winner);
1744 EXPECT_EQ(keyword, winner->keyword());
1745 EXPECT_EQ(url, winner->url());
1746 ASSERT_TRUE(processor()->contains_guid("key1"));
1747 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
1748 processor()->change_for_guid("key1").change_type());
1749 EXPECT_EQ(url, GetURL(processor()->change_for_guid("key1").sync_data()));
1750
1751 // There is no loser, as the two were merged together. The local sync_guid
1752 // should no longer be found in the model.
1753 const TemplateURL* loser = model()->GetTemplateURLForGUID("whateverguid");
1754 ASSERT_FALSE(loser);
1755 }
1756
TEST_F(TemplateURLServiceSyncTest,DeleteBogusData)1757 TEST_F(TemplateURLServiceSyncTest, DeleteBogusData) {
1758 // Create a couple of bogus entries to sync.
1759 syncer::SyncDataList initial_data;
1760 scoped_ptr<TemplateURL> turl(
1761 CreateTestTemplateURL(ASCIIToUTF16("key1"), "http://key1.com", "key1"));
1762 initial_data.push_back(
1763 CreateCustomSyncData(*turl, false, std::string(), turl->sync_guid()));
1764 turl.reset(CreateTestTemplateURL(ASCIIToUTF16("key2"), "http://key2.com"));
1765 initial_data.push_back(
1766 CreateCustomSyncData(*turl, false, turl->url(), std::string()));
1767
1768 // Now try to sync the data locally.
1769 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1770 PassProcessor(), CreateAndPassSyncErrorFactory());
1771
1772 // Nothing should have been added, and both bogus entries should be marked for
1773 // deletion.
1774 EXPECT_EQ(0U, model()->GetTemplateURLs().size());
1775 EXPECT_EQ(2U, processor()->change_list_size());
1776 ASSERT_TRUE(processor()->contains_guid("key1"));
1777 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE,
1778 processor()->change_for_guid("key1").change_type());
1779 ASSERT_TRUE(processor()->contains_guid(std::string()));
1780 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE,
1781 processor()->change_for_guid(std::string()).change_type());
1782 }
1783
TEST_F(TemplateURLServiceSyncTest,PreSyncDeletes)1784 TEST_F(TemplateURLServiceSyncTest, PreSyncDeletes) {
1785 model()->pre_sync_deletes_.insert("key1");
1786 model()->pre_sync_deletes_.insert("key2");
1787 model()->pre_sync_deletes_.insert("aaa");
1788 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("whatever"),
1789 "http://key1.com", "bbb"));
1790 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
1791 syncer::SEARCH_ENGINES,
1792 CreateInitialSyncData(), PassProcessor(),
1793 CreateAndPassSyncErrorFactory());
1794
1795 // We expect the model to have GUIDs {bbb, key3} after our initial merge.
1796 EXPECT_TRUE(model()->GetTemplateURLForGUID("bbb"));
1797 EXPECT_TRUE(model()->GetTemplateURLForGUID("key3"));
1798 syncer::SyncChange change = processor()->change_for_guid("key1");
1799 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, change.change_type());
1800 change = processor()->change_for_guid("key2");
1801 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, change.change_type());
1802 // "aaa" should have been pruned out on account of not being from Sync.
1803 EXPECT_FALSE(processor()->contains_guid("aaa"));
1804 // The set of pre-sync deletes should be cleared so they're not reused if
1805 // MergeDataAndStartSyncing gets called again.
1806 EXPECT_TRUE(model()->pre_sync_deletes_.empty());
1807
1808 // Those sync items deleted via pre-sync-deletes should not get added. The
1809 // remaining sync item (key3) should though.
1810 EXPECT_EQ(1, merge_result.num_items_added());
1811 EXPECT_EQ(0, merge_result.num_items_modified());
1812 EXPECT_EQ(0, merge_result.num_items_deleted());
1813 EXPECT_EQ(1, merge_result.num_items_before_association());
1814 EXPECT_EQ(2, merge_result.num_items_after_association());
1815 }
1816
TEST_F(TemplateURLServiceSyncTest,PreSyncUpdates)1817 TEST_F(TemplateURLServiceSyncTest, PreSyncUpdates) {
1818 const char* kNewKeyword = "somethingnew";
1819 // Fetch the prepopulate search engines so we know what they are.
1820 size_t default_search_provider_index = 0;
1821 ScopedVector<TemplateURLData> prepop_turls =
1822 TemplateURLPrepopulateData::GetPrepopulatedEngines(
1823 profile_a()->GetTestingPrefService(), &default_search_provider_index);
1824
1825 // We have to prematurely exit this test if for some reason this machine does
1826 // not have any prepopulate TemplateURLs.
1827 ASSERT_FALSE(prepop_turls.empty());
1828
1829 // Create a copy of the first TemplateURL with a really old timestamp and a
1830 // new keyword. Add it to the model.
1831 TemplateURLData data_copy(*prepop_turls[0]);
1832 data_copy.last_modified = Time::FromTimeT(10);
1833 base::string16 original_keyword = data_copy.keyword();
1834 data_copy.SetKeyword(ASCIIToUTF16(kNewKeyword));
1835 // Set safe_for_autoreplace to false so our keyword survives.
1836 data_copy.safe_for_autoreplace = false;
1837 model()->Add(new TemplateURL(data_copy));
1838
1839 // Merge the prepopulate search engines.
1840 base::Time pre_merge_time = base::Time::Now();
1841 base::RunLoop().RunUntilIdle();
1842 test_util_a_.ResetModel(true);
1843
1844 // The newly added search engine should have been safely merged, with an
1845 // updated time.
1846 TemplateURL* added_turl = model()->GetTemplateURLForKeyword(
1847 ASCIIToUTF16(kNewKeyword));
1848 ASSERT_TRUE(added_turl);
1849 base::Time new_timestamp = added_turl->last_modified();
1850 EXPECT_GE(new_timestamp, pre_merge_time);
1851 std::string sync_guid = added_turl->sync_guid();
1852
1853 // Bring down a copy of the prepopulate engine from Sync with the old values,
1854 // including the old timestamp and the same GUID. Ensure that it loses
1855 // conflict resolution against the local value, and an update is sent to the
1856 // server. The new timestamp should be preserved.
1857 syncer::SyncDataList initial_data;
1858 data_copy.SetKeyword(original_keyword);
1859 data_copy.sync_guid = sync_guid;
1860 scoped_ptr<TemplateURL> sync_turl(new TemplateURL(data_copy));
1861 initial_data.push_back(
1862 TemplateURLService::CreateSyncDataFromTemplateURL(*sync_turl));
1863
1864 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
1865 syncer::SEARCH_ENGINES,
1866 initial_data, PassProcessor(), CreateAndPassSyncErrorFactory());
1867
1868 ASSERT_EQ(added_turl, model()->GetTemplateURLForKeyword(
1869 ASCIIToUTF16(kNewKeyword)));
1870 EXPECT_EQ(new_timestamp, added_turl->last_modified());
1871 syncer::SyncChange change = processor()->change_for_guid(sync_guid);
1872 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type());
1873 EXPECT_EQ(kNewKeyword,
1874 change.sync_data().GetSpecifics().search_engine().keyword());
1875 EXPECT_EQ(new_timestamp, base::Time::FromInternalValue(
1876 change.sync_data().GetSpecifics().search_engine().last_modified()));
1877
1878 // All the sync data is old, so nothing should change locally.
1879 EXPECT_EQ(0, merge_result.num_items_added());
1880 EXPECT_EQ(0, merge_result.num_items_modified());
1881 EXPECT_EQ(0, merge_result.num_items_deleted());
1882 EXPECT_EQ(static_cast<int>(prepop_turls.size()),
1883 merge_result.num_items_before_association());
1884 EXPECT_EQ(static_cast<int>(prepop_turls.size()),
1885 merge_result.num_items_after_association());
1886 }
1887
TEST_F(TemplateURLServiceSyncTest,SyncBaseURLs)1888 TEST_F(TemplateURLServiceSyncTest, SyncBaseURLs) {
1889 // Verify that bringing in a remote TemplateURL that uses Google base URLs
1890 // causes it to get a local keyword that matches the local base URL.
1891 test_util_a_.SetGoogleBaseURL(GURL("http://google.com/"));
1892 syncer::SyncDataList initial_data;
1893 scoped_ptr<TemplateURL> turl(CreateTestTemplateURL(
1894 ASCIIToUTF16("google.co.uk"), "{google:baseURL}search?q={searchTerms}",
1895 "guid"));
1896 initial_data.push_back(
1897 TemplateURLService::CreateSyncDataFromTemplateURL(*turl));
1898 model()->MergeDataAndStartSyncing(syncer::SEARCH_ENGINES, initial_data,
1899 PassProcessor(), CreateAndPassSyncErrorFactory());
1900 TemplateURL* synced_turl = model()->GetTemplateURLForGUID("guid");
1901 ASSERT_TRUE(synced_turl);
1902 EXPECT_EQ(ASCIIToUTF16("google.com"), synced_turl->keyword());
1903 EXPECT_EQ(0U, processor()->change_list_size());
1904
1905 // Remote updates to this URL's keyword should be silently ignored.
1906 syncer::SyncChangeList changes;
1907 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
1908 CreateTestTemplateURL(ASCIIToUTF16("google.de"),
1909 "{google:baseURL}search?q={searchTerms}", "guid")));
1910 model()->ProcessSyncChanges(FROM_HERE, changes);
1911 EXPECT_EQ(ASCIIToUTF16("google.com"), synced_turl->keyword());
1912 EXPECT_EQ(0U, processor()->change_list_size());
1913
1914 // A local change to the Google base URL should update the keyword and
1915 // generate a sync change.
1916 test_util_a_.SetGoogleBaseURL(GURL("http://google.co.in/"));
1917 EXPECT_EQ(ASCIIToUTF16("google.co.in"), synced_turl->keyword());
1918 EXPECT_EQ(1U, processor()->change_list_size());
1919 ASSERT_TRUE(processor()->contains_guid("guid"));
1920 syncer::SyncChange change(processor()->change_for_guid("guid"));
1921 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type());
1922 EXPECT_EQ("google.co.in", GetKeyword(change.sync_data()));
1923 }
1924
TEST_F(TemplateURLServiceSyncTest,MergeInSyncTemplateURL)1925 TEST_F(TemplateURLServiceSyncTest, MergeInSyncTemplateURL) {
1926 // An enumeration used to indicate which TemplateURL test value is expected
1927 // for a particular test result.
1928 enum ExpectedTemplateURL {
1929 LOCAL,
1930 SYNC,
1931 BOTH,
1932 NEITHER,
1933 };
1934
1935 // Sets up and executes a MergeInSyncTemplateURL test given a number of
1936 // expected start and end states:
1937 // * |conflict_winner| denotes which TemplateURL should win the
1938 // conflict.
1939 // * |synced_at_start| denotes which of the TemplateURLs should known
1940 // to Sync.
1941 // * |update_sent| denotes which TemplateURL should have an
1942 // ACTION_UPDATE sent to the server after the merge.
1943 // * |turl_uniquified| denotes which TemplateURL should have its
1944 // keyword updated after the merge.
1945 // * |present_in_model| denotes which TemplateURL should be found in
1946 // the model after the merge.
1947 // * If |keywords_conflict| is true, the TemplateURLs are set up with
1948 // the same keyword.
1949 const struct {
1950 ExpectedTemplateURL conflict_winner;
1951 ExpectedTemplateURL synced_at_start;
1952 ExpectedTemplateURL update_sent;
1953 ExpectedTemplateURL turl_uniquified;
1954 ExpectedTemplateURL present_in_model;
1955 bool keywords_conflict;
1956 int merge_results[3]; // in Added, Modified, Deleted order.
1957 } test_cases[] = {
1958 // Both are synced and the new sync entry is better: Local is uniquified and
1959 // UPDATE sent. Sync is added.
1960 {SYNC, BOTH, LOCAL, LOCAL, BOTH, true, {1, 1, 0}},
1961 // Both are synced and the local entry is better: Sync is uniquified and
1962 // added to the model. An UPDATE is sent for it.
1963 {LOCAL, BOTH, SYNC, SYNC, BOTH, true, {1, 1, 0}},
1964 // Local was not known to Sync and the new sync entry is better: Sync is
1965 // added. Local is removed. No updates.
1966 {SYNC, SYNC, NEITHER, NEITHER, SYNC, true, {1, 0, 1}},
1967 // Local was not known to sync and the local entry is better: Local is
1968 // updated with sync GUID, Sync is not added. UPDATE sent for Sync.
1969 {LOCAL, SYNC, SYNC, NEITHER, SYNC, true, {0, 1, 0}},
1970 // No conflicting keyword. Both should be added with their original
1971 // keywords, with no updates sent. Note that MergeDataAndStartSyncing is
1972 // responsible for creating the ACTION_ADD for the local TemplateURL.
1973 {NEITHER, SYNC, NEITHER, NEITHER, BOTH, false, {1, 0, 0}},
1974 };
1975
1976 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
1977 // Assert all the valid states of ExpectedTemplateURLs.
1978 ASSERT_FALSE(test_cases[i].conflict_winner == BOTH);
1979 ASSERT_FALSE(test_cases[i].synced_at_start == NEITHER);
1980 ASSERT_FALSE(test_cases[i].synced_at_start == LOCAL);
1981 ASSERT_FALSE(test_cases[i].update_sent == BOTH);
1982 ASSERT_FALSE(test_cases[i].turl_uniquified == BOTH);
1983 ASSERT_FALSE(test_cases[i].present_in_model == NEITHER);
1984
1985 const base::string16 local_keyword = ASCIIToUTF16("localkeyword");
1986 const base::string16 sync_keyword = test_cases[i].keywords_conflict ?
1987 local_keyword : ASCIIToUTF16("synckeyword");
1988 const std::string local_url = "www.localurl.com";
1989 const std::string sync_url = "www.syncurl.com";
1990 const time_t local_last_modified = 100;
1991 const time_t sync_last_modified =
1992 test_cases[i].conflict_winner == SYNC ? 110 : 90;
1993 const std::string local_guid = "local_guid";
1994 const std::string sync_guid = "sync_guid";
1995
1996 // Initialize expectations.
1997 base::string16 expected_local_keyword = local_keyword;
1998 base::string16 expected_sync_keyword = sync_keyword;
1999
2000 // Create the data and run the actual test.
2001 TemplateURL* local_turl = CreateTestTemplateURL(
2002 local_keyword, local_url, local_guid, local_last_modified);
2003 model()->Add(local_turl);
2004 scoped_ptr<TemplateURL> sync_turl(CreateTestTemplateURL(
2005 sync_keyword, sync_url, sync_guid, sync_last_modified));
2006
2007 SyncDataMap sync_data;
2008 if (test_cases[i].synced_at_start == SYNC ||
2009 test_cases[i].synced_at_start == BOTH) {
2010 sync_data[sync_turl->sync_guid()] =
2011 TemplateURLService::CreateSyncDataFromTemplateURL(*sync_turl);
2012 }
2013 if (test_cases[i].synced_at_start == BOTH) {
2014 sync_data[local_turl->sync_guid()] =
2015 TemplateURLService::CreateSyncDataFromTemplateURL(*local_turl);
2016 }
2017 SyncDataMap initial_data;
2018 initial_data[local_turl->sync_guid()] =
2019 TemplateURLService::CreateSyncDataFromTemplateURL(*local_turl);
2020
2021 syncer::SyncChangeList change_list;
2022 syncer::SyncMergeResult merge_result(syncer::SEARCH_ENGINES);
2023 model()->MergeInSyncTemplateURL(sync_turl.get(),
2024 sync_data,
2025 &change_list,
2026 &initial_data,
2027 &merge_result);
2028
2029 // Verify the merge results were set appropriately.
2030 EXPECT_EQ(test_cases[i].merge_results[0], merge_result.num_items_added());
2031 EXPECT_EQ(test_cases[i].merge_results[1],
2032 merge_result.num_items_modified());
2033 EXPECT_EQ(test_cases[i].merge_results[2], merge_result.num_items_deleted());
2034
2035 // Check for expected updates, if any.
2036 std::string expected_update_guid;
2037 if (test_cases[i].update_sent == LOCAL)
2038 expected_update_guid = local_guid;
2039 else if (test_cases[i].update_sent == SYNC)
2040 expected_update_guid = sync_guid;
2041 if (!expected_update_guid.empty()) {
2042 ASSERT_EQ(1U, change_list.size());
2043 EXPECT_EQ(expected_update_guid, GetGUID(change_list[0].sync_data()));
2044 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE,
2045 change_list[0].change_type());
2046 } else {
2047 EXPECT_EQ(0U, change_list.size());
2048 }
2049
2050 // Adjust the expectations based on the expectation enums.
2051 if (test_cases[i].turl_uniquified == LOCAL) {
2052 DCHECK(test_cases[i].keywords_conflict);
2053 expected_local_keyword = ASCIIToUTF16("localkeyword_");
2054 }
2055 if (test_cases[i].turl_uniquified == SYNC) {
2056 DCHECK(test_cases[i].keywords_conflict);
2057 expected_sync_keyword = ASCIIToUTF16("localkeyword_");
2058 }
2059
2060 // Check for TemplateURLs expected in the model. Note that this is checked
2061 // by GUID rather than the initial pointer, as a merge could occur (the
2062 // Sync TemplateURL overtakes the local one). Also remove the present
2063 // TemplateURL when done so the next test case starts with a clean slate.
2064 if (test_cases[i].present_in_model == LOCAL ||
2065 test_cases[i].present_in_model == BOTH) {
2066 ASSERT_TRUE(model()->GetTemplateURLForGUID(local_guid));
2067 EXPECT_EQ(expected_local_keyword, local_turl->keyword());
2068 EXPECT_EQ(local_url, local_turl->url());
2069 EXPECT_EQ(local_last_modified, local_turl->last_modified().ToTimeT());
2070 model()->Remove(model()->GetTemplateURLForGUID(local_guid));
2071 }
2072 if (test_cases[i].present_in_model == SYNC ||
2073 test_cases[i].present_in_model == BOTH) {
2074 ASSERT_TRUE(model()->GetTemplateURLForGUID(sync_guid));
2075 EXPECT_EQ(expected_sync_keyword, sync_turl->keyword());
2076 EXPECT_EQ(sync_url, sync_turl->url());
2077 EXPECT_EQ(sync_last_modified, sync_turl->last_modified().ToTimeT());
2078 model()->Remove(model()->GetTemplateURLForGUID(sync_guid));
2079 }
2080 } // for
2081 }
2082
TEST_F(TemplateURLServiceSyncTest,MergePrepopulatedEngine)2083 TEST_F(TemplateURLServiceSyncTest, MergePrepopulatedEngine) {
2084 scoped_ptr<TemplateURLData> default_turl(
2085 TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(NULL));
2086
2087 // Merge with an initial list containing a prepopulated engine with a wrong
2088 // URL.
2089 syncer::SyncDataList list;
2090 scoped_ptr<TemplateURL> sync_turl(CopyTemplateURL(default_turl.get(),
2091 "http://wrong.url.com?q={searchTerms}", "default"));
2092 list.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(*sync_turl));
2093 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
2094 syncer::SEARCH_ENGINES, list, PassProcessor(),
2095 CreateAndPassSyncErrorFactory());
2096
2097 const TemplateURL* result_turl = model()->GetTemplateURLForGUID("default");
2098 EXPECT_TRUE(result_turl);
2099 EXPECT_EQ(default_turl->keyword(), result_turl->keyword());
2100 EXPECT_EQ(default_turl->short_name, result_turl->short_name());
2101 EXPECT_EQ(default_turl->url(), result_turl->url());
2102 }
2103
TEST_F(TemplateURLServiceSyncTest,AddPrepopulatedEngine)2104 TEST_F(TemplateURLServiceSyncTest, AddPrepopulatedEngine) {
2105 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
2106 syncer::SEARCH_ENGINES, syncer::SyncDataList(), PassProcessor(),
2107 CreateAndPassSyncErrorFactory());
2108
2109 scoped_ptr<TemplateURLData> default_turl(
2110 TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(NULL));
2111 TemplateURL* sync_turl = CopyTemplateURL(default_turl.get(),
2112 "http://wrong.url.com?q={searchTerms}", "default");
2113
2114 // Add a prepopulated engine with a wrong URL.
2115 syncer::SyncChangeList changes;
2116 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_ADD,
2117 sync_turl));
2118 model()->ProcessSyncChanges(FROM_HERE, changes);
2119
2120 const TemplateURL* result_turl = model()->GetTemplateURLForGUID("default");
2121 EXPECT_TRUE(result_turl);
2122 EXPECT_EQ(default_turl->keyword(), result_turl->keyword());
2123 EXPECT_EQ(default_turl->short_name, result_turl->short_name());
2124 EXPECT_EQ(default_turl->url(), result_turl->url());
2125 }
2126
TEST_F(TemplateURLServiceSyncTest,UpdatePrepopulatedEngine)2127 TEST_F(TemplateURLServiceSyncTest, UpdatePrepopulatedEngine) {
2128 scoped_ptr<TemplateURLData> default_turl(
2129 TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(NULL));
2130
2131 TemplateURLData data = *default_turl;
2132 data.SetURL("http://old.wrong.url.com?q={searchTerms}");
2133 data.sync_guid = "default";
2134 model()->Add(new TemplateURL(data));
2135
2136 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
2137 syncer::SEARCH_ENGINES, syncer::SyncDataList(), PassProcessor(),
2138 CreateAndPassSyncErrorFactory());
2139
2140 TemplateURL* sync_turl = CopyTemplateURL(default_turl.get(),
2141 "http://new.wrong.url.com?q={searchTerms}", "default");
2142
2143 // Update the engine in the model, which is prepopulated, with a new one.
2144 // Both have wrong URLs, but it should still get corrected.
2145 syncer::SyncChangeList changes;
2146 changes.push_back(CreateTestSyncChange(syncer::SyncChange::ACTION_UPDATE,
2147 sync_turl));
2148 model()->ProcessSyncChanges(FROM_HERE, changes);
2149
2150 const TemplateURL* result_turl = model()->GetTemplateURLForGUID("default");
2151 EXPECT_TRUE(result_turl);
2152 EXPECT_EQ(default_turl->keyword(), result_turl->keyword());
2153 EXPECT_EQ(default_turl->short_name, result_turl->short_name());
2154 EXPECT_EQ(default_turl->url(), result_turl->url());
2155 }
2156
TEST_F(TemplateURLServiceSyncTest,MergeEditedPrepopulatedEngine)2157 TEST_F(TemplateURLServiceSyncTest, MergeEditedPrepopulatedEngine) {
2158 scoped_ptr<TemplateURLData> default_turl(
2159 TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(NULL));
2160
2161 TemplateURLData data(*default_turl);
2162 data.safe_for_autoreplace = false;
2163 data.SetKeyword(ASCIIToUTF16("new_kw"));
2164 data.short_name = ASCIIToUTF16("my name");
2165 data.SetURL("http://wrong.url.com?q={searchTerms}");
2166 data.date_created = Time::FromTimeT(50);
2167 data.last_modified = Time::FromTimeT(50);
2168 data.sync_guid = "default";
2169 model()->Add(new TemplateURL(data));
2170
2171 data.date_created = Time::FromTimeT(100);
2172 data.last_modified = Time::FromTimeT(100);
2173 scoped_ptr<TemplateURL> sync_turl(new TemplateURL(data));
2174 syncer::SyncDataList list;
2175 list.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(*sync_turl));
2176 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
2177 syncer::SEARCH_ENGINES, list, PassProcessor(),
2178 CreateAndPassSyncErrorFactory());
2179
2180 const TemplateURL* result_turl = model()->GetTemplateURLForGUID("default");
2181 EXPECT_TRUE(result_turl);
2182 EXPECT_EQ(ASCIIToUTF16("new_kw"), result_turl->keyword());
2183 EXPECT_EQ(ASCIIToUTF16("my name"), result_turl->short_name());
2184 EXPECT_EQ(default_turl->url(), result_turl->url());
2185 }
2186
TEST_F(TemplateURLServiceSyncTest,MergeNonEditedPrepopulatedEngine)2187 TEST_F(TemplateURLServiceSyncTest, MergeNonEditedPrepopulatedEngine) {
2188 scoped_ptr<TemplateURLData> default_turl(
2189 TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(NULL));
2190
2191 TemplateURLData data(*default_turl);
2192 data.safe_for_autoreplace = true; // Can be replaced with built-in values.
2193 data.SetKeyword(ASCIIToUTF16("new_kw"));
2194 data.short_name = ASCIIToUTF16("my name");
2195 data.SetURL("http://wrong.url.com?q={searchTerms}");
2196 data.date_created = Time::FromTimeT(50);
2197 data.last_modified = Time::FromTimeT(50);
2198 data.sync_guid = "default";
2199 model()->Add(new TemplateURL(data));
2200
2201 data.date_created = Time::FromTimeT(100);
2202 data.last_modified = Time::FromTimeT(100);
2203 scoped_ptr<TemplateURL> sync_turl(new TemplateURL(data));
2204 syncer::SyncDataList list;
2205 list.push_back(TemplateURLService::CreateSyncDataFromTemplateURL(*sync_turl));
2206 syncer::SyncMergeResult merge_result = model()->MergeDataAndStartSyncing(
2207 syncer::SEARCH_ENGINES, list, PassProcessor(),
2208 CreateAndPassSyncErrorFactory());
2209
2210 const TemplateURL* result_turl = model()->GetTemplateURLForGUID("default");
2211 EXPECT_TRUE(result_turl);
2212 EXPECT_EQ(default_turl->keyword(), result_turl->keyword());
2213 EXPECT_EQ(default_turl->short_name, result_turl->short_name());
2214 EXPECT_EQ(default_turl->url(), result_turl->url());
2215 }
2216
TEST_F(TemplateURLServiceSyncTest,GUIDUpdatedOnDefaultSearchChange)2217 TEST_F(TemplateURLServiceSyncTest, GUIDUpdatedOnDefaultSearchChange) {
2218 const char kGUID[] = "initdefault";
2219 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("what"),
2220 "http://thewhat.com/{searchTerms}",
2221 kGUID));
2222 model()->SetUserSelectedDefaultSearchProvider(
2223 model()->GetTemplateURLForGUID(kGUID));
2224
2225 const TemplateURL* default_search = model()->GetDefaultSearchProvider();
2226 ASSERT_TRUE(default_search);
2227
2228 const char kNewGUID[] = "newdefault";
2229 model()->Add(CreateTestTemplateURL(ASCIIToUTF16("what"),
2230 "http://thewhat.com/{searchTerms}",
2231 kNewGUID));
2232 model()->SetUserSelectedDefaultSearchProvider(
2233 model()->GetTemplateURLForGUID(kNewGUID));
2234
2235 EXPECT_EQ(kNewGUID, profile_a()->GetTestingPrefService()->GetString(
2236 prefs::kSyncedDefaultSearchProviderGUID));
2237 }
2238