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