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