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 <map>
6#include <string>
7
8#include "base/bind.h"
9#include "base/bind_helpers.h"
10#include "base/callback.h"
11#include "base/json/json_reader.h"
12#include "base/json/json_string_value_serializer.h"
13#include "base/location.h"
14#include "base/stl_util.h"
15#include "base/strings/string_piece.h"
16#include "chrome/browser/invalidation/invalidation_service_factory.h"
17#include "chrome/browser/prefs/pref_model_associator.h"
18#include "chrome/browser/prefs/scoped_user_pref_update.h"
19#include "chrome/browser/signin/signin_manager.h"
20#include "chrome/browser/signin/signin_manager_factory.h"
21#include "chrome/browser/signin/token_service_factory.h"
22#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
23#include "chrome/browser/sync/glue/generic_change_processor.h"
24#include "chrome/browser/sync/glue/sync_backend_host.h"
25#include "chrome/browser/sync/glue/ui_data_type_controller.h"
26#include "chrome/browser/sync/profile_sync_service_factory.h"
27#include "chrome/browser/sync/profile_sync_test_util.h"
28#include "chrome/browser/sync/test_profile_sync_service.h"
29#include "chrome/common/pref_names.h"
30#include "chrome/test/base/testing_pref_service_syncable.h"
31#include "chrome/test/base/testing_profile.h"
32#include "components/user_prefs/pref_registry_syncable.h"
33#include "google_apis/gaia/gaia_constants.h"
34#include "sync/api/sync_data.h"
35#include "sync/internal_api/public/base/model_type.h"
36#include "sync/internal_api/public/change_record.h"
37#include "sync/internal_api/public/data_type_debug_info_listener.h"
38#include "sync/internal_api/public/read_node.h"
39#include "sync/internal_api/public/read_transaction.h"
40#include "sync/internal_api/public/write_node.h"
41#include "sync/internal_api/public/write_transaction.h"
42#include "sync/protocol/preference_specifics.pb.h"
43#include "testing/gmock/include/gmock/gmock.h"
44#include "testing/gtest/include/gtest/gtest.h"
45
46using base::JSONReader;
47using browser_sync::GenericChangeProcessor;
48using browser_sync::SharedChangeProcessor;
49using browser_sync::UIDataTypeController;
50using syncer::ChangeRecord;
51using testing::_;
52using testing::Invoke;
53using testing::Return;
54
55typedef std::map<const std::string, const Value*> PreferenceValues;
56
57ACTION_P(CreateAndSaveChangeProcessor, change_processor) {
58  syncer::UserShare* user_share = arg0->GetUserShare();
59  *change_processor = new GenericChangeProcessor(arg1,
60                                                 arg2,
61                                                 arg3,
62                                                 user_share);
63  return *change_processor;
64}
65
66ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) {
67  return new browser_sync::DataTypeManagerImpl(
68      debug_listener,
69      arg1,
70      arg2,
71      arg3,
72      arg4,
73      arg5);
74}
75
76// TODO(zea): Refactor to remove the ProfileSyncService usage.
77class ProfileSyncServicePreferenceTest
78    : public AbstractProfileSyncServiceTest,
79      public syncer::DataTypeDebugInfoListener {
80 public:
81  int64 SetSyncedValue(const std::string& name, const Value& value) {
82    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
83    syncer::ReadNode root(&trans);
84    if (root.InitByTagLookup(syncer::ModelTypeToRootTag(
85            syncer::PREFERENCES)) != syncer::BaseNode::INIT_OK) {
86      return syncer::kInvalidId;
87    }
88
89    syncer::WriteNode tag_node(&trans);
90    syncer::WriteNode node(&trans);
91
92    if (tag_node.InitByClientTagLookup(syncer::PREFERENCES, name) ==
93            syncer::BaseNode::INIT_OK) {
94      return WriteSyncedValue(name, value, &tag_node);
95    }
96
97    syncer::WriteNode::InitUniqueByCreationResult result =
98        node.InitUniqueByCreation(syncer::PREFERENCES, root, name);
99    if (result == syncer::WriteNode::INIT_SUCCESS)
100      return WriteSyncedValue(name, value, &node);
101
102    return syncer::kInvalidId;
103  }
104
105  // DataTypeDebugInfoListener implementation.
106  virtual void OnSingleDataTypeConfigureComplete(
107      const syncer::DataTypeConfigurationStats& configuration_stats) OVERRIDE {
108    association_stats_ = configuration_stats.association_stats;
109  }
110  virtual void OnConfigureComplete() OVERRIDE {
111    // Do nothing.
112  }
113
114 protected:
115  ProfileSyncServicePreferenceTest()
116      : debug_ptr_factory_(this),
117        example_url0_("http://example.com/0"),
118        example_url1_("http://example.com/1"),
119        example_url2_("http://example.com/2"),
120        not_synced_preference_name_("nonsense_pref_name"),
121        not_synced_preference_default_value_("default"),
122        non_default_charset_value_("foo") {}
123
124  virtual void SetUp() {
125    AbstractProfileSyncServiceTest::SetUp();
126    profile_.reset(new TestingProfile());
127    invalidation::InvalidationServiceFactory::GetInstance()->
128        SetBuildOnlyFakeInvalidatorsForTest(true);
129    prefs_ = profile_->GetTestingPrefService();
130
131    prefs_->registry()->RegisterStringPref(
132        not_synced_preference_name_.c_str(),
133        not_synced_preference_default_value_,
134        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
135  }
136
137  virtual void TearDown() {
138    profile_.reset();
139    AbstractProfileSyncServiceTest::TearDown();
140  }
141
142  int GetSyncPreferenceCount() {
143    syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
144    syncer::ReadNode node(&trans);
145    if (node.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::PREFERENCES)) !=
146        syncer::BaseNode::INIT_OK)
147      return 0;
148    return node.GetTotalNodeCount() - 1;
149  }
150
151  bool StartSyncService(const base::Closure& callback,
152                        bool will_fail_association) {
153    if (sync_service_)
154      return false;
155
156    SigninManagerBase* signin =
157         SigninManagerFactory::GetForProfile(profile_.get());
158    signin->SetAuthenticatedUsername("test");
159    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
160        profile_.get(), FakeOAuth2TokenService::BuildTokenService);
161    sync_service_ = static_cast<TestProfileSyncService*>(
162        ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
163            profile_.get(), &TestProfileSyncService::BuildAutoStartAsyncInit));
164    sync_service_->set_backend_init_callback(callback);
165    pref_sync_service_ = reinterpret_cast<PrefModelAssociator*>(
166        prefs_->GetSyncableService(syncer::PREFERENCES));
167    if (!pref_sync_service_)
168      return false;
169    ProfileSyncComponentsFactoryMock* components =
170        sync_service_->components_factory_mock();
171    EXPECT_CALL(*components, GetSyncableServiceForType(syncer::PREFERENCES)).
172        WillOnce(Return(pref_sync_service_->AsWeakPtr()));
173
174    EXPECT_CALL(*components, CreateDataTypeManager(_, _, _, _, _, _)).
175        WillOnce(ReturnNewDataTypeManagerWithDebugListener(
176                     syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr())));
177    dtc_ = new UIDataTypeController(syncer::PREFERENCES,
178                                    components,
179                                    profile_.get(),
180                                    sync_service_);
181    EXPECT_CALL(*components, CreateSharedChangeProcessor()).
182        WillOnce(Return(new SharedChangeProcessor()));
183    EXPECT_CALL(*components, CreateGenericChangeProcessor(_, _, _, _)).
184        WillOnce(CreateAndSaveChangeProcessor(
185                     &change_processor_));
186    sync_service_->RegisterDataTypeController(dtc_);
187    TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
188        GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth2_login_token");
189    TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
190        GaiaConstants::kSyncService, "token");
191
192    sync_service_->Initialize();
193    base::MessageLoop::current()->Run();
194
195    // It's possible this test triggered an unrecoverable error, in which case
196    // we can't get the preference count.
197    if (sync_service_->ShouldPushChanges()) {
198        EXPECT_EQ(GetSyncPreferenceCount(),
199                  association_stats_.num_sync_items_after_association);
200    }
201    EXPECT_EQ(association_stats_.num_sync_items_after_association,
202              association_stats_.num_sync_items_before_association +
203              association_stats_.num_sync_items_added -
204              association_stats_.num_sync_items_deleted);
205
206    return true;
207  }
208
209  const Value& GetPreferenceValue(const std::string& name) {
210    const PrefService::Preference* preference =
211        prefs_->FindPreference(name.c_str());
212    return *preference->GetValue();
213  }
214
215  // Caller gets ownership of the returned value.
216  const Value* GetSyncedValue(const std::string& name) {
217    syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
218    syncer::ReadNode node(&trans);
219
220    if (node.InitByClientTagLookup(syncer::PREFERENCES, name) !=
221            syncer::BaseNode::INIT_OK) {
222      return NULL;
223    }
224
225    const sync_pb::PreferenceSpecifics& specifics(
226        node.GetEntitySpecifics().preference());
227
228    return base::JSONReader::Read(specifics.value());
229  }
230
231  int64 WriteSyncedValue(const std::string& name,
232                         const Value& value,
233                         syncer::WriteNode* node) {
234    syncer::SyncData sync_data;
235    if (!pref_sync_service_->CreatePrefSyncData(name,
236                                                value,
237                                                &sync_data)) {
238      return syncer::kInvalidId;
239    }
240    node->SetEntitySpecifics(sync_data.GetSpecifics());
241    return node->GetId();
242  }
243
244  bool IsSynced(const std::string& pref_name) {
245    return pref_sync_service_->registered_preferences().count(pref_name) > 0;
246  }
247
248  std::string ValueString(const Value& value) {
249    std::string serialized;
250    JSONStringValueSerializer json(&serialized);
251    json.Serialize(value);
252    return serialized;
253  }
254
255  scoped_ptr<TestingProfile> profile_;
256  TestingPrefServiceSyncable* prefs_;
257
258  UIDataTypeController* dtc_;
259  PrefModelAssociator* pref_sync_service_;
260  GenericChangeProcessor* change_processor_;
261  syncer::DataTypeAssociationStats association_stats_;
262  base::WeakPtrFactory<DataTypeDebugInfoListener> debug_ptr_factory_;
263
264  std::string example_url0_;
265  std::string example_url1_;
266  std::string example_url2_;
267  std::string not_synced_preference_name_;
268  std::string not_synced_preference_default_value_;
269  std::string non_default_charset_value_;
270};
271
272class AddPreferenceEntriesHelper {
273 public:
274  AddPreferenceEntriesHelper(ProfileSyncServicePreferenceTest* test,
275                             const PreferenceValues& entries)
276      : callback_(base::Bind(
277            &AddPreferenceEntriesHelper::AddPreferenceEntriesCallback,
278            base::Unretained(this), test, entries)),
279        success_(false) {
280  }
281
282  const base::Closure& callback() const { return callback_; }
283  bool success() { return success_; }
284
285 private:
286  void AddPreferenceEntriesCallback(ProfileSyncServicePreferenceTest* test,
287                                    const PreferenceValues& entries) {
288    if (!test->CreateRoot(syncer::PREFERENCES))
289      return;
290
291    for (PreferenceValues::const_iterator i = entries.begin();
292         i != entries.end(); ++i) {
293      if (test->SetSyncedValue(i->first, *i->second) == syncer::kInvalidId)
294        return;
295    }
296    success_ = true;
297  }
298
299  base::Closure callback_;
300  bool success_;
301};
302
303TEST_F(ProfileSyncServicePreferenceTest, CreatePrefSyncData) {
304  prefs_->SetString(prefs::kHomePage, example_url0_);
305  CreateRootHelper create_root(this, syncer::PREFERENCES);
306  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
307  ASSERT_TRUE(create_root.success());
308
309  const PrefService::Preference* pref =
310      prefs_->FindPreference(prefs::kHomePage);
311  syncer::SyncData sync_data;
312  EXPECT_TRUE(pref_sync_service_->CreatePrefSyncData(pref->name(),
313      *pref->GetValue(), &sync_data));
314  EXPECT_EQ(std::string(prefs::kHomePage), sync_data.GetTag());
315  const sync_pb::PreferenceSpecifics& specifics(sync_data.GetSpecifics().
316      preference());
317  EXPECT_EQ(std::string(prefs::kHomePage), specifics.name());
318
319  scoped_ptr<Value> value(base::JSONReader::Read(specifics.value()));
320  EXPECT_TRUE(pref->GetValue()->Equals(value.get()));
321}
322
323TEST_F(ProfileSyncServicePreferenceTest, ModelAssociationDoNotSyncDefaults) {
324  const PrefService::Preference* pref =
325      prefs_->FindPreference(prefs::kHomePage);
326  EXPECT_TRUE(pref->IsDefaultValue());
327  CreateRootHelper create_root(this, syncer::PREFERENCES);
328  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
329  ASSERT_TRUE(create_root.success());
330  EXPECT_TRUE(IsSynced(prefs::kHomePage));
331  EXPECT_TRUE(pref->IsDefaultValue());
332  EXPECT_TRUE(GetSyncedValue(prefs::kHomePage) == NULL);
333  EXPECT_TRUE(GetSyncedValue(not_synced_preference_name_) == NULL);
334}
335
336TEST_F(ProfileSyncServicePreferenceTest, ModelAssociationEmptyCloud) {
337  prefs_->SetString(prefs::kHomePage, example_url0_);
338  {
339    ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartup);
340    ListValue* url_list = update.Get();
341    url_list->Append(Value::CreateStringValue(example_url0_));
342    url_list->Append(Value::CreateStringValue(example_url1_));
343  }
344  CreateRootHelper create_root(this, syncer::PREFERENCES);
345  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
346  ASSERT_TRUE(create_root.success());
347
348  scoped_ptr<const Value> value(GetSyncedValue(prefs::kHomePage));
349  ASSERT_TRUE(value.get());
350  EXPECT_TRUE(GetPreferenceValue(prefs::kHomePage).Equals(value.get()));
351  value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
352  ASSERT_TRUE(value.get());
353  EXPECT_TRUE(
354      GetPreferenceValue(prefs::kURLsToRestoreOnStartup).Equals(value.get()));
355}
356
357TEST_F(ProfileSyncServicePreferenceTest, ModelAssociationCloudHasData) {
358  prefs_->SetString(prefs::kHomePage, example_url0_);
359  {
360    ListPrefUpdate update(prefs_, prefs::kURLsToRestoreOnStartup);
361    ListValue* url_list = update.Get();
362    url_list->Append(Value::CreateStringValue(example_url0_));
363    url_list->Append(Value::CreateStringValue(example_url1_));
364  }
365
366  PreferenceValues cloud_data;
367  cloud_data[prefs::kHomePage] = Value::CreateStringValue(example_url1_);
368  ListValue* urls_to_restore = new ListValue;
369  urls_to_restore->Append(Value::CreateStringValue(example_url1_));
370  urls_to_restore->Append(Value::CreateStringValue(example_url2_));
371  cloud_data[prefs::kURLsToRestoreOnStartup] = urls_to_restore;
372  cloud_data[prefs::kDefaultCharset] =
373      Value::CreateStringValue(non_default_charset_value_);
374
375  AddPreferenceEntriesHelper helper(this, cloud_data);
376  ASSERT_TRUE(StartSyncService(helper.callback(), false));
377  ASSERT_TRUE(helper.success());
378
379  scoped_ptr<const Value> value(GetSyncedValue(prefs::kHomePage));
380  ASSERT_TRUE(value.get());
381  std::string string_value;
382  EXPECT_TRUE(value->GetAsString(&string_value));
383  EXPECT_EQ(example_url1_, string_value);
384  EXPECT_EQ(example_url1_, prefs_->GetString(prefs::kHomePage));
385
386  scoped_ptr<ListValue> expected_urls(new ListValue);
387  expected_urls->Append(Value::CreateStringValue(example_url1_));
388  expected_urls->Append(Value::CreateStringValue(example_url2_));
389  expected_urls->Append(Value::CreateStringValue(example_url0_));
390  value.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
391  ASSERT_TRUE(value.get());
392  EXPECT_TRUE(value->Equals(expected_urls.get()));
393  EXPECT_TRUE(GetPreferenceValue(prefs::kURLsToRestoreOnStartup).
394              Equals(expected_urls.get()));
395
396  value.reset(GetSyncedValue(prefs::kDefaultCharset));
397  ASSERT_TRUE(value.get());
398  EXPECT_TRUE(value->GetAsString(&string_value));
399  EXPECT_EQ(non_default_charset_value_, string_value);
400  EXPECT_EQ(non_default_charset_value_,
401            prefs_->GetString(prefs::kDefaultCharset));
402  STLDeleteValues(&cloud_data);
403}
404
405TEST_F(ProfileSyncServicePreferenceTest, FailModelAssociation) {
406  ASSERT_TRUE(StartSyncService(base::Closure(), true));
407  EXPECT_TRUE(sync_service_->HasUnrecoverableError());
408}
409
410TEST_F(ProfileSyncServicePreferenceTest, UpdatedPreferenceWithDefaultValue) {
411  const PrefService::Preference* pref =
412      prefs_->FindPreference(prefs::kHomePage);
413  EXPECT_TRUE(pref->IsDefaultValue());
414
415  CreateRootHelper create_root(this, syncer::PREFERENCES);
416  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
417  ASSERT_TRUE(create_root.success());
418
419  scoped_ptr<Value> expected(Value::CreateStringValue(example_url0_));
420  profile_->GetPrefs()->Set(prefs::kHomePage, *expected);
421
422  scoped_ptr<const Value> actual(GetSyncedValue(prefs::kHomePage));
423  ASSERT_TRUE(actual.get());
424  EXPECT_TRUE(expected->Equals(actual.get()));
425}
426
427TEST_F(ProfileSyncServicePreferenceTest, UpdatedPreferenceWithValue) {
428  profile_->GetPrefs()->SetString(prefs::kHomePage, example_url0_);
429  CreateRootHelper create_root(this, syncer::PREFERENCES);
430  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
431  ASSERT_TRUE(create_root.success());
432
433  scoped_ptr<Value> expected(Value::CreateStringValue(example_url1_));
434  profile_->GetPrefs()->Set(prefs::kHomePage, *expected);
435
436  scoped_ptr<const Value> actual(GetSyncedValue(prefs::kHomePage));
437  ASSERT_TRUE(actual.get());
438  EXPECT_TRUE(expected->Equals(actual.get()));
439}
440
441TEST_F(ProfileSyncServicePreferenceTest, UpdatedSyncNodeActionUpdate) {
442  profile_->GetPrefs()->SetString(prefs::kHomePage, example_url0_);
443  CreateRootHelper create_root(this, syncer::PREFERENCES);
444  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
445  ASSERT_TRUE(create_root.success());
446
447  scoped_ptr<Value> expected(Value::CreateStringValue(example_url1_));
448  int64 node_id = SetSyncedValue(prefs::kHomePage, *expected);
449  ASSERT_NE(node_id, syncer::kInvalidId);
450  {
451    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
452    change_processor_->ApplyChangesFromSyncModel(
453        &trans, 0,
454        ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
455            node_id, ChangeRecord::ACTION_UPDATE));
456  }
457  change_processor_->CommitChangesFromSyncModel();
458
459  const Value& actual = GetPreferenceValue(prefs::kHomePage);
460  EXPECT_TRUE(expected->Equals(&actual));
461}
462
463TEST_F(ProfileSyncServicePreferenceTest, UpdatedSyncNodeActionAdd) {
464  CreateRootHelper create_root(this, syncer::PREFERENCES);
465  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
466  ASSERT_TRUE(create_root.success());
467
468  scoped_ptr<Value> expected(Value::CreateStringValue(example_url0_));
469  int64 node_id = SetSyncedValue(prefs::kHomePage, *expected);
470  ASSERT_NE(node_id, syncer::kInvalidId);
471  {
472    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
473    change_processor_->ApplyChangesFromSyncModel(
474        &trans, 0,
475        ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
476            node_id, ChangeRecord::ACTION_ADD));
477  }
478  change_processor_->CommitChangesFromSyncModel();
479
480  const Value& actual = GetPreferenceValue(prefs::kHomePage);
481  EXPECT_TRUE(expected->Equals(&actual));
482  EXPECT_EQ(1U,
483      pref_sync_service_->registered_preferences().count(prefs::kHomePage));
484}
485
486TEST_F(ProfileSyncServicePreferenceTest, UpdatedSyncNodeUnknownPreference) {
487  CreateRootHelper create_root(this, syncer::PREFERENCES);
488  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
489  ASSERT_TRUE(create_root.success());
490
491  scoped_ptr<Value> expected(Value::CreateStringValue(example_url0_));
492  int64 node_id = SetSyncedValue("unknown preference", *expected);
493  ASSERT_NE(node_id, syncer::kInvalidId);
494  {
495    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
496    change_processor_->ApplyChangesFromSyncModel(
497        &trans, 0,
498        ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
499            node_id, ChangeRecord::ACTION_UPDATE));
500  }
501  change_processor_->CommitChangesFromSyncModel();
502
503  // Nothing interesting happens on the client when it gets an update
504  // of an unknown preference.  We just should not crash.
505}
506
507TEST_F(ProfileSyncServicePreferenceTest, ManagedPreferences) {
508  // Make the homepage preference managed.
509  scoped_ptr<Value> managed_value(
510      Value::CreateStringValue("http://example.com"));
511  prefs_->SetManagedPref(prefs::kHomePage, managed_value->DeepCopy());
512
513  CreateRootHelper create_root(this, syncer::PREFERENCES);
514  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
515  ASSERT_TRUE(create_root.success());
516
517  // Changing the homepage preference should not sync anything.
518  scoped_ptr<Value> user_value(
519      Value::CreateStringValue("http://chromium..com"));
520  prefs_->SetUserPref(prefs::kHomePage, user_value->DeepCopy());
521  EXPECT_EQ(NULL, GetSyncedValue(prefs::kHomePage));
522
523  // An incoming sync transaction should change the user value, not the managed
524  // value.
525  scoped_ptr<Value> sync_value(
526      Value::CreateStringValue("http://crbug.com"));
527  int64 node_id = SetSyncedValue(prefs::kHomePage, *sync_value);
528  ASSERT_NE(node_id, syncer::kInvalidId);
529  {
530    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
531    change_processor_->ApplyChangesFromSyncModel(
532        &trans, 0,
533        ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
534            node_id, ChangeRecord::ACTION_UPDATE));
535  }
536  change_processor_->CommitChangesFromSyncModel();
537
538  EXPECT_TRUE(managed_value->Equals(prefs_->GetManagedPref(prefs::kHomePage)));
539  EXPECT_TRUE(sync_value->Equals(prefs_->GetUserPref(prefs::kHomePage)));
540}
541
542// List preferences have special handling at association time due to our ability
543// to merge the local and sync value. Make sure the merge logic doesn't merge
544// managed preferences.
545TEST_F(ProfileSyncServicePreferenceTest, ManagedListPreferences) {
546  // Make the list of urls to restore on startup managed.
547  ListValue managed_value;
548  managed_value.Append(Value::CreateStringValue(example_url0_));
549  managed_value.Append(Value::CreateStringValue(example_url1_));
550  prefs_->SetManagedPref(prefs::kURLsToRestoreOnStartup,
551                         managed_value.DeepCopy());
552
553  // Set a cloud version.
554  PreferenceValues cloud_data;
555  scoped_ptr<ListValue> urls_to_restore(new ListValue);
556  urls_to_restore->Append(Value::CreateStringValue(example_url1_));
557  urls_to_restore->Append(Value::CreateStringValue(example_url2_));
558  cloud_data[prefs::kURLsToRestoreOnStartup] = urls_to_restore.get();
559
560  // Start sync and verify the synced value didn't get merged.
561  AddPreferenceEntriesHelper helper(this, cloud_data);
562  ASSERT_TRUE(StartSyncService(helper.callback(), false));
563  ASSERT_TRUE(helper.success());
564  scoped_ptr<const Value> actual(
565      GetSyncedValue(prefs::kURLsToRestoreOnStartup));
566  EXPECT_TRUE(cloud_data[prefs::kURLsToRestoreOnStartup]->Equals(actual.get()));
567
568  // Changing the user's urls to restore on startup pref should not sync
569  // anything.
570  ListValue user_value;
571  user_value.Append(Value::CreateStringValue("http://chromium.org"));
572  prefs_->SetUserPref(prefs::kURLsToRestoreOnStartup, user_value.DeepCopy());
573  actual.reset(GetSyncedValue(prefs::kURLsToRestoreOnStartup));
574  EXPECT_TRUE(cloud_data[prefs::kURLsToRestoreOnStartup]->Equals(actual.get()));
575
576  // An incoming sync transaction should change the user value, not the managed
577  // value.
578  ListValue sync_value;
579  sync_value.Append(Value::CreateStringValue("http://crbug.com"));
580  int64 node_id = SetSyncedValue(prefs::kURLsToRestoreOnStartup, sync_value);
581  ASSERT_NE(node_id, syncer::kInvalidId);
582  {
583    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
584    change_processor_->ApplyChangesFromSyncModel(
585        &trans, 0,
586        ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
587            node_id, ChangeRecord::ACTION_UPDATE));
588  }
589  change_processor_->CommitChangesFromSyncModel();
590
591  EXPECT_TRUE(managed_value.Equals(
592          prefs_->GetManagedPref(prefs::kURLsToRestoreOnStartup)));
593  EXPECT_TRUE(sync_value.Equals(
594          prefs_->GetUserPref(prefs::kURLsToRestoreOnStartup)));
595}
596
597TEST_F(ProfileSyncServicePreferenceTest, DynamicManagedPreferences) {
598  CreateRootHelper create_root(this, syncer::PREFERENCES);
599  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
600  ASSERT_TRUE(create_root.success());
601
602  scoped_ptr<Value> initial_value(
603      Value::CreateStringValue("http://example.com/initial"));
604  profile_->GetPrefs()->Set(prefs::kHomePage, *initial_value);
605  scoped_ptr<const Value> actual(GetSyncedValue(prefs::kHomePage));
606  ASSERT_TRUE(actual.get());
607  EXPECT_TRUE(initial_value->Equals(actual.get()));
608
609  // Switch kHomePage to managed and set a different value.
610  scoped_ptr<Value> managed_value(
611      Value::CreateStringValue("http://example.com/managed"));
612  profile_->GetTestingPrefService()->SetManagedPref(
613      prefs::kHomePage, managed_value->DeepCopy());
614
615  // The pref value should be the one dictated by policy.
616  EXPECT_TRUE(managed_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
617
618  // Switch kHomePage back to unmanaged.
619  profile_->GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
620
621  // The original value should be picked up.
622  EXPECT_TRUE(initial_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
623}
624
625TEST_F(ProfileSyncServicePreferenceTest,
626       DynamicManagedPreferencesWithSyncChange) {
627  CreateRootHelper create_root(this, syncer::PREFERENCES);
628  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
629  ASSERT_TRUE(create_root.success());
630
631  scoped_ptr<Value> initial_value(
632      Value::CreateStringValue("http://example.com/initial"));
633  profile_->GetPrefs()->Set(prefs::kHomePage, *initial_value);
634  scoped_ptr<const Value> actual(GetSyncedValue(prefs::kHomePage));
635  EXPECT_TRUE(initial_value->Equals(actual.get()));
636
637  // Switch kHomePage to managed and set a different value.
638  scoped_ptr<Value> managed_value(
639      Value::CreateStringValue("http://example.com/managed"));
640  profile_->GetTestingPrefService()->SetManagedPref(
641      prefs::kHomePage, managed_value->DeepCopy());
642
643  // Change the sync value.
644  scoped_ptr<Value> sync_value(
645      Value::CreateStringValue("http://example.com/sync"));
646  int64 node_id = SetSyncedValue(prefs::kHomePage, *sync_value);
647  ASSERT_NE(node_id, syncer::kInvalidId);
648  {
649    syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
650    change_processor_->ApplyChangesFromSyncModel(
651        &trans, 0,
652        ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
653            node_id, ChangeRecord::ACTION_ADD));
654  }
655  change_processor_->CommitChangesFromSyncModel();
656
657  // The pref value should still be the one dictated by policy.
658  EXPECT_TRUE(managed_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
659
660  // Switch kHomePage back to unmanaged.
661  profile_->GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
662
663  // Sync value should be picked up.
664  EXPECT_TRUE(sync_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
665}
666
667TEST_F(ProfileSyncServicePreferenceTest, DynamicManagedDefaultPreferences) {
668  const PrefService::Preference* pref =
669      prefs_->FindPreference(prefs::kHomePage);
670  EXPECT_TRUE(pref->IsDefaultValue());
671  CreateRootHelper create_root(this, syncer::PREFERENCES);
672  ASSERT_TRUE(StartSyncService(create_root.callback(), false));
673  ASSERT_TRUE(create_root.success());
674  EXPECT_TRUE(IsSynced(prefs::kHomePage));
675  EXPECT_TRUE(pref->IsDefaultValue());
676  EXPECT_TRUE(GetSyncedValue(prefs::kHomePage) == NULL);
677  // Switch kHomePage to managed and set a different value.
678  scoped_ptr<Value> managed_value(
679      Value::CreateStringValue("http://example.com/managed"));
680  profile_->GetTestingPrefService()->SetManagedPref(
681      prefs::kHomePage, managed_value->DeepCopy());
682  // The pref value should be the one dictated by policy.
683  EXPECT_TRUE(managed_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
684  EXPECT_FALSE(pref->IsDefaultValue());
685  // There should be no synced value.
686  EXPECT_TRUE(GetSyncedValue(prefs::kHomePage) == NULL);
687  // Switch kHomePage back to unmanaged.
688  profile_->GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
689  // The original value should be picked up.
690  EXPECT_TRUE(pref->IsDefaultValue());
691  // There should still be no synced value.
692  EXPECT_TRUE(GetSyncedValue(prefs::kHomePage) == NULL);
693}
694