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