1// Copyright 2014 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/json/json_reader.h"
6#include "base/json/json_string_value_serializer.h"
7#include "base/json/json_writer.h"
8#include "base/message_loop/message_loop.h"
9#include "base/prefs/scoped_user_pref_update.h"
10#include "base/strings/utf_string_conversions.h"
11#include "chrome/browser/prefs/pref_model_associator.h"
12#include "chrome/browser/prefs/pref_service_syncable.h"
13#include "chrome/common/pref_names.h"
14#include "chrome/grit/locale_settings.h"
15#include "chrome/test/base/testing_pref_service_syncable.h"
16#include "components/pref_registry/pref_registry_syncable.h"
17#include "sync/api/attachments/attachment_id.h"
18#include "sync/api/sync_change.h"
19#include "sync/api/sync_data.h"
20#include "sync/api/sync_error_factory_mock.h"
21#include "sync/api/syncable_service.h"
22#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
23#include "sync/protocol/preference_specifics.pb.h"
24#include "sync/protocol/sync.pb.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27using syncer::SyncChange;
28using syncer::SyncData;
29
30namespace {
31const char kExampleUrl0[] = "http://example.com/0";
32const char kExampleUrl1[] = "http://example.com/1";
33const char kExampleUrl2[] = "http://example.com/2";
34const char kUnsyncedPreferenceName[] = "nonsense_pref_name";
35const char kUnsyncedPreferenceDefaultValue[] = "default";
36const char kNonDefaultCharsetValue[] = "foo";
37}  // namespace
38
39class TestSyncProcessorStub : public syncer::SyncChangeProcessor {
40 public:
41  explicit TestSyncProcessorStub(syncer::SyncChangeList* output)
42      : output_(output), fail_next_(false) {}
43  virtual syncer::SyncError ProcessSyncChanges(
44      const tracked_objects::Location& from_here,
45      const syncer::SyncChangeList& change_list) OVERRIDE {
46    if (output_)
47      output_->insert(output_->end(), change_list.begin(), change_list.end());
48    if (fail_next_) {
49      fail_next_ = false;
50      return syncer::SyncError(
51          FROM_HERE, syncer::SyncError::DATATYPE_ERROR, "Error",
52          syncer::PREFERENCES);
53    }
54    return syncer::SyncError();
55  }
56
57  void FailNextProcessSyncChanges() {
58    fail_next_ = true;
59  }
60
61  virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
62      const OVERRIDE {
63    return syncer::SyncDataList();
64  }
65 private:
66  syncer::SyncChangeList* output_;
67  bool fail_next_;
68};
69
70class PrefsSyncableServiceTest : public testing::Test {
71 public:
72  PrefsSyncableServiceTest() :
73      pref_sync_service_(NULL),
74      test_processor_(NULL),
75      next_pref_remote_sync_node_id_(0) {}
76
77  virtual void SetUp() {
78    prefs_.registry()->RegisterStringPref(
79        kUnsyncedPreferenceName,
80        kUnsyncedPreferenceDefaultValue,
81        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
82    prefs_.registry()->RegisterStringPref(
83        prefs::kHomePage,
84        std::string(),
85        user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
86    prefs_.registry()->RegisterListPref(
87        prefs::kURLsToRestoreOnStartup,
88        user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
89    prefs_.registry()->RegisterListPref(
90        prefs::kURLsToRestoreOnStartupOld,
91        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
92    prefs_.registry()->RegisterLocalizedStringPref(
93        prefs::kDefaultCharset,
94        IDS_DEFAULT_ENCODING,
95        user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
96
97    pref_sync_service_ = reinterpret_cast<PrefModelAssociator*>(
98        prefs_.GetSyncableService(syncer::PREFERENCES));
99    ASSERT_TRUE(pref_sync_service_);
100    next_pref_remote_sync_node_id_ = 0;
101  }
102
103  syncer::SyncChange MakeRemoteChange(
104      int64 id,
105      const std::string& name,
106      const base::Value& value,
107      SyncChange::SyncChangeType type) {
108    std::string serialized;
109    JSONStringValueSerializer json(&serialized);
110    if (!json.Serialize(value))
111      return syncer::SyncChange();
112    sync_pb::EntitySpecifics entity;
113    sync_pb::PreferenceSpecifics* pref_one = entity.mutable_preference();
114    pref_one->set_name(name);
115    pref_one->set_value(serialized);
116    return syncer::SyncChange(
117        FROM_HERE,
118        type,
119        syncer::SyncData::CreateRemoteData(
120            id,
121            entity,
122            base::Time(),
123            syncer::AttachmentIdList(),
124            syncer::AttachmentServiceProxyForTest::Create()));
125  }
126
127  void AddToRemoteDataList(const std::string& name,
128                           const base::Value& value,
129                           syncer::SyncDataList* out) {
130    std::string serialized;
131    JSONStringValueSerializer json(&serialized);
132    ASSERT_TRUE(json.Serialize(value));
133    sync_pb::EntitySpecifics one;
134    sync_pb::PreferenceSpecifics* pref_one = one.mutable_preference();
135    pref_one->set_name(name);
136    pref_one->set_value(serialized);
137    out->push_back(SyncData::CreateRemoteData(
138        ++next_pref_remote_sync_node_id_,
139        one,
140        base::Time(),
141        syncer::AttachmentIdList(),
142        syncer::AttachmentServiceProxyForTest::Create()));
143  }
144
145  void InitWithSyncDataTakeOutput(const syncer::SyncDataList& initial_data,
146                                  syncer::SyncChangeList* output) {
147    test_processor_ = new TestSyncProcessorStub(output);
148    syncer::SyncMergeResult r = pref_sync_service_->MergeDataAndStartSyncing(
149        syncer::PREFERENCES, initial_data,
150        scoped_ptr<syncer::SyncChangeProcessor>(test_processor_),
151        scoped_ptr<syncer::SyncErrorFactory>(
152            new syncer::SyncErrorFactoryMock()));
153    EXPECT_FALSE(r.error().IsSet());
154  }
155
156  void InitWithNoSyncData() {
157    InitWithSyncDataTakeOutput(syncer::SyncDataList(), NULL);
158  }
159
160  const base::Value& GetPreferenceValue(const std::string& name) {
161    const PrefService::Preference* preference =
162        prefs_.FindPreference(name.c_str());
163    return *preference->GetValue();
164  }
165
166  scoped_ptr<base::Value> FindValue(const std::string& name,
167      const syncer::SyncChangeList& list) {
168    syncer::SyncChangeList::const_iterator it = list.begin();
169    for (; it != list.end(); ++it) {
170      if (syncer::SyncDataLocal(it->sync_data()).GetTag() == name) {
171        return make_scoped_ptr(base::JSONReader::Read(
172            it->sync_data().GetSpecifics().preference().value()));
173      }
174    }
175    return scoped_ptr<base::Value>();
176  }
177
178  bool IsSynced(const std::string& pref_name) {
179    return pref_sync_service_->registered_preferences().count(pref_name) > 0;
180  }
181
182  bool HasSyncData(const std::string& pref_name) {
183    return pref_sync_service_->IsPrefSynced(pref_name);
184  }
185
186  // Returns whether a given preference name is a new name of a migrated
187  // preference. Exposed here for testing.
188  static bool IsMigratedPreference(const char* preference_name) {
189    return PrefModelAssociator::IsMigratedPreference(preference_name);
190  }
191  static bool IsOldMigratedPreference(const char* old_preference_name) {
192    return PrefModelAssociator::IsOldMigratedPreference(old_preference_name);
193  }
194
195  PrefService* GetPrefs() { return &prefs_; }
196  TestingPrefServiceSyncable* GetTestingPrefService() { return &prefs_; }
197
198 protected:
199  TestingPrefServiceSyncable prefs_;
200
201  PrefModelAssociator* pref_sync_service_;
202  TestSyncProcessorStub* test_processor_;
203
204  // TODO(tim): Remove this by fixing AttachmentServiceProxyForTest.
205  base::MessageLoop loop_;
206
207  int next_pref_remote_sync_node_id_;
208};
209
210TEST_F(PrefsSyncableServiceTest, CreatePrefSyncData) {
211  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
212
213  const PrefService::Preference* pref =
214      prefs_.FindPreference(prefs::kHomePage);
215  syncer::SyncData sync_data;
216  EXPECT_TRUE(pref_sync_service_->CreatePrefSyncData(pref->name(),
217      *pref->GetValue(), &sync_data));
218  EXPECT_EQ(std::string(prefs::kHomePage),
219            syncer::SyncDataLocal(sync_data).GetTag());
220  const sync_pb::PreferenceSpecifics& specifics(sync_data.GetSpecifics().
221      preference());
222  EXPECT_EQ(std::string(prefs::kHomePage), specifics.name());
223
224  scoped_ptr<base::Value> value(base::JSONReader::Read(specifics.value()));
225  EXPECT_TRUE(pref->GetValue()->Equals(value.get()));
226}
227
228TEST_F(PrefsSyncableServiceTest, ModelAssociationDoNotSyncDefaults) {
229  const PrefService::Preference* pref =
230      prefs_.FindPreference(prefs::kHomePage);
231  EXPECT_TRUE(pref->IsDefaultValue());
232  syncer::SyncChangeList out;
233  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
234
235  EXPECT_TRUE(IsSynced(prefs::kHomePage));
236  EXPECT_TRUE(pref->IsDefaultValue());
237  EXPECT_FALSE(FindValue(prefs::kHomePage, out).get());
238}
239
240TEST_F(PrefsSyncableServiceTest, ModelAssociationEmptyCloud) {
241  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
242  {
243    ListPrefUpdate update(GetPrefs(), prefs::kURLsToRestoreOnStartup);
244    base::ListValue* url_list = update.Get();
245    url_list->Append(new base::StringValue(kExampleUrl0));
246    url_list->Append(new base::StringValue(kExampleUrl1));
247  }
248  syncer::SyncChangeList out;
249  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
250
251  scoped_ptr<base::Value> value(FindValue(prefs::kHomePage, out));
252  ASSERT_TRUE(value.get());
253  EXPECT_TRUE(GetPreferenceValue(prefs::kHomePage).Equals(value.get()));
254  value = FindValue(prefs::kURLsToRestoreOnStartup, out).Pass();
255  ASSERT_TRUE(value.get());
256  EXPECT_TRUE(
257      GetPreferenceValue(prefs::kURLsToRestoreOnStartup).Equals(value.get()));
258}
259
260TEST_F(PrefsSyncableServiceTest, ModelAssociationCloudHasData) {
261  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
262  {
263    ListPrefUpdate update(GetPrefs(), prefs::kURLsToRestoreOnStartup);
264    base::ListValue* url_list = update.Get();
265    url_list->Append(new base::StringValue(kExampleUrl0));
266    url_list->Append(new base::StringValue(kExampleUrl1));
267  }
268
269  syncer::SyncDataList in;
270  syncer::SyncChangeList out;
271  AddToRemoteDataList(prefs::kHomePage, base::StringValue(kExampleUrl1), &in);
272  base::ListValue urls_to_restore;
273  urls_to_restore.Append(new base::StringValue(kExampleUrl1));
274  urls_to_restore.Append(new base::StringValue(kExampleUrl2));
275  AddToRemoteDataList(prefs::kURLsToRestoreOnStartup, urls_to_restore, &in);
276  AddToRemoteDataList(prefs::kDefaultCharset,
277                      base::StringValue(kNonDefaultCharsetValue),
278                      &in);
279  InitWithSyncDataTakeOutput(in, &out);
280
281  ASSERT_FALSE(FindValue(prefs::kHomePage, out).get());
282  ASSERT_FALSE(FindValue(prefs::kDefaultCharset, out).get());
283
284  EXPECT_EQ(kExampleUrl1, prefs_.GetString(prefs::kHomePage));
285
286  scoped_ptr<base::ListValue> expected_urls(new base::ListValue);
287  expected_urls->Append(new base::StringValue(kExampleUrl1));
288  expected_urls->Append(new base::StringValue(kExampleUrl2));
289  expected_urls->Append(new base::StringValue(kExampleUrl0));
290  scoped_ptr<base::Value> value(
291      FindValue(prefs::kURLsToRestoreOnStartup, out));
292  ASSERT_TRUE(value.get());
293  EXPECT_TRUE(value->Equals(expected_urls.get()));
294  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
295              Equals(expected_urls.get()));
296  EXPECT_EQ(kNonDefaultCharsetValue,
297            prefs_.GetString(prefs::kDefaultCharset));
298}
299
300TEST_F(PrefsSyncableServiceTest, ModelAssociationMigrateOldData) {
301  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
302  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
303
304  syncer::SyncDataList in;
305  syncer::SyncChangeList out;
306  base::ListValue urls_to_restore;
307  urls_to_restore.Append(new base::StringValue(kExampleUrl1));
308  urls_to_restore.Append(new base::StringValue(kExampleUrl2));
309  AddToRemoteDataList(prefs::kURLsToRestoreOnStartupOld, urls_to_restore,
310                      &in);
311  InitWithSyncDataTakeOutput(in, &out);
312
313  // Expect that the new preference data contains the old pref's values.
314  scoped_ptr<base::ListValue> expected_urls(new base::ListValue);
315  expected_urls->Append(new base::StringValue(kExampleUrl1));
316  expected_urls->Append(new base::StringValue(kExampleUrl2));
317
318  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
319  scoped_ptr<base::Value> value(
320      FindValue(prefs::kURLsToRestoreOnStartup, out));
321  ASSERT_TRUE(value.get());
322  EXPECT_TRUE(value->Equals(expected_urls.get()));
323  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
324              Equals(expected_urls.get()));
325
326  // The old preference value should be the same.
327  expected_urls.reset(new base::ListValue);
328  ASSERT_FALSE(FindValue(prefs::kURLsToRestoreOnStartupOld, out).get());
329  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
330              Equals(expected_urls.get()));
331}
332
333TEST_F(PrefsSyncableServiceTest,
334       ModelAssociationCloudHasOldMigratedData) {
335  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
336  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
337  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
338  {
339    ListPrefUpdate update(GetPrefs(), prefs::kURLsToRestoreOnStartup);
340    base::ListValue* url_list = update.Get();
341    url_list->Append(new base::StringValue(kExampleUrl0));
342    url_list->Append(new base::StringValue(kExampleUrl1));
343  }
344
345  syncer::SyncDataList in;
346  syncer::SyncChangeList out;
347  base::ListValue urls_to_restore;
348  urls_to_restore.Append(new base::StringValue(kExampleUrl1));
349  urls_to_restore.Append(new base::StringValue(kExampleUrl2));
350  AddToRemoteDataList(prefs::kURLsToRestoreOnStartupOld, urls_to_restore, &in);
351  AddToRemoteDataList(prefs::kHomePage, base::StringValue(kExampleUrl1), &in);
352  InitWithSyncDataTakeOutput(in, &out);
353
354  ASSERT_FALSE(FindValue(prefs::kHomePage, out).get());
355
356  // Expect that the new preference data contains the merged old prefs values.
357  scoped_ptr<base::ListValue> expected_urls(new base::ListValue);
358  expected_urls->Append(new base::StringValue(kExampleUrl1));
359  expected_urls->Append(new base::StringValue(kExampleUrl2));
360  expected_urls->Append(new base::StringValue(kExampleUrl0));
361
362  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
363  scoped_ptr<base::Value> value(
364      FindValue(prefs::kURLsToRestoreOnStartup, out));
365  ASSERT_TRUE(value.get());
366  EXPECT_TRUE(value->Equals(expected_urls.get()));
367  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
368              Equals(expected_urls.get()));
369
370  expected_urls.reset(new base::ListValue);
371  value = FindValue(prefs::kURLsToRestoreOnStartupOld, out).Pass();
372  ASSERT_TRUE(value.get());
373  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
374              Equals(expected_urls.get()));
375}
376
377TEST_F(PrefsSyncableServiceTest,
378       ModelAssociationCloudHasNewMigratedData) {
379  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
380  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
381  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
382  {
383    ListPrefUpdate update(GetPrefs(), prefs::kURLsToRestoreOnStartupOld);
384    base::ListValue* url_list = update.Get();
385    url_list->Append(new base::StringValue(kExampleUrl0));
386    url_list->Append(new base::StringValue(kExampleUrl1));
387  }
388
389  syncer::SyncDataList in;
390  syncer::SyncChangeList out;
391  base::ListValue urls_to_restore;
392  urls_to_restore.Append(new base::StringValue(kExampleUrl1));
393  urls_to_restore.Append(new base::StringValue(kExampleUrl2));
394  AddToRemoteDataList(prefs::kURLsToRestoreOnStartupOld, urls_to_restore, &in);
395  AddToRemoteDataList(prefs::kHomePage, base::StringValue(kExampleUrl1), &in);
396  InitWithSyncDataTakeOutput(in, &out);
397
398  scoped_ptr<base::Value> value(FindValue(prefs::kHomePage, out));
399  ASSERT_FALSE(value.get());
400
401  // Expect that the cloud data under the new migrated preference name sticks.
402  scoped_ptr<base::ListValue> expected_urls(new base::ListValue);
403  expected_urls->Append(new base::StringValue(kExampleUrl1));
404  expected_urls->Append(new base::StringValue(kExampleUrl2));
405
406  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
407  value = FindValue(prefs::kURLsToRestoreOnStartup, out).Pass();
408  ASSERT_TRUE(value.get());
409  EXPECT_TRUE(value->Equals(expected_urls.get()));
410  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
411              Equals(expected_urls.get()));
412
413  // The old preference data should still be here, though not synced.
414  expected_urls.reset(new base::ListValue);
415  expected_urls->Append(new base::StringValue(kExampleUrl0));
416  expected_urls->Append(new base::StringValue(kExampleUrl1));
417
418  value = FindValue(prefs::kURLsToRestoreOnStartupOld, out).Pass();
419  ASSERT_FALSE(value.get());
420  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
421              Equals(expected_urls.get()));
422}
423
424TEST_F(PrefsSyncableServiceTest,
425       ModelAssociationCloudAddsOldAndNewMigratedData) {
426  ASSERT_TRUE(IsMigratedPreference(prefs::kURLsToRestoreOnStartup));
427  ASSERT_TRUE(IsOldMigratedPreference(prefs::kURLsToRestoreOnStartupOld));
428  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
429  {
430    ListPrefUpdate update_old(GetPrefs(), prefs::kURLsToRestoreOnStartupOld);
431    base::ListValue* url_list_old = update_old.Get();
432    url_list_old->Append(new base::StringValue(kExampleUrl0));
433    url_list_old->Append(new base::StringValue(kExampleUrl1));
434    ListPrefUpdate update(GetPrefs(), prefs::kURLsToRestoreOnStartup);
435    base::ListValue* url_list = update.Get();
436    url_list->Append(new base::StringValue(kExampleUrl1));
437    url_list->Append(new base::StringValue(kExampleUrl2));
438  }
439
440  syncer::SyncDataList in;
441  syncer::SyncChangeList out;
442  AddToRemoteDataList(prefs::kHomePage, base::StringValue(kExampleUrl1), &in);
443  InitWithSyncDataTakeOutput(in, &out);
444
445  scoped_ptr<base::Value> value(FindValue(prefs::kHomePage, out));
446  ASSERT_FALSE(value.get());
447
448  // Expect that the cloud data under the new migrated preference name sticks.
449  scoped_ptr<base::ListValue> expected_urls(new base::ListValue);
450  expected_urls->Append(new base::StringValue(kExampleUrl1));
451  expected_urls->Append(new base::StringValue(kExampleUrl2));
452
453  ASSERT_TRUE(HasSyncData(prefs::kURLsToRestoreOnStartup));
454  value = FindValue(prefs::kURLsToRestoreOnStartup, out).Pass();
455  ASSERT_TRUE(value.get());
456  EXPECT_TRUE(value->Equals(expected_urls.get()));
457  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
458              Equals(expected_urls.get()));
459
460  // Should not have synced in the old startup url values.
461  value = FindValue(prefs::kURLsToRestoreOnStartupOld, out).Pass();
462  ASSERT_FALSE(value.get());
463  EXPECT_FALSE(GetPreferenceValue(prefs::kURLsToRestoreOnStartupOld).
464               Equals(expected_urls.get()));
465}
466
467TEST_F(PrefsSyncableServiceTest, FailModelAssociation) {
468  syncer::SyncChangeList output;
469  TestSyncProcessorStub* stub = new TestSyncProcessorStub(&output);
470  stub->FailNextProcessSyncChanges();
471  syncer::SyncMergeResult r = pref_sync_service_->MergeDataAndStartSyncing(
472      syncer::PREFERENCES, syncer::SyncDataList(),
473      scoped_ptr<syncer::SyncChangeProcessor>(stub),
474      scoped_ptr<syncer::SyncErrorFactory>(
475          new syncer::SyncErrorFactoryMock()));
476  EXPECT_TRUE(r.error().IsSet());
477}
478
479TEST_F(PrefsSyncableServiceTest, UpdatedPreferenceWithDefaultValue) {
480  const PrefService::Preference* pref =
481      prefs_.FindPreference(prefs::kHomePage);
482  EXPECT_TRUE(pref->IsDefaultValue());
483
484  syncer::SyncChangeList out;
485  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
486  out.clear();
487
488  base::StringValue expected(kExampleUrl0);
489  GetPrefs()->Set(prefs::kHomePage, expected);
490
491  scoped_ptr<base::Value> actual(FindValue(prefs::kHomePage, out));
492  ASSERT_TRUE(actual.get());
493  EXPECT_TRUE(expected.Equals(actual.get()));
494}
495
496TEST_F(PrefsSyncableServiceTest, UpdatedPreferenceWithValue) {
497  GetPrefs()->SetString(prefs::kHomePage, kExampleUrl0);
498  syncer::SyncChangeList out;
499  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
500  out.clear();
501
502  base::StringValue expected(kExampleUrl1);
503  GetPrefs()->Set(prefs::kHomePage, expected);
504
505  scoped_ptr<base::Value> actual(FindValue(prefs::kHomePage, out));
506  ASSERT_TRUE(actual.get());
507  EXPECT_TRUE(expected.Equals(actual.get()));
508}
509
510TEST_F(PrefsSyncableServiceTest, UpdatedSyncNodeActionUpdate) {
511  GetPrefs()->SetString(prefs::kHomePage, kExampleUrl0);
512  InitWithNoSyncData();
513
514  base::StringValue expected(kExampleUrl1);
515  syncer::SyncChangeList list;
516  list.push_back(MakeRemoteChange(
517      1, prefs::kHomePage, expected, SyncChange::ACTION_UPDATE));
518  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
519
520  const base::Value& actual = GetPreferenceValue(prefs::kHomePage);
521  EXPECT_TRUE(expected.Equals(&actual));
522}
523
524TEST_F(PrefsSyncableServiceTest, UpdatedSyncNodeActionAdd) {
525  InitWithNoSyncData();
526
527  base::StringValue expected(kExampleUrl0);
528  syncer::SyncChangeList list;
529  list.push_back(MakeRemoteChange(
530      1, prefs::kHomePage, expected, SyncChange::ACTION_ADD));
531  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
532
533  const base::Value& actual = GetPreferenceValue(prefs::kHomePage);
534  EXPECT_TRUE(expected.Equals(&actual));
535  EXPECT_EQ(1U,
536      pref_sync_service_->registered_preferences().count(prefs::kHomePage));
537}
538
539TEST_F(PrefsSyncableServiceTest, UpdatedSyncNodeUnknownPreference) {
540  InitWithNoSyncData();
541  syncer::SyncChangeList list;
542  base::StringValue expected(kExampleUrl0);
543  list.push_back(MakeRemoteChange(
544      1, "unknown preference", expected, SyncChange::ACTION_UPDATE));
545  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
546  // Nothing interesting happens on the client when it gets an update
547  // of an unknown preference.  We just should not crash.
548}
549
550TEST_F(PrefsSyncableServiceTest, ManagedPreferences) {
551  // Make the homepage preference managed.
552  base::StringValue managed_value("http://example.com");
553  prefs_.SetManagedPref(prefs::kHomePage, managed_value.DeepCopy());
554
555  syncer::SyncChangeList out;
556  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
557  out.clear();
558
559  // Changing the homepage preference should not sync anything.
560  base::StringValue user_value("http://chromium..com");
561  prefs_.SetUserPref(prefs::kHomePage, user_value.DeepCopy());
562  EXPECT_TRUE(out.empty());
563
564  // An incoming sync transaction should change the user value, not the managed
565  // value.
566  base::StringValue sync_value("http://crbug.com");
567  syncer::SyncChangeList list;
568  list.push_back(MakeRemoteChange(
569      1, prefs::kHomePage, sync_value, SyncChange::ACTION_UPDATE));
570  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
571
572  EXPECT_TRUE(managed_value.Equals(prefs_.GetManagedPref(prefs::kHomePage)));
573  EXPECT_TRUE(sync_value.Equals(prefs_.GetUserPref(prefs::kHomePage)));
574}
575
576// List preferences have special handling at association time due to our ability
577// to merge the local and sync value. Make sure the merge logic doesn't merge
578// managed preferences.
579TEST_F(PrefsSyncableServiceTest, ManagedListPreferences) {
580  // Make the list of urls to restore on startup managed.
581  base::ListValue managed_value;
582  managed_value.Append(new base::StringValue(kExampleUrl0));
583  managed_value.Append(new base::StringValue(kExampleUrl1));
584  prefs_.SetManagedPref(prefs::kURLsToRestoreOnStartup,
585                         managed_value.DeepCopy());
586
587  // Set a cloud version.
588  syncer::SyncDataList in;
589  syncer::SyncChangeList out;
590  base::ListValue urls_to_restore;
591  urls_to_restore.Append(new base::StringValue(kExampleUrl1));
592  urls_to_restore.Append(new base::StringValue(kExampleUrl2));
593  AddToRemoteDataList(prefs::kURLsToRestoreOnStartup, urls_to_restore, &in);
594
595  // Start sync and verify the synced value didn't get merged.
596  InitWithSyncDataTakeOutput(in, &out);
597  EXPECT_FALSE(FindValue(prefs::kURLsToRestoreOnStartup, out).get());
598  out.clear();
599
600  // Changing the user's urls to restore on startup pref should not sync
601  // anything.
602  base::ListValue user_value;
603  user_value.Append(new base::StringValue("http://chromium.org"));
604  prefs_.SetUserPref(prefs::kURLsToRestoreOnStartup, user_value.DeepCopy());
605  EXPECT_FALSE(FindValue(prefs::kURLsToRestoreOnStartup, out).get());
606
607  // An incoming sync transaction should change the user value, not the managed
608  // value.
609  base::ListValue sync_value;
610  sync_value.Append(new base::StringValue("http://crbug.com"));
611  syncer::SyncChangeList list;
612  list.push_back(MakeRemoteChange(
613      1, prefs::kURLsToRestoreOnStartup, sync_value,
614      SyncChange::ACTION_UPDATE));
615  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
616
617  EXPECT_TRUE(managed_value.Equals(
618          prefs_.GetManagedPref(prefs::kURLsToRestoreOnStartup)));
619  EXPECT_TRUE(sync_value.Equals(
620          prefs_.GetUserPref(prefs::kURLsToRestoreOnStartup)));
621}
622
623TEST_F(PrefsSyncableServiceTest, DynamicManagedPreferences) {
624  syncer::SyncChangeList out;
625  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
626  out.clear();
627  base::StringValue initial_value("http://example.com/initial");
628  GetPrefs()->Set(prefs::kHomePage, initial_value);
629  scoped_ptr<base::Value> actual(FindValue(prefs::kHomePage, out));
630  ASSERT_TRUE(actual.get());
631  EXPECT_TRUE(initial_value.Equals(actual.get()));
632
633  // Switch kHomePage to managed and set a different value.
634  base::StringValue managed_value("http://example.com/managed");
635  GetTestingPrefService()->SetManagedPref(prefs::kHomePage,
636                                                    managed_value.DeepCopy());
637
638  // The pref value should be the one dictated by policy.
639  EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(prefs::kHomePage)));
640
641  // Switch kHomePage back to unmanaged.
642  GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
643
644  // The original value should be picked up.
645  EXPECT_TRUE(initial_value.Equals(&GetPreferenceValue(prefs::kHomePage)));
646}
647
648TEST_F(PrefsSyncableServiceTest,
649       DynamicManagedPreferencesWithSyncChange) {
650  syncer::SyncChangeList out;
651  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
652  out.clear();
653
654  base::StringValue initial_value("http://example.com/initial");
655  GetPrefs()->Set(prefs::kHomePage, initial_value);
656  scoped_ptr<base::Value> actual(FindValue(prefs::kHomePage, out));
657  EXPECT_TRUE(initial_value.Equals(actual.get()));
658
659  // Switch kHomePage to managed and set a different value.
660  base::StringValue managed_value("http://example.com/managed");
661  GetTestingPrefService()->SetManagedPref(prefs::kHomePage,
662                                                    managed_value.DeepCopy());
663
664  // Change the sync value.
665  base::StringValue sync_value("http://example.com/sync");
666  syncer::SyncChangeList list;
667  list.push_back(MakeRemoteChange(
668      1, prefs::kHomePage, sync_value, SyncChange::ACTION_UPDATE));
669  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
670
671  // The pref value should still be the one dictated by policy.
672  EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(prefs::kHomePage)));
673
674  // Switch kHomePage back to unmanaged.
675  GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
676
677  // Sync value should be picked up.
678  EXPECT_TRUE(sync_value.Equals(&GetPreferenceValue(prefs::kHomePage)));
679}
680
681TEST_F(PrefsSyncableServiceTest, DynamicManagedDefaultPreferences) {
682  const PrefService::Preference* pref =
683      prefs_.FindPreference(prefs::kHomePage);
684  EXPECT_TRUE(pref->IsDefaultValue());
685  syncer::SyncChangeList out;
686  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
687
688  EXPECT_TRUE(IsSynced(prefs::kHomePage));
689  EXPECT_TRUE(pref->IsDefaultValue());
690  EXPECT_FALSE(FindValue(prefs::kHomePage, out).get());
691  out.clear();
692
693  // Switch kHomePage to managed and set a different value.
694  base::StringValue managed_value("http://example.com/managed");
695  GetTestingPrefService()->SetManagedPref(prefs::kHomePage,
696                                          managed_value.DeepCopy());
697  // The pref value should be the one dictated by policy.
698  EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(prefs::kHomePage)));
699  EXPECT_FALSE(pref->IsDefaultValue());
700  // There should be no synced value.
701  EXPECT_FALSE(FindValue(prefs::kHomePage, out).get());
702  // Switch kHomePage back to unmanaged.
703  GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
704  // The original value should be picked up.
705  EXPECT_TRUE(pref->IsDefaultValue());
706  // There should still be no synced value.
707  EXPECT_FALSE(FindValue(prefs::kHomePage, out).get());
708}
709
710TEST_F(PrefsSyncableServiceTest, DeletePreference) {
711  prefs_.SetString(prefs::kHomePage, kExampleUrl0);
712  const PrefService::Preference* pref =
713      prefs_.FindPreference(prefs::kHomePage);
714  EXPECT_FALSE(pref->IsDefaultValue());
715
716  InitWithNoSyncData();
717
718  scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
719  syncer::SyncChangeList list;
720  list.push_back(MakeRemoteChange(
721      1, prefs::kHomePage, *null_value, SyncChange::ACTION_DELETE));
722  pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
723  EXPECT_TRUE(pref->IsDefaultValue());
724}
725