1// Copyright 2013 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 <string>
6
7#include "base/json/json_string_value_serializer.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/time/time.h"
10#include "base/values.h"
11#include "chrome/browser/prefs/synced_pref_change_registrar.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/common/pref_names.h"
14#include "chrome/test/base/in_process_browser_test.h"
15#include "chrome/test/base/testing_pref_service_syncable.h"
16#include "chrome/test/base/testing_profile.h"
17#include "content/public/test/test_utils.h"
18#include "sync/api/attachments/attachment_id.h"
19#include "sync/api/fake_sync_change_processor.h"
20#include "sync/api/sync_change.h"
21#include "sync/api/sync_error_factory.h"
22#include "sync/api/sync_error_factory_mock.h"
23#include "sync/api/syncable_service.h"
24#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
25#include "sync/protocol/sync.pb.h"
26
27#if defined(ENABLE_CONFIGURATION_POLICY)
28#include "components/policy/core/browser/browser_policy_connector.h"
29#include "components/policy/core/common/mock_configuration_policy_provider.h"
30#include "components/policy/core/common/policy_map.h"
31#include "policy/policy_constants.h"
32#endif
33
34namespace {
35
36using testing::Return;
37using testing::_;
38
39class SyncedPrefChangeRegistrarTest : public InProcessBrowserTest {
40 public:
41  SyncedPrefChangeRegistrarTest() : next_sync_data_id_(0) {}
42  virtual ~SyncedPrefChangeRegistrarTest() {}
43
44#if defined(ENABLE_CONFIGURATION_POLICY)
45  void UpdateChromePolicy(const policy::PolicyMap& policies) {
46    policy_provider_.UpdateChromePolicy(policies);
47    DCHECK(base::MessageLoop::current());
48    base::RunLoop loop;
49    loop.RunUntilIdle();
50  }
51#endif
52
53  void SetBooleanPrefValueFromSync(const std::string& name, bool value) {
54    std::string serialized_value;
55    JSONStringValueSerializer json(&serialized_value);
56    json.Serialize(base::FundamentalValue(value));
57
58    sync_pb::EntitySpecifics specifics;
59    sync_pb::PreferenceSpecifics* pref_specifics =
60        specifics.mutable_preference();
61    pref_specifics->set_name(name);
62    pref_specifics->set_value(serialized_value);
63
64    syncer::SyncData change_data = syncer::SyncData::CreateRemoteData(
65        ++next_sync_data_id_,
66        specifics,
67        base::Time(),
68        syncer::AttachmentIdList(),
69        syncer::AttachmentServiceProxyForTest::Create());
70    syncer::SyncChange change(
71        FROM_HERE, syncer::SyncChange::ACTION_UPDATE, change_data);
72
73    syncer::SyncChangeList change_list;
74    change_list.push_back(change);
75
76    syncer_->ProcessSyncChanges(FROM_HERE, change_list);
77  }
78
79  void SetBooleanPrefValueFromLocal(const std::string& name, bool value) {
80    prefs_->SetBoolean(name.c_str(), value);
81  }
82
83  bool GetBooleanPrefValue(const std::string& name) {
84    return prefs_->GetBoolean(name.c_str());
85  }
86
87  PrefServiceSyncable* prefs() const {
88    return prefs_;
89  }
90
91  SyncedPrefChangeRegistrar* registrar() const {
92    return registrar_.get();
93  }
94
95 private:
96#if defined(ENABLE_CONFIGURATION_POLICY)
97  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
98    EXPECT_CALL(policy_provider_, IsInitializationComplete(_))
99        .WillRepeatedly(Return(true));
100    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
101        &policy_provider_);
102  }
103#endif
104
105  virtual void SetUpOnMainThread() OVERRIDE {
106    prefs_ = PrefServiceSyncable::FromProfile(browser()->profile());
107    syncer_ = prefs_->GetSyncableService(syncer::PREFERENCES);
108    syncer_->MergeDataAndStartSyncing(
109        syncer::PREFERENCES,
110        syncer::SyncDataList(),
111        scoped_ptr<syncer::SyncChangeProcessor>(
112            new syncer::FakeSyncChangeProcessor),
113        scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock));
114    registrar_.reset(new SyncedPrefChangeRegistrar(prefs_));
115  }
116
117  virtual void TearDownOnMainThread() OVERRIDE {
118    registrar_.reset();
119  }
120
121  PrefServiceSyncable* prefs_;
122  syncer::SyncableService* syncer_;
123  int next_sync_data_id_;
124
125  scoped_ptr<SyncedPrefChangeRegistrar> registrar_;
126#if defined(ENABLE_CONFIGURATION_POLICY)
127  policy::MockConfigurationPolicyProvider policy_provider_;
128#endif
129};
130
131struct TestSyncedPrefObserver {
132  bool last_seen_value;
133  bool last_update_is_from_sync;
134  bool has_been_notified;
135};
136
137void TestPrefChangeCallback(PrefService* prefs,
138                            TestSyncedPrefObserver* observer,
139                            const std::string& path,
140                            bool from_sync) {
141  observer->last_seen_value = prefs->GetBoolean(path.c_str());
142  observer->last_update_is_from_sync = from_sync;
143  observer->has_been_notified = true;
144}
145
146}  // namespace
147
148IN_PROC_BROWSER_TEST_F(SyncedPrefChangeRegistrarTest,
149                       DifferentiateRemoteAndLocalChanges) {
150  TestSyncedPrefObserver observer = {};
151  registrar()->Add(prefs::kShowHomeButton,
152      base::Bind(&TestPrefChangeCallback, prefs(), &observer));
153
154  EXPECT_FALSE(observer.has_been_notified);
155
156  SetBooleanPrefValueFromSync(prefs::kShowHomeButton, true);
157  EXPECT_TRUE(observer.has_been_notified);
158  EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton));
159  EXPECT_TRUE(observer.last_update_is_from_sync);
160  EXPECT_TRUE(observer.last_seen_value);
161
162  observer.has_been_notified = false;
163  SetBooleanPrefValueFromLocal(prefs::kShowHomeButton, false);
164  EXPECT_TRUE(observer.has_been_notified);
165  EXPECT_FALSE(GetBooleanPrefValue(prefs::kShowHomeButton));
166  EXPECT_FALSE(observer.last_update_is_from_sync);
167  EXPECT_FALSE(observer.last_seen_value);
168
169  observer.has_been_notified = false;
170  SetBooleanPrefValueFromLocal(prefs::kShowHomeButton, true);
171  EXPECT_TRUE(observer.has_been_notified);
172  EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton));
173  EXPECT_FALSE(observer.last_update_is_from_sync);
174  EXPECT_TRUE(observer.last_seen_value);
175
176  observer.has_been_notified = false;
177  SetBooleanPrefValueFromSync(prefs::kShowHomeButton, false);
178  EXPECT_TRUE(observer.has_been_notified);
179  EXPECT_FALSE(GetBooleanPrefValue(prefs::kShowHomeButton));
180  EXPECT_TRUE(observer.last_update_is_from_sync);
181  EXPECT_FALSE(observer.last_seen_value);
182}
183
184#if defined(ENABLE_CONFIGURATION_POLICY)
185IN_PROC_BROWSER_TEST_F(SyncedPrefChangeRegistrarTest,
186                       IgnoreLocalChangesToManagedPrefs) {
187  TestSyncedPrefObserver observer = {};
188  registrar()->Add(prefs::kShowHomeButton,
189      base::Bind(&TestPrefChangeCallback, prefs(), &observer));
190
191  policy::PolicyMap policies;
192  policies.Set(policy::key::kShowHomeButton,
193               policy::POLICY_LEVEL_MANDATORY,
194               policy::POLICY_SCOPE_USER,
195               new base::FundamentalValue(true),
196               NULL);
197  UpdateChromePolicy(policies);
198
199  EXPECT_TRUE(prefs()->IsManagedPreference(prefs::kShowHomeButton));
200
201  SetBooleanPrefValueFromLocal(prefs::kShowHomeButton, false);
202  EXPECT_FALSE(observer.has_been_notified);
203  EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton));
204}
205
206IN_PROC_BROWSER_TEST_F(SyncedPrefChangeRegistrarTest,
207                       IgnoreSyncChangesToManagedPrefs) {
208  TestSyncedPrefObserver observer = {};
209  registrar()->Add(prefs::kShowHomeButton,
210      base::Bind(&TestPrefChangeCallback, prefs(), &observer));
211
212  policy::PolicyMap policies;
213  policies.Set(policy::key::kShowHomeButton,
214               policy::POLICY_LEVEL_MANDATORY,
215               policy::POLICY_SCOPE_USER,
216               new base::FundamentalValue(true),
217               NULL);
218  UpdateChromePolicy(policies);
219
220  EXPECT_TRUE(prefs()->IsManagedPreference(prefs::kShowHomeButton));
221  SetBooleanPrefValueFromSync(prefs::kShowHomeButton, false);
222  EXPECT_FALSE(observer.has_been_notified);
223  EXPECT_TRUE(GetBooleanPrefValue(prefs::kShowHomeButton));
224}
225#endif
226