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