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 "content/public/test/test_browser_thread_bundle.h"
12 #include "sync/api/fake_sync_change_processor.h"
13 #include "sync/api/sync_change.h"
14 #include "sync/api/sync_change_processor_wrapper_for_test.h"
15 #include "sync/api/sync_error_factory_mock.h"
16 #include "sync/protocol/sync.pb.h"
17 #include "testing/gtest/include/gtest/gtest.h"
21 class MockSyncErrorFactory
: public syncer::SyncErrorFactory
{
23 explicit MockSyncErrorFactory(syncer::ModelType type
);
24 ~MockSyncErrorFactory() override
;
26 // SyncErrorFactory implementation:
27 syncer::SyncError
CreateAndUploadError(
28 const tracked_objects::Location
& location
,
29 const std::string
& message
) override
;
32 syncer::ModelType type_
;
34 DISALLOW_COPY_AND_ASSIGN(MockSyncErrorFactory
);
37 MockSyncErrorFactory::MockSyncErrorFactory(syncer::ModelType type
)
40 MockSyncErrorFactory::~MockSyncErrorFactory() {}
42 syncer::SyncError
MockSyncErrorFactory::CreateAndUploadError(
43 const tracked_objects::Location
& location
,
44 const std::string
& message
) {
45 return syncer::SyncError(location
,
46 syncer::SyncError::DATATYPE_ERROR
,
53 const char kAtomicItemName
[] = "X-Wombat";
54 const char kSettingsName
[] = "TestingSetting";
55 const char kSettingsValue
[] = "SettingsValue";
56 const char kSplitItemName
[] = "X-SuperMoosePowers";
58 class SupervisedUserSettingsServiceTest
: public ::testing::Test
{
60 SupervisedUserSettingsServiceTest() : settings_service_(nullptr) {}
61 ~SupervisedUserSettingsServiceTest() override
{}
63 scoped_ptr
<syncer::SyncChangeProcessor
> CreateSyncProcessor() {
64 sync_processor_
.reset(new syncer::FakeSyncChangeProcessor
);
65 return scoped_ptr
<syncer::SyncChangeProcessor
>(
66 new syncer::SyncChangeProcessorWrapperForTest(sync_processor_
.get()));
69 void StartSyncing(const syncer::SyncDataList
& initial_sync_data
) {
70 scoped_ptr
<syncer::SyncErrorFactory
> error_handler(
71 new MockSyncErrorFactory(syncer::SUPERVISED_USER_SETTINGS
));
72 syncer::SyncMergeResult result
= settings_service_
.MergeDataAndStartSyncing(
73 syncer::SUPERVISED_USER_SETTINGS
,
75 CreateSyncProcessor(),
76 error_handler
.Pass());
77 EXPECT_FALSE(result
.error().IsSet());
80 void UploadSplitItem(const std::string
& key
, const std::string
& value
) {
81 split_items_
.SetStringWithoutPathExpansion(key
, value
);
82 settings_service_
.UploadItem(
83 SupervisedUserSettingsService::MakeSplitSettingKey(kSplitItemName
,
85 scoped_ptr
<base::Value
>(new base::StringValue(value
)));
88 void UploadAtomicItem(const std::string
& value
) {
89 atomic_setting_value_
.reset(new base::StringValue(value
));
90 settings_service_
.UploadItem(
92 scoped_ptr
<base::Value
>(new base::StringValue(value
)));
95 void VerifySyncDataItem(syncer::SyncData sync_data
) {
96 const sync_pb::ManagedUserSettingSpecifics
& supervised_user_setting
=
97 sync_data
.GetSpecifics().managed_user_setting();
98 base::Value
* expected_value
= NULL
;
99 if (supervised_user_setting
.name() == kAtomicItemName
) {
100 expected_value
= atomic_setting_value_
.get();
102 EXPECT_TRUE(base::StartsWith(supervised_user_setting
.name(),
103 std::string(kSplitItemName
) + ':',
104 base::CompareCase::SENSITIVE
));
106 supervised_user_setting
.name().substr(strlen(kSplitItemName
) + 1);
107 EXPECT_TRUE(split_items_
.GetWithoutPathExpansion(key
, &expected_value
));
110 scoped_ptr
<base::Value
> value(
111 base::JSONReader::DeprecatedRead(supervised_user_setting
.value()));
112 EXPECT_TRUE(expected_value
->Equals(value
.get()));
115 void OnNewSettingsAvailable(const base::DictionaryValue
* settings
) {
119 settings_
.reset(settings
->DeepCopy());
122 // testing::Test overrides:
123 void SetUp() override
{
124 TestingPrefStore
* pref_store
= new TestingPrefStore
;
125 settings_service_
.Init(pref_store
);
126 user_settings_subscription_
= settings_service_
.Subscribe(
127 base::Bind(&SupervisedUserSettingsServiceTest::OnNewSettingsAvailable
,
128 base::Unretained(this)));
129 pref_store
->SetInitializationCompleted();
130 ASSERT_FALSE(settings_
);
131 settings_service_
.SetActive(true);
132 ASSERT_TRUE(settings_
);
135 void TearDown() override
{ settings_service_
.Shutdown(); }
137 content::TestBrowserThreadBundle thread_bundle_
;
138 base::DictionaryValue split_items_
;
139 scoped_ptr
<base::Value
> atomic_setting_value_
;
140 SupervisedUserSettingsService settings_service_
;
141 scoped_ptr
<base::DictionaryValue
> settings_
;
142 scoped_ptr
<base::CallbackList
<void(
143 const base::DictionaryValue
*)>::Subscription
> user_settings_subscription_
;
145 scoped_ptr
<syncer::FakeSyncChangeProcessor
> sync_processor_
;
148 TEST_F(SupervisedUserSettingsServiceTest
, ProcessAtomicSetting
) {
149 StartSyncing(syncer::SyncDataList());
150 ASSERT_TRUE(settings_
);
151 const base::Value
* value
= NULL
;
152 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
155 syncer::SyncData data
=
156 SupervisedUserSettingsService::CreateSyncDataForSetting(
157 kSettingsName
, base::StringValue(kSettingsValue
));
158 syncer::SyncChangeList change_list
;
159 change_list
.push_back(
160 syncer::SyncChange(FROM_HERE
, syncer::SyncChange::ACTION_ADD
, data
));
161 syncer::SyncError error
=
162 settings_service_
.ProcessSyncChanges(FROM_HERE
, change_list
);
163 EXPECT_FALSE(error
.IsSet()) << error
.ToString();
164 ASSERT_TRUE(settings_
);
165 ASSERT_TRUE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
166 std::string string_value
;
167 EXPECT_TRUE(value
->GetAsString(&string_value
));
168 EXPECT_EQ(kSettingsValue
, string_value
);
171 TEST_F(SupervisedUserSettingsServiceTest
, ProcessSplitSetting
) {
172 StartSyncing(syncer::SyncDataList());
173 ASSERT_TRUE(settings_
);
174 const base::Value
* value
= NULL
;
175 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
177 base::DictionaryValue dict
;
178 dict
.SetString("foo", "bar");
179 dict
.SetBoolean("awesomesauce", true);
180 dict
.SetInteger("eaudecologne", 4711);
183 syncer::SyncChangeList change_list
;
184 for (base::DictionaryValue::Iterator
it(dict
); !it
.IsAtEnd(); it
.Advance()) {
185 syncer::SyncData data
=
186 SupervisedUserSettingsService::CreateSyncDataForSetting(
187 SupervisedUserSettingsService::MakeSplitSettingKey(kSettingsName
,
190 change_list
.push_back(
191 syncer::SyncChange(FROM_HERE
, syncer::SyncChange::ACTION_ADD
, data
));
193 syncer::SyncError error
=
194 settings_service_
.ProcessSyncChanges(FROM_HERE
, change_list
);
195 EXPECT_FALSE(error
.IsSet()) << error
.ToString();
196 ASSERT_TRUE(settings_
);
197 ASSERT_TRUE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
198 const base::DictionaryValue
* dict_value
= NULL
;
199 ASSERT_TRUE(value
->GetAsDictionary(&dict_value
));
200 EXPECT_TRUE(dict_value
->Equals(&dict
));
203 TEST_F(SupervisedUserSettingsServiceTest
, SetLocalSetting
) {
204 const base::Value
* value
= NULL
;
205 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
208 settings_service_
.SetLocalSetting(
210 scoped_ptr
<base::Value
>(new base::StringValue(kSettingsValue
)));
211 ASSERT_TRUE(settings_
);
212 ASSERT_TRUE(settings_
->GetWithoutPathExpansion(kSettingsName
, &value
));
213 std::string string_value
;
214 EXPECT_TRUE(value
->GetAsString(&string_value
));
215 EXPECT_EQ(kSettingsValue
, string_value
);
218 TEST_F(SupervisedUserSettingsServiceTest
, UploadItem
) {
219 UploadSplitItem("foo", "bar");
220 UploadSplitItem("blurp", "baz");
221 UploadAtomicItem("hurdle");
223 // Uploading should produce changes when we start syncing.
224 StartSyncing(syncer::SyncDataList());
225 ASSERT_EQ(3u, sync_processor_
->changes().size());
226 for (const syncer::SyncChange
& sync_change
: sync_processor_
->changes()) {
227 ASSERT_TRUE(sync_change
.IsValid());
228 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, sync_change
.change_type());
229 VerifySyncDataItem(sync_change
.sync_data());
232 // It should also show up in local Sync data.
233 syncer::SyncDataList sync_data
=
234 settings_service_
.GetAllSyncData(syncer::SUPERVISED_USER_SETTINGS
);
235 EXPECT_EQ(3u, sync_data
.size());
236 for (const syncer::SyncData
& sync_data_item
: sync_data
)
237 VerifySyncDataItem(sync_data_item
);
239 // Uploading after we have started syncing should work too.
240 sync_processor_
->changes().clear();
241 UploadSplitItem("froodle", "narf");
242 ASSERT_EQ(1u, sync_processor_
->changes().size());
243 syncer::SyncChange change
= sync_processor_
->changes()[0];
244 ASSERT_TRUE(change
.IsValid());
245 EXPECT_EQ(syncer::SyncChange::ACTION_ADD
, change
.change_type());
246 VerifySyncDataItem(change
.sync_data());
248 sync_data
= settings_service_
.GetAllSyncData(
249 syncer::SUPERVISED_USER_SETTINGS
);
250 EXPECT_EQ(4u, sync_data
.size());
251 for (const syncer::SyncData
& sync_data_item
: sync_data
)
252 VerifySyncDataItem(sync_data_item
);
254 // Uploading an item with a previously seen key should create an UPDATE
256 sync_processor_
->changes().clear();
257 UploadSplitItem("blurp", "snarl");
258 ASSERT_EQ(1u, sync_processor_
->changes().size());
259 change
= sync_processor_
->changes()[0];
260 ASSERT_TRUE(change
.IsValid());
261 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, change
.change_type());
262 VerifySyncDataItem(change
.sync_data());
264 sync_data
= settings_service_
.GetAllSyncData(
265 syncer::SUPERVISED_USER_SETTINGS
);
266 EXPECT_EQ(4u, sync_data
.size());
267 for (const syncer::SyncData
& sync_data_item
: sync_data
)
268 VerifySyncDataItem(sync_data_item
);
270 sync_processor_
->changes().clear();
271 UploadAtomicItem("fjord");
272 ASSERT_EQ(1u, sync_processor_
->changes().size());
273 change
= sync_processor_
->changes()[0];
274 ASSERT_TRUE(change
.IsValid());
275 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE
, change
.change_type());
276 VerifySyncDataItem(change
.sync_data());
278 sync_data
= settings_service_
.GetAllSyncData(
279 syncer::SUPERVISED_USER_SETTINGS
);
280 EXPECT_EQ(4u, sync_data
.size());
281 for (const syncer::SyncData
& sync_data_item
: sync_data
)
282 VerifySyncDataItem(sync_data_item
);
284 // The uploaded items should not show up as settings.
285 const base::Value
* value
= NULL
;
286 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kAtomicItemName
, &value
));
287 EXPECT_FALSE(settings_
->GetWithoutPathExpansion(kSplitItemName
, &value
));
289 // Restarting sync should not create any new changes.
290 settings_service_
.StopSyncing(syncer::SUPERVISED_USER_SETTINGS
);
291 StartSyncing(sync_data
);
292 ASSERT_EQ(0u, sync_processor_
->changes().size());