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