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