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