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