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.
6 #include "base/callback.h"
7 #include "base/json/json_reader.h"
8 #include "base/prefs/testing_pref_store.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
11 #include "sync/api/fake_sync_change_processor.h"
12 #include "sync/api/sync_change.h"
13 #include "sync/api/sync_change_processor_wrapper_for_test.h"
14 #include "sync/api/sync_error_factory_mock.h"
15 #include "sync/protocol/sync.pb.h"
16 #include "testing/gtest/include/gtest/gtest.h"
20 class MockSyncErrorFactory
: public syncer::SyncErrorFactory
{
22 explicit MockSyncErrorFactory(syncer::ModelType type
);
23 ~MockSyncErrorFactory() override
;
25 // SyncErrorFactory implementation:
26 syncer::SyncError
CreateAndUploadError(
27 const tracked_objects::Location
& location
,
28 const std::string
& message
) override
;
31 syncer::ModelType type_
;
33 DISALLOW_COPY_AND_ASSIGN(MockSyncErrorFactory
);
36 MockSyncErrorFactory::MockSyncErrorFactory(syncer::ModelType type
)
39 MockSyncErrorFactory::~MockSyncErrorFactory() {}
41 syncer::SyncError
MockSyncErrorFactory::CreateAndUploadError(
42 const tracked_objects::Location
& location
,
43 const std::string
& message
) {
44 return syncer::SyncError(location
,
45 syncer::SyncError::DATATYPE_ERROR
,
52 const char kAtomicItemName
[] = "X-Wombat";
53 const char kSettingsName
[] = "TestingSetting";
54 const char kSettingsValue
[] = "SettingsValue";
55 const char kSplitItemName
[] = "X-SuperMoosePowers";
57 class SupervisedUserSettingsServiceTest
: public ::testing::Test
{
59 SupervisedUserSettingsServiceTest() {}
60 ~SupervisedUserSettingsServiceTest() override
{}
62 scoped_ptr
<syncer::SyncChangeProcessor
> CreateSyncProcessor() {
63 sync_processor_
.reset(new syncer::FakeSyncChangeProcessor
);
64 return scoped_ptr
<syncer::SyncChangeProcessor
>(
65 new syncer::SyncChangeProcessorWrapperForTest(sync_processor_
.get()));
68 void StartSyncing(const syncer::SyncDataList
& initial_sync_data
) {
69 scoped_ptr
<syncer::SyncErrorFactory
> error_handler(
70 new MockSyncErrorFactory(syncer::SUPERVISED_USER_SETTINGS
));
71 syncer::SyncMergeResult result
= settings_service_
.MergeDataAndStartSyncing(
72 syncer::SUPERVISED_USER_SETTINGS
,
74 CreateSyncProcessor(),
75 error_handler
.Pass());
76 EXPECT_FALSE(result
.error().IsSet());
79 void UploadSplitItem(const std::string
& key
, const std::string
& value
) {
80 split_items_
.SetStringWithoutPathExpansion(key
, value
);
81 settings_service_
.UploadItem(
82 SupervisedUserSettingsService::MakeSplitSettingKey(kSplitItemName
,
84 scoped_ptr
<base::Value
>(new base::StringValue(value
)));
87 void UploadAtomicItem(const std::string
& value
) {
88 atomic_setting_value_
.reset(new base::StringValue(value
));
89 settings_service_
.UploadItem(
91 scoped_ptr
<base::Value
>(new base::StringValue(value
)));
94 void VerifySyncDataItem(syncer::SyncData sync_data
) {
95 const sync_pb::ManagedUserSettingSpecifics
& supervised_user_setting
=
96 sync_data
.GetSpecifics().managed_user_setting();
97 base::Value
* expected_value
= NULL
;
98 if (supervised_user_setting
.name() == kAtomicItemName
) {
99 expected_value
= atomic_setting_value_
.get();
101 EXPECT_TRUE(StartsWithASCII(supervised_user_setting
.name(),
102 std::string(kSplitItemName
) + ':',
105 supervised_user_setting
.name().substr(strlen(kSplitItemName
) + 1);
106 EXPECT_TRUE(split_items_
.GetWithoutPathExpansion(key
, &expected_value
));
109 scoped_ptr
<base::Value
> value(
110 base::JSONReader::Read(supervised_user_setting
.value()));
111 EXPECT_TRUE(expected_value
->Equals(value
.get()));
114 void OnNewSettingsAvailable(const base::DictionaryValue
* settings
) {
118 settings_
.reset(settings
->DeepCopy());
121 // testing::Test overrides:
122 void SetUp() override
{
123 TestingPrefStore
* pref_store
= new TestingPrefStore
;
124 settings_service_
.Init(pref_store
);
125 settings_service_
.Subscribe(
126 base::Bind(&SupervisedUserSettingsServiceTest::OnNewSettingsAvailable
,
127 base::Unretained(this)));
128 pref_store
->SetInitializationCompleted();
129 ASSERT_FALSE(settings_
);
130 settings_service_
.SetActive(true);
131 ASSERT_TRUE(settings_
);
134 void TearDown() override
{ settings_service_
.Shutdown(); }
136 base::DictionaryValue split_items_
;
137 scoped_ptr
<base::Value
> atomic_setting_value_
;
138 SupervisedUserSettingsService settings_service_
;
139 scoped_ptr
<base::DictionaryValue
> settings_
;
141 scoped_ptr
<syncer::FakeSyncChangeProcessor
> sync_processor_
;
144 TEST_F(SupervisedUserSettingsServiceTest
, ProcessAtomicSetting
) {
145 StartSyncing(syncer::SyncDataList());
146 ASSERT_TRUE(settings_
);
147 const base::Value
* value
= NULL
;
148 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
151 syncer::SyncData data
=
152 SupervisedUserSettingsService::CreateSyncDataForSetting(
153 kSettingsName
, base::StringValue(kSettingsValue
));
154 syncer::SyncChangeList change_list
;
155 change_list
.push_back(
156 syncer::SyncChange(FROM_HERE
, syncer::SyncChange::ACTION_ADD
, data
));
157 syncer::SyncError error
=
158 settings_service_
.ProcessSyncChanges(FROM_HERE
, change_list
);
159 EXPECT_FALSE(error
.IsSet()) << error
.ToString();
160 ASSERT_TRUE(settings_
);
161 ASSERT_TRUE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
162 std::string string_value
;
163 EXPECT_TRUE(value
->GetAsString(&string_value
));
164 EXPECT_EQ(kSettingsValue
, string_value
);
167 TEST_F(SupervisedUserSettingsServiceTest
, ProcessSplitSetting
) {
168 StartSyncing(syncer::SyncDataList());
169 ASSERT_TRUE(settings_
);
170 const base::Value
* value
= NULL
;
171 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
173 base::DictionaryValue dict
;
174 dict
.SetString("foo", "bar");
175 dict
.SetBoolean("awesomesauce", true);
176 dict
.SetInteger("eaudecologne", 4711);
179 syncer::SyncChangeList change_list
;
180 for (base::DictionaryValue::Iterator
it(dict
); !it
.IsAtEnd(); it
.Advance()) {
181 syncer::SyncData data
=
182 SupervisedUserSettingsService::CreateSyncDataForSetting(
183 SupervisedUserSettingsService::MakeSplitSettingKey(kSettingsName
,
186 change_list
.push_back(
187 syncer::SyncChange(FROM_HERE
, syncer::SyncChange::ACTION_ADD
, data
));
189 syncer::SyncError error
=
190 settings_service_
.ProcessSyncChanges(FROM_HERE
, change_list
);
191 EXPECT_FALSE(error
.IsSet()) << error
.ToString();
192 ASSERT_TRUE(settings_
);
193 ASSERT_TRUE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
194 const base::DictionaryValue
* dict_value
= NULL
;
195 ASSERT_TRUE(value
->GetAsDictionary(&dict_value
));
196 EXPECT_TRUE(dict_value
->Equals(&dict
));
199 TEST_F(SupervisedUserSettingsServiceTest
, SetLocalSetting
) {
200 const base::Value
* value
= NULL
;
201 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
204 settings_service_
.SetLocalSetting(
206 scoped_ptr
<base::Value
>(new base::StringValue(kSettingsValue
)));
207 ASSERT_TRUE(settings_
);
208 ASSERT_TRUE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
209 std::string string_value
;
210 EXPECT_TRUE(value
->GetAsString(&string_value
));
211 EXPECT_EQ(kSettingsValue
, string_value
);
214 TEST_F(SupervisedUserSettingsServiceTest
, UploadItem
) {
215 UploadSplitItem("foo", "bar");
216 UploadSplitItem("blurp", "baz");
217 UploadAtomicItem("hurdle");
219 // Uploading should produce changes when we start syncing.
220 StartSyncing(syncer::SyncDataList());
221 ASSERT_EQ(3u, sync_processor_
->changes().size());
222 for (const syncer::SyncChange
& sync_change
: sync_processor_
->changes()) {
223 ASSERT_TRUE(sync_change
.IsValid());
224 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, sync_change
.change_type());
225 VerifySyncDataItem(sync_change
.sync_data());
228 // It should also show up in local Sync data.
229 syncer::SyncDataList sync_data
=
230 settings_service_
.GetAllSyncData(syncer::SUPERVISED_USER_SETTINGS
);
231 EXPECT_EQ(3u, sync_data
.size());
232 for (const syncer::SyncData
& sync_data_item
: sync_data
)
233 VerifySyncDataItem(sync_data_item
);
235 // Uploading after we have started syncing should work too.
236 sync_processor_
->changes().clear();
237 UploadSplitItem("froodle", "narf");
238 ASSERT_EQ(1u, sync_processor_
->changes().size());
239 syncer::SyncChange change
= sync_processor_
->changes()[0];
240 ASSERT_TRUE(change
.IsValid());
241 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, change
.change_type());
242 VerifySyncDataItem(change
.sync_data());
244 sync_data
= settings_service_
.GetAllSyncData(
245 syncer::SUPERVISED_USER_SETTINGS
);
246 EXPECT_EQ(4u, sync_data
.size());
247 for (const syncer::SyncData
& sync_data_item
: sync_data
)
248 VerifySyncDataItem(sync_data_item
);
250 // Uploading an item with a previously seen key should create an UPDATE
252 sync_processor_
->changes().clear();
253 UploadSplitItem("blurp", "snarl");
254 ASSERT_EQ(1u, sync_processor_
->changes().size());
255 change
= sync_processor_
->changes()[0];
256 ASSERT_TRUE(change
.IsValid());
257 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, change
.change_type());
258 VerifySyncDataItem(change
.sync_data());
260 sync_data
= settings_service_
.GetAllSyncData(
261 syncer::SUPERVISED_USER_SETTINGS
);
262 EXPECT_EQ(4u, sync_data
.size());
263 for (const syncer::SyncData
& sync_data_item
: sync_data
)
264 VerifySyncDataItem(sync_data_item
);
266 sync_processor_
->changes().clear();
267 UploadAtomicItem("fjord");
268 ASSERT_EQ(1u, sync_processor_
->changes().size());
269 change
= sync_processor_
->changes()[0];
270 ASSERT_TRUE(change
.IsValid());
271 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, change
.change_type());
272 VerifySyncDataItem(change
.sync_data());
274 sync_data
= settings_service_
.GetAllSyncData(
275 syncer::SUPERVISED_USER_SETTINGS
);
276 EXPECT_EQ(4u, sync_data
.size());
277 for (const syncer::SyncData
& sync_data_item
: sync_data
)
278 VerifySyncDataItem(sync_data_item
);
280 // The uploaded items should not show up as settings.
281 const base::Value
* value
= NULL
;
282 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kAtomicItemName
, &value
));
283 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSplitItemName
, &value
));
285 // Restarting sync should not create any new changes.
286 settings_service_
.StopSyncing(syncer::SUPERVISED_USER_SETTINGS
);
287 StartSyncing(sync_data
);
288 ASSERT_EQ(0u, sync_processor_
->changes().size());