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