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