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