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