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