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