Commit 82110212 authored by bauerb@chromium.org's avatar bauerb@chromium.org

Add ManagedUserSharedSettingsService.

ManagedUserSharedSettingsService syncs settings that can be modified/accessed both by a supervised user and their manager (for example, the avatar).

BUG=316168

Review URL: https://codereview.chromium.org/123293003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243680 0039d316-1c4b-4281-b951-d872f2087c98
parent c829088c
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/values.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_data.h"
#include "sync/api/sync_error.h"
#include "sync/api/sync_error_factory.h"
#include "sync/api/sync_merge_result.h"
#include "sync/protocol/sync.pb.h"
using base::DictionaryValue;
using base::Value;
using syncer::MANAGED_USER_SHARED_SETTINGS;
using syncer::ModelType;
using syncer::SyncChange;
using syncer::SyncChangeList;
using syncer::SyncChangeProcessor;
using syncer::SyncData;
using syncer::SyncDataList;
using syncer::SyncError;
using syncer::SyncErrorFactory;
using syncer::SyncMergeResult;
namespace {
const char kAcknowledged[] = "acknowledged";
const char kValue[] = "value";
DictionaryValue* FindOrCreateDictionary(DictionaryValue* parent,
const std::string& key) {
DictionaryValue* dict = NULL;
if (!parent->GetDictionaryWithoutPathExpansion(key, &dict)) {
dict = new DictionaryValue;
parent->SetWithoutPathExpansion(key, dict);
}
return dict;
}
class ScopedManagedUserSharedSettingsUpdate {
public:
ScopedManagedUserSharedSettingsUpdate(PrefService* prefs,
const std::string& mu_id)
: update_(prefs, prefs::kManagedUserSharedSettings), mu_id_(mu_id) {
DCHECK(!mu_id.empty());
// A supervised user can only modify their own settings.
std::string id = prefs->GetString(prefs::kManagedUserId);
DCHECK(id.empty() || id == mu_id);
}
DictionaryValue* Get() {
return FindOrCreateDictionary(update_.Get(), mu_id_);
}
private:
DictionaryPrefUpdate update_;
std::string mu_id_;
};
SyncData CreateSyncDataForValue(
const std::string& mu_id,
const std::string& key,
const Value& dict_value) {
const DictionaryValue* dict = NULL;
if (!dict_value.GetAsDictionary(&dict))
return SyncData();
const Value* value = NULL;
if (!dict->Get(kValue, &value))
return SyncData();
bool acknowledged = false;
dict->GetBoolean(kAcknowledged, &acknowledged);
return ManagedUserSharedSettingsService::CreateSyncDataForSetting(
mu_id, key, *value, acknowledged);
}
} // namespace
ManagedUserSharedSettingsService::ManagedUserSharedSettingsService(
PrefService* prefs)
: prefs_(prefs) {}
ManagedUserSharedSettingsService::~ManagedUserSharedSettingsService() {}
void ManagedUserSharedSettingsService::SetValueInternal(
const std::string& mu_id,
const std::string& key,
const Value& value,
bool acknowledged) {
ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id);
DictionaryValue* update_dict = update.Get();
DictionaryValue* dict = NULL;
bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
if (!has_key) {
dict = new DictionaryValue;
update_dict->SetWithoutPathExpansion(key, dict);
}
dict->SetWithoutPathExpansion(kValue, value.DeepCopy());
dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged);
if (!sync_processor_)
return;
SyncData data = CreateSyncDataForSetting(mu_id, key, value, acknowledged);
SyncChange::SyncChangeType change_type =
has_key ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD;
SyncChangeList changes;
changes.push_back(SyncChange(FROM_HERE, change_type, data));
SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
DCHECK(!error.IsSet()) << error.ToString();
}
const Value* ManagedUserSharedSettingsService::GetValue(
const std::string& mu_id,
const std::string& key) {
const DictionaryValue* data =
prefs_->GetDictionary(prefs::kManagedUserSharedSettings);
const DictionaryValue* dict = NULL;
if (!data->GetDictionaryWithoutPathExpansion(mu_id, &dict))
return NULL;
const DictionaryValue* settings = NULL;
if (!dict->GetDictionaryWithoutPathExpansion(key, &settings))
return NULL;
const Value* value = NULL;
if (!settings->GetWithoutPathExpansion(kValue, &value))
return NULL;
return value;
}
void ManagedUserSharedSettingsService::SetValue(
const std::string& mu_id,
const std::string& key,
const Value& value) {
SetValueInternal(mu_id, key, value, true);
}
scoped_ptr<ManagedUserSharedSettingsService::ChangeCallbackList::Subscription>
ManagedUserSharedSettingsService::Subscribe(
const ManagedUserSharedSettingsService::ChangeCallback& cb) {
return callbacks_.Add(cb);
}
// static
void ManagedUserSharedSettingsService::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterDictionaryPref(
prefs::kManagedUserSharedSettings,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
// static
SyncData ManagedUserSharedSettingsService::CreateSyncDataForSetting(
const std::string& mu_id,
const std::string& key,
const Value& value,
bool acknowledged) {
std::string json_value;
base::JSONWriter::Write(&value, &json_value);
::sync_pb::EntitySpecifics specifics;
specifics.mutable_managed_user_shared_setting()->set_mu_id(mu_id);
specifics.mutable_managed_user_shared_setting()->set_key(key);
specifics.mutable_managed_user_shared_setting()->set_value(json_value);
specifics.mutable_managed_user_shared_setting()->set_acknowledged(
acknowledged);
std::string title = mu_id + ":" + key;
return SyncData::CreateLocalData(title, title, specifics);
}
void ManagedUserSharedSettingsService::Shutdown() {}
syncer::SyncMergeResult
ManagedUserSharedSettingsService::MergeDataAndStartSyncing(
syncer::ModelType type,
const syncer::SyncDataList& initial_sync_data,
scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
scoped_ptr<syncer::SyncErrorFactory> error_handler) {
DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, type);
sync_processor_ = sync_processor.Pass();
error_handler_ = error_handler.Pass();
// We keep a map from MU ID to the set of keys that we have seen in the
// initial sync data.
std::map<std::string, std::set<std::string> > seen_keys;
// Iterate over all initial sync data, and update it locally. This means that
// the value from the server always wins over a local value.
for (SyncDataList::const_iterator it = initial_sync_data.begin();
it != initial_sync_data.end();
++it) {
DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, it->GetDataType());
const ::sync_pb::ManagedUserSharedSettingSpecifics&
managed_user_shared_setting =
it->GetSpecifics().managed_user_shared_setting();
scoped_ptr<Value> value(
base::JSONReader::Read(managed_user_shared_setting.value()));
const std::string& mu_id = managed_user_shared_setting.mu_id();
ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id);
const std::string& key = managed_user_shared_setting.key();
DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key);
dict->SetWithoutPathExpansion(kValue, value.release());
// Every setting we get from the server should have the acknowledged flag
// set.
DCHECK(managed_user_shared_setting.acknowledged());
dict->SetBooleanWithoutPathExpansion(
kAcknowledged, managed_user_shared_setting.acknowledged());
callbacks_.Notify(mu_id, key);
seen_keys[mu_id].insert(key);
}
// Iterate over all settings that we have locally, which includes settings
// that were just synced down. We filter those out using |seen_keys|.
SyncChangeList change_list;
const DictionaryValue* all_settings =
prefs_->GetDictionary(prefs::kManagedUserSharedSettings);
for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
it.Advance()) {
const DictionaryValue* dict = NULL;
bool success = it.value().GetAsDictionary(&dict);
DCHECK(success);
const std::set<std::string>& seen = seen_keys[it.key()];
for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
// We only need to upload settings that we haven't seen in the initial
// sync data (which means they were added locally).
if (seen.count(jt.key()) > 0)
continue;
SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value());
DCHECK(data.IsValid());
change_list.push_back(
SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data));
}
}
SyncMergeResult result(MANAGED_USER_SHARED_SETTINGS);
// Process all the accumulated changes.
if (change_list.size() > 0) {
result.set_error(
sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
}
// TODO(bauerb): Statistics?
return result;
}
void ManagedUserSharedSettingsService::StopSyncing(syncer::ModelType type) {
DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, type);
sync_processor_.reset();
error_handler_.reset();
}
syncer::SyncDataList ManagedUserSharedSettingsService::GetAllSyncData(
syncer::ModelType type) const {
DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, type);
SyncDataList data;
const DictionaryValue* all_settings =
prefs_->GetDictionary(prefs::kManagedUserSharedSettings);
for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
it.Advance()) {
const DictionaryValue* dict = NULL;
bool success = it.value().GetAsDictionary(&dict);
DCHECK(success);
for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value()));
}
}
return data;
}
syncer::SyncError ManagedUserSharedSettingsService::ProcessSyncChanges(
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) {
for (SyncChangeList::const_iterator it = change_list.begin();
it != change_list.end();
++it) {
SyncData data = it->sync_data();
DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, data.GetDataType());
const ::sync_pb::ManagedUserSharedSettingSpecifics&
managed_user_shared_setting =
data.GetSpecifics().managed_user_shared_setting();
const std::string& key = managed_user_shared_setting.key();
const std::string& mu_id = managed_user_shared_setting.mu_id();
ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id);
DictionaryValue* update_dict = update.Get();
DictionaryValue* dict = NULL;
bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
switch (it->change_type()) {
case SyncChange::ACTION_ADD:
case SyncChange::ACTION_UPDATE: {
// Every setting we get from the server should have the acknowledged
// flag set.
DCHECK(managed_user_shared_setting.acknowledged());
if (has_key) {
// If the managed user already exists, it should be an update action.
DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type());
} else {
// Otherwise, it should be an add action.
DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type());
dict = new DictionaryValue;
update_dict->SetWithoutPathExpansion(key, dict);
}
scoped_ptr<Value> value(
base::JSONReader::Read(managed_user_shared_setting.value()));
dict->SetWithoutPathExpansion(kValue, value.release());
dict->SetBooleanWithoutPathExpansion(
kAcknowledged, managed_user_shared_setting.acknowledged());
break;
}
case SyncChange::ACTION_DELETE: {
if (has_key)
update_dict->RemoveWithoutPathExpansion(key, NULL);
else
NOTREACHED() << "Trying to delete nonexistent key " << key;
break;
}
case SyncChange::ACTION_INVALID: {
NOTREACHED();
break;
}
}
callbacks_.Notify(mu_id, key);
}
SyncError error;
return error;
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_SERVICE_H_
#define CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_SERVICE_H_
#include "base/callback.h"
#include "base/callback_list.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/managed_mode/managed_users.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "sync/api/syncable_service.h"
class PrefService;
namespace base {
class DictionaryValue;
class Value;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
// ManagedUserSharedSettingsService syncs settings (as key-value pairs) that can
// be modified both by a supervised user and their manager.
// A supervised user can only modify their own settings, whereas a manager can
// modify settings for all their supervised users.
//
// The shared settings are stored in the user preferences in a multi-level
// dictionary. The first level is the MU ID, the second level is the key for the
// setting, and the third level is a dictionary with a "value" key for the value
// and an "acknowledged" flag, which is used to wait for the Sync server to
// acknowledge that it has seen a setting change (see
// ManagedUserSharedSettingsUpdate for how to use this).
class ManagedUserSharedSettingsService : public BrowserContextKeyedService,
public syncer::SyncableService {
public:
// Called whenever a setting changes (see Subscribe() below).
typedef base::Callback<void(const std::string& /* mu_id */,
const std::string& /* key */)> ChangeCallback;
typedef base::CallbackList<
void(const std::string& /* mu_id */, const std::string& /* key */)>
ChangeCallbackList;
// This constructor is public only for testing. Use
// |ManagedUserSyncServiceFactory::GetForProfile(...)| instead to get an
// instance of this service in production code.
explicit ManagedUserSharedSettingsService(PrefService* prefs);
virtual ~ManagedUserSharedSettingsService();
// Returns the value for the given |key| and the supervised user identified by
// |mu_id|. If either the supervised user or the key does not exist, NULL is
// returned. Note that if the profile that owns this service belongs to a
// supervised user, callers will only see settings for their own |mu_id|, i.e.
// a non-matching |mu_id| is treated as non-existent.
const base::Value* GetValue(const std::string& mu_id, const std::string& key);
// Sets the value for the given |key| and the supervised user identified by
// |mu_id|. If the profile that owns this service belongs to a supervised
// user, |mu_id| must be their own.
void SetValue(const std::string& mu_id,
const std::string& key,
const base::Value& value);
// Subscribes to changes in the synced settings. The callback will be notified
// whenever any setting for any supervised user is changed via Sync (but not
// for local changes). Subscribers should filter the settings and users they
// are interested in with the |mu_id| and |key| parameters to the callback.
scoped_ptr<ChangeCallbackList::Subscription> Subscribe(
const ChangeCallback& cb);
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Public for testing.
void SetValueInternal(const std::string& mu_id,
const std::string& key,
const base::Value& value,
bool acknowledged);
// Public for testing.
static syncer::SyncData CreateSyncDataForSetting(const std::string& mu_id,
const std::string& key,
const base::Value& value,
bool acknowledged);
// BrowserContextKeyedService implementation:
virtual void Shutdown() OVERRIDE;
// SyncableService implementation:
virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
syncer::ModelType type,
const syncer::SyncDataList& initial_sync_data,
scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE;
virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
OVERRIDE;
virtual syncer::SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) OVERRIDE;
private:
friend class ManagedUserSharedSettingsUpdate;
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
scoped_ptr<syncer::SyncErrorFactory> error_handler_;
ChangeCallbackList callbacks_;
PrefService* prefs_;
};
#endif // CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_SERVICE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/managed_mode/managed_user_shared_settings_service_factory.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
// static
ManagedUserSharedSettingsService*
ManagedUserSharedSettingsServiceFactory::GetForBrowserContext(
content::BrowserContext* profile) {
return static_cast<ManagedUserSharedSettingsService*>(
GetInstance()->GetServiceForBrowserContext(profile, true));
}
// static
ManagedUserSharedSettingsServiceFactory*
ManagedUserSharedSettingsServiceFactory::GetInstance() {
return Singleton<ManagedUserSharedSettingsServiceFactory>::get();
}
ManagedUserSharedSettingsServiceFactory::
ManagedUserSharedSettingsServiceFactory()
: BrowserContextKeyedServiceFactory(
"ManagedUserSharedSettingsService",
BrowserContextDependencyManager::GetInstance()) {}
ManagedUserSharedSettingsServiceFactory::
~ManagedUserSharedSettingsServiceFactory() {}
BrowserContextKeyedService*
ManagedUserSharedSettingsServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* profile) const {
return new ManagedUserSharedSettingsService(
user_prefs::UserPrefs::Get(profile));
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_SERVICE_FACTORY_H_
#define CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_SERVICE_FACTORY_H_
#include "base/memory/singleton.h"
#include "chrome/browser/managed_mode/managed_users.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
class ManagedUserSharedSettingsService;
class ManagedUserSharedSettingsServiceFactory
: public BrowserContextKeyedServiceFactory {
public:
static ManagedUserSharedSettingsService* GetForBrowserContext(
content::BrowserContext* profile);
static ManagedUserSharedSettingsServiceFactory* GetInstance();
private:
friend struct DefaultSingletonTraits<ManagedUserSharedSettingsServiceFactory>;
ManagedUserSharedSettingsServiceFactory();
virtual ~ManagedUserSharedSettingsServiceFactory();
// BrowserContextKeyedServiceFactory:
virtual BrowserContextKeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const OVERRIDE;
};
#endif // CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_SERVICE_FACTORY_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_error_factory_mock.h"
#include "sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::DictionaryValue;
using base::FundamentalValue;
using base::StringValue;
using base::Value;
using sync_pb::ManagedUserSharedSettingSpecifics;
using syncer::MANAGED_USER_SHARED_SETTINGS;
using syncer::SyncChange;
using syncer::SyncChangeList;
using syncer::SyncChangeProcessor;
using syncer::SyncData;
using syncer::SyncDataList;
using syncer::SyncError;
using syncer::SyncErrorFactory;
using syncer::SyncMergeResult;
namespace {
class MockChangeProcessor : public syncer::SyncChangeProcessor {
public:
MockChangeProcessor() {}
virtual ~MockChangeProcessor() {}
// SyncChangeProcessor implementation:
virtual syncer::SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) OVERRIDE;
virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
OVERRIDE;
const syncer::SyncChangeList& changes() const { return change_list_; }
private:
syncer::SyncChangeList change_list_;
DISALLOW_COPY_AND_ASSIGN(MockChangeProcessor);
};
syncer::SyncError MockChangeProcessor::ProcessSyncChanges(
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) {
change_list_ = change_list;
return syncer::SyncError();
}
syncer::SyncDataList
MockChangeProcessor::GetAllSyncData(syncer::ModelType type) const {
return syncer::SyncDataList();
}
class MockSyncErrorFactory : public syncer::SyncErrorFactory {
public:
explicit MockSyncErrorFactory(syncer::ModelType type);
virtual ~MockSyncErrorFactory();
// SyncErrorFactory implementation:
virtual syncer::SyncError CreateAndUploadError(
const tracked_objects::Location& location,
const std::string& message) OVERRIDE;
private:
syncer::ModelType type_;
DISALLOW_COPY_AND_ASSIGN(MockSyncErrorFactory);
};
MockSyncErrorFactory::MockSyncErrorFactory(syncer::ModelType type)
: type_(type) {}
MockSyncErrorFactory::~MockSyncErrorFactory() {}
syncer::SyncError MockSyncErrorFactory::CreateAndUploadError(
const tracked_objects::Location& location,
const std::string& message) {
return syncer::SyncError(location, SyncError::DATATYPE_ERROR, message, type_);
}
// Convenience method to allow us to use EXPECT_EQ to compare values.
std::string ToJson(const Value* value) {
if (!value)
return std::string();
std::string json_value;
base::JSONWriter::Write(value, &json_value);
return json_value;
}
} // namespace
class ManagedUserSharedSettingsServiceTest : public ::testing::Test {
protected:
typedef base::CallbackList<void(const std::string&, const std::string&)>
CallbackList;
ManagedUserSharedSettingsServiceTest()
: settings_service_(profile_.GetPrefs()) {}
virtual ~ManagedUserSharedSettingsServiceTest() {}
void StartSyncing(const syncer::SyncDataList& initial_sync_data) {
sync_processor_ = new MockChangeProcessor();
scoped_ptr<syncer::SyncErrorFactory> error_handler(
new MockSyncErrorFactory(MANAGED_USER_SHARED_SETTINGS));
SyncMergeResult result = settings_service_.MergeDataAndStartSyncing(
MANAGED_USER_SHARED_SETTINGS,
initial_sync_data,
scoped_ptr<SyncChangeProcessor>(sync_processor_),
error_handler.Pass());
EXPECT_FALSE(result.error().IsSet());
}
const base::DictionaryValue* GetAllSettings() {
return profile_.GetPrefs()->GetDictionary(
prefs::kManagedUserSharedSettings);
}
void VerifySyncChanges() {
const SyncChangeList& changes = sync_processor_->changes();
for (SyncChangeList::const_iterator it = changes.begin();
it != changes.end();
++it) {
const sync_pb::ManagedUserSharedSettingSpecifics& setting =
it->sync_data().GetSpecifics().managed_user_shared_setting();
EXPECT_EQ(
setting.value(),
ToJson(settings_service_.GetValue(setting.mu_id(), setting.key())));
}
}
// testing::Test overrides:
virtual void SetUp() OVERRIDE {
subscription_ = settings_service_.Subscribe(
base::Bind(&ManagedUserSharedSettingsServiceTest::OnSettingChanged,
base::Unretained(this)));
}
virtual void TearDown() OVERRIDE { settings_service_.Shutdown(); }
void OnSettingChanged(const std::string& mu_id, const std::string& key) {
const Value* value = settings_service_.GetValue(mu_id, key);
ASSERT_TRUE(value);
changed_settings_.push_back(
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
mu_id, key, *value, true));
}
TestingProfile profile_;
ManagedUserSharedSettingsService settings_service_;
SyncDataList changed_settings_;
scoped_ptr<CallbackList::Subscription> subscription_;
// Owned by the ManagedUserSettingsService.
MockChangeProcessor* sync_processor_;
};
TEST_F(ManagedUserSharedSettingsServiceTest, Empty) {
StartSyncing(SyncDataList());
EXPECT_EQ(0u, sync_processor_->changes().size());
EXPECT_EQ(0u, changed_settings_.size());
EXPECT_EQ(
0u,
settings_service_.GetAllSyncData(MANAGED_USER_SHARED_SETTINGS).size());
EXPECT_EQ(0u, GetAllSettings()->size());
}
TEST_F(ManagedUserSharedSettingsServiceTest, SetAndGet) {
StartSyncing(SyncDataList());
const char kIdA[] = "aaaaaa";
const char kIdB[] = "bbbbbb";
const char kIdC[] = "cccccc";
StringValue name("Jack");
FundamentalValue age(8);
StringValue bar("bar");
settings_service_.SetValue(kIdA, "name", name);
ASSERT_EQ(1u, sync_processor_->changes().size());
VerifySyncChanges();
settings_service_.SetValue(kIdA, "age", FundamentalValue(6));
ASSERT_EQ(1u, sync_processor_->changes().size());
VerifySyncChanges();
settings_service_.SetValue(kIdA, "age", age);
ASSERT_EQ(1u, sync_processor_->changes().size());
VerifySyncChanges();
settings_service_.SetValue(kIdB, "foo", bar);
ASSERT_EQ(1u, sync_processor_->changes().size());
VerifySyncChanges();
EXPECT_EQ(
3u,
settings_service_.GetAllSyncData(MANAGED_USER_SHARED_SETTINGS).size());
EXPECT_EQ(ToJson(&name), ToJson(settings_service_.GetValue(kIdA, "name")));
EXPECT_EQ(ToJson(&age), ToJson(settings_service_.GetValue(kIdA, "age")));
EXPECT_EQ(ToJson(&bar), ToJson(settings_service_.GetValue(kIdB, "foo")));
EXPECT_FALSE(settings_service_.GetValue(kIdA, "foo"));
EXPECT_FALSE(settings_service_.GetValue(kIdB, "name"));
EXPECT_FALSE(settings_service_.GetValue(kIdC, "name"));
}
TEST_F(ManagedUserSharedSettingsServiceTest, Merge) {
// Set initial values, then stop syncing so we can restart.
StartSyncing(SyncDataList());
const char kIdA[] = "aaaaaa";
const char kIdB[] = "bbbbbb";
const char kIdC[] = "cccccc";
FundamentalValue age(8);
StringValue bar("bar");
settings_service_.SetValue(kIdA, "name", StringValue("Jack"));
settings_service_.SetValue(kIdA, "age", age);
settings_service_.SetValue(kIdB, "foo", bar);
settings_service_.StopSyncing(MANAGED_USER_SHARED_SETTINGS);
StringValue name("Jill");
StringValue blurp("blurp");
SyncDataList sync_data;
sync_data.push_back(
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
kIdA, "name", name, true));
sync_data.push_back(
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
kIdC, "baz", blurp, true));
StartSyncing(sync_data);
EXPECT_EQ(2u, sync_processor_->changes().size());
VerifySyncChanges();
EXPECT_EQ(2u, changed_settings_.size());
EXPECT_EQ(
4u,
settings_service_.GetAllSyncData(MANAGED_USER_SHARED_SETTINGS).size());
EXPECT_EQ(ToJson(&name),
ToJson(settings_service_.GetValue(kIdA, "name")));
EXPECT_EQ(ToJson(&age), ToJson(settings_service_.GetValue(kIdA, "age")));
EXPECT_EQ(ToJson(&bar), ToJson(settings_service_.GetValue(kIdB, "foo")));
EXPECT_EQ(ToJson(&blurp), ToJson(settings_service_.GetValue(kIdC, "baz")));
EXPECT_FALSE(settings_service_.GetValue(kIdA, "foo"));
EXPECT_FALSE(settings_service_.GetValue(kIdB, "name"));
EXPECT_FALSE(settings_service_.GetValue(kIdC, "name"));
}
TEST_F(ManagedUserSharedSettingsServiceTest, ProcessChanges) {
StartSyncing(SyncDataList());
const char kIdA[] = "aaaaaa";
const char kIdB[] = "bbbbbb";
const char kIdC[] = "cccccc";
FundamentalValue age(8);
StringValue bar("bar");
settings_service_.SetValue(kIdA, "name", StringValue("Jack"));
settings_service_.SetValue(kIdA, "age", age);
settings_service_.SetValue(kIdB, "foo", bar);
StringValue name("Jill");
StringValue blurp("blurp");
SyncChangeList changes;
changes.push_back(
SyncChange(FROM_HERE,
SyncChange::ACTION_UPDATE,
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
kIdA, "name", name, true)));
changes.push_back(
SyncChange(FROM_HERE,
SyncChange::ACTION_ADD,
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
kIdC, "baz", blurp, true)));
SyncError error = settings_service_.ProcessSyncChanges(FROM_HERE, changes);
EXPECT_FALSE(error.IsSet()) << error.ToString();
EXPECT_EQ(2u, changed_settings_.size());
EXPECT_EQ(
4u,
settings_service_.GetAllSyncData(MANAGED_USER_SHARED_SETTINGS).size());
EXPECT_EQ(ToJson(&name),
ToJson(settings_service_.GetValue(kIdA, "name")));
EXPECT_EQ(ToJson(&age), ToJson(settings_service_.GetValue(kIdA, "age")));
EXPECT_EQ(ToJson(&bar), ToJson(settings_service_.GetValue(kIdB, "foo")));
EXPECT_EQ(ToJson(&blurp), ToJson(settings_service_.GetValue(kIdC, "baz")));
EXPECT_FALSE(settings_service_.GetValue(kIdA, "foo"));
EXPECT_FALSE(settings_service_.GetValue(kIdB, "name"));
EXPECT_FALSE(settings_service_.GetValue(kIdC, "name"));
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/managed_mode/managed_user_shared_settings_update.h"
#include "base/bind.h"
#include "base/values.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
ManagedUserSharedSettingsUpdate::ManagedUserSharedSettingsUpdate(
ManagedUserSharedSettingsService* service,
const std::string& mu_id,
const std::string& key,
scoped_ptr<base::Value> value,
const base::Callback<void(bool)>& success_callback)
: service_(service),
mu_id_(mu_id),
key_(key),
value_(value.Pass()),
callback_(success_callback) {
service->SetValueInternal(mu_id, key, *value_, false);
subscription_ = service->Subscribe(
base::Bind(&ManagedUserSharedSettingsUpdate::OnSettingChanged,
base::Unretained(this)));
}
ManagedUserSharedSettingsUpdate::~ManagedUserSharedSettingsUpdate() {}
void ManagedUserSharedSettingsUpdate::OnSettingChanged(const std::string& mu_id,
const std::string& key) {
if (mu_id != mu_id_)
return;
if (key != key_)
return;
const base::Value* value = service_->GetValue(mu_id, key);
callback_.Run(value->Equals(value_.get()));
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_UPDATE_H_
#define CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_UPDATE_H_
#include <string>
#include "base/callback.h"
#include "base/callback_list.h"
#include "base/memory/scoped_ptr.h"
namespace base {
class Value;
}
class ManagedUserSharedSettingsService;
// Lets clients of ManagedUserSharedSettingsService change settings and wait for
// the Sync server to acknowledge the change. The callback passed in the
// constructor will be called with a true success value after the Sync server
// has flipped the acknowledgement flag for the setting. If another client
// changes the value in the mean time, the callback will be run with a false
// success value. If the object is destroyed before that, the callback will not
// be run. Note that any changes made to the setting will not be undone when
// destroying the object, even if the update was not successful or was canceled.
class ManagedUserSharedSettingsUpdate {
public:
ManagedUserSharedSettingsUpdate(
ManagedUserSharedSettingsService* service,
const std::string& mu_id,
const std::string& key,
scoped_ptr<base::Value> value,
const base::Callback<void(bool)>& success_callback);
~ManagedUserSharedSettingsUpdate();
private:
typedef base::CallbackList<void(const std::string&, const std::string&)>
CallbackList;
void OnSettingChanged(const std::string& mu_id,
const std::string& key);
ManagedUserSharedSettingsService* service_;
std::string mu_id_;
std::string key_;
scoped_ptr<base::Value> value_;
base::Callback<void(bool)> callback_;
scoped_ptr<CallbackList::Subscription> subscription_;
};
#endif // CHROME_BROWSER_MANAGED_MODE_MANAGED_USER_SHARED_SETTINGS_UPDATE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_update.h"
#include "chrome/test/base/testing_profile.h"
#include "sync/api/sync_change.h"
#include "testing/gtest/include/gtest/gtest.h"
class ManagedUserSharedSettingsUpdateTest : public testing::Test {
public:
ManagedUserSharedSettingsUpdateTest() : service_(profile_.GetPrefs()) {}
virtual ~ManagedUserSharedSettingsUpdateTest() {}
void OnSettingUpdated(bool success) {
result_.reset(new bool(success));
}
protected:
TestingProfile profile_;
ManagedUserSharedSettingsService service_;
scoped_ptr<bool> result_;
};
TEST_F(ManagedUserSharedSettingsUpdateTest, Success) {
ManagedUserSharedSettingsUpdate update(
&service_,
"abcdef",
"name",
scoped_ptr<base::Value>(new base::StringValue("Hans Moleman")),
base::Bind(&ManagedUserSharedSettingsUpdateTest::OnSettingUpdated,
base::Unretained(this)));
syncer::SyncChangeList changes;
changes.push_back(syncer::SyncChange(
FROM_HERE,
syncer::SyncChange::ACTION_UPDATE,
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
"abcdef", "name", base::StringValue("Hans Moleman"), true)));
syncer::SyncError error = service_.ProcessSyncChanges(FROM_HERE, changes);
EXPECT_FALSE(error.IsSet()) << error.ToString();
ASSERT_TRUE(result_);
EXPECT_TRUE(*result_);
}
TEST_F(ManagedUserSharedSettingsUpdateTest, Failure) {
ManagedUserSharedSettingsUpdate update(
&service_,
"abcdef",
"name",
scoped_ptr<base::Value>(new base::StringValue("Hans Moleman")),
base::Bind(&ManagedUserSharedSettingsUpdateTest::OnSettingUpdated,
base::Unretained(this)));
// Syncing down a different change will cause the update to fail.
syncer::SyncChangeList changes;
changes.push_back(syncer::SyncChange(
FROM_HERE,
syncer::SyncChange::ACTION_UPDATE,
ManagedUserSharedSettingsService::CreateSyncDataForSetting(
"abcdef",
"name",
base::StringValue("Barney Gumble"),
true)));
syncer::SyncError error = service_.ProcessSyncChanges(FROM_HERE, changes);
EXPECT_FALSE(error.IsSet()) << error.ToString();
ASSERT_TRUE(result_);
EXPECT_FALSE(*result_);
}
TEST_F(ManagedUserSharedSettingsUpdateTest, Cancel) {
{
ManagedUserSharedSettingsUpdate update(
&service_,
"abcdef",
"name",
scoped_ptr<base::Value>(new base::StringValue("Hans Moleman")),
base::Bind(&ManagedUserSharedSettingsUpdateTest::OnSettingUpdated,
base::Unretained(this)));
ASSERT_FALSE(result_);
}
ASSERT_FALSE(result_);
}
...@@ -112,6 +112,7 @@ ...@@ -112,6 +112,7 @@
#if defined(ENABLE_MANAGED_USERS) #if defined(ENABLE_MANAGED_USERS)
#include "chrome/browser/managed_mode/managed_user_service.h" #include "chrome/browser/managed_mode/managed_user_service.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "chrome/browser/managed_mode/managed_user_sync_service.h" #include "chrome/browser/managed_mode/managed_user_sync_service.h"
#endif #endif
...@@ -387,6 +388,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { ...@@ -387,6 +388,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
#if defined(ENABLE_MANAGED_USERS) #if defined(ENABLE_MANAGED_USERS)
ManagedUserService::RegisterProfilePrefs(registry); ManagedUserService::RegisterProfilePrefs(registry);
ManagedUserSharedSettingsService::RegisterProfilePrefs(registry);
ManagedUserSyncService::RegisterProfilePrefs(registry); ManagedUserSyncService::RegisterProfilePrefs(registry);
#endif #endif
......
...@@ -72,6 +72,8 @@ ...@@ -72,6 +72,8 @@
#if defined(ENABLE_MANAGED_USERS) #if defined(ENABLE_MANAGED_USERS)
#include "chrome/browser/managed_mode/managed_user_settings_service.h" #include "chrome/browser/managed_mode/managed_user_settings_service.h"
#include "chrome/browser/managed_mode/managed_user_settings_service_factory.h" #include "chrome/browser/managed_mode/managed_user_settings_service_factory.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
#include "chrome/browser/managed_mode/managed_user_shared_settings_service_factory.h"
#include "chrome/browser/managed_mode/managed_user_sync_service.h" #include "chrome/browser/managed_mode/managed_user_sync_service.h"
#include "chrome/browser/managed_mode/managed_user_sync_service_factory.h" #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
#endif #endif
...@@ -227,6 +229,9 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( ...@@ -227,6 +229,9 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
new UIDataTypeController( new UIDataTypeController(
syncer::MANAGED_USERS, this, profile_, pss)); syncer::MANAGED_USERS, this, profile_, pss));
} }
pss->RegisterDataTypeController(
new UIDataTypeController(
syncer::MANAGED_USER_SHARED_SETTINGS, this, profile_, pss));
#endif #endif
} }
...@@ -434,6 +439,9 @@ base::WeakPtr<syncer::SyncableService> ProfileSyncComponentsFactoryImpl:: ...@@ -434,6 +439,9 @@ base::WeakPtr<syncer::SyncableService> ProfileSyncComponentsFactoryImpl::
case syncer::MANAGED_USERS: case syncer::MANAGED_USERS:
return ManagedUserSyncServiceFactory::GetForProfile(profile_)-> return ManagedUserSyncServiceFactory::GetForProfile(profile_)->
AsWeakPtr(); AsWeakPtr();
case syncer::MANAGED_USER_SHARED_SETTINGS:
return ManagedUserSharedSettingsServiceFactory::GetForBrowserContext(
profile_)->AsWeakPtr();
#endif #endif
case syncer::ARTICLES: { case syncer::ARTICLES: {
dom_distiller::DomDistillerService* service = dom_distiller::DomDistillerService* service =
......
...@@ -59,6 +59,7 @@ class ProfileSyncComponentsFactoryImplTest : public testing::Test { ...@@ -59,6 +59,7 @@ class ProfileSyncComponentsFactoryImplTest : public testing::Test {
datatypes.push_back(syncer::FAVICON_IMAGES); datatypes.push_back(syncer::FAVICON_IMAGES);
datatypes.push_back(syncer::SYNCED_NOTIFICATIONS); datatypes.push_back(syncer::SYNCED_NOTIFICATIONS);
datatypes.push_back(syncer::MANAGED_USERS); datatypes.push_back(syncer::MANAGED_USERS);
datatypes.push_back(syncer::MANAGED_USER_SHARED_SETTINGS);
return datatypes; return datatypes;
} }
......
...@@ -1036,6 +1036,12 @@ ...@@ -1036,6 +1036,12 @@
'browser/managed_mode/managed_user_service.h', 'browser/managed_mode/managed_user_service.h',
'browser/managed_mode/managed_user_service_factory.cc', 'browser/managed_mode/managed_user_service_factory.cc',
'browser/managed_mode/managed_user_service_factory.h', 'browser/managed_mode/managed_user_service_factory.h',
'browser/managed_mode/managed_user_shared_settings_service.cc',
'browser/managed_mode/managed_user_shared_settings_service.h',
'browser/managed_mode/managed_user_shared_settings_service_factory.cc',
'browser/managed_mode/managed_user_shared_settings_service_factory.h',
'browser/managed_mode/managed_user_shared_settings_update.cc',
'browser/managed_mode/managed_user_shared_settings_update.h',
'browser/managed_mode/managed_user_sync_service.cc', 'browser/managed_mode/managed_user_sync_service.cc',
'browser/managed_mode/managed_user_sync_service.h', 'browser/managed_mode/managed_user_sync_service.h',
'browser/managed_mode/managed_user_sync_service_factory.cc', 'browser/managed_mode/managed_user_sync_service_factory.cc',
......
...@@ -1006,6 +1006,8 @@ ...@@ -1006,6 +1006,8 @@
'browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc', 'browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc',
'browser/managed_mode/managed_user_registration_utility_unittest.cc', 'browser/managed_mode/managed_user_registration_utility_unittest.cc',
'browser/managed_mode/managed_user_settings_service_unittest.cc', 'browser/managed_mode/managed_user_settings_service_unittest.cc',
'browser/managed_mode/managed_user_shared_settings_service_unittest.cc',
'browser/managed_mode/managed_user_shared_settings_update_unittest.cc',
'browser/managed_mode/supervised_user_pref_store_unittest.cc', 'browser/managed_mode/supervised_user_pref_store_unittest.cc',
'browser/media/desktop_media_list_ash_unittest.cc', 'browser/media/desktop_media_list_ash_unittest.cc',
'browser/media/native_desktop_media_list_unittest.cc', 'browser/media/native_desktop_media_list_unittest.cc',
......
...@@ -47,6 +47,11 @@ const char kManagedUserCustodianEmail[] = "profile.managed.custodian_email"; ...@@ -47,6 +47,11 @@ const char kManagedUserCustodianEmail[] = "profile.managed.custodian_email";
// starts a session. // starts a session.
const char kManagedUserCustodianName[] = "profile.managed.custodian_name"; const char kManagedUserCustodianName[] = "profile.managed.custodian_name";
// Stores settings that can be modified both by a supervised user and their
// manager. See ManagedUserSharedSettingsService for a description of
// the format.
const char kManagedUserSharedSettings[] = "profile.managed.shared_settings";
// An integer that keeps track of the profile icon version. This allows us to // An integer that keeps track of the profile icon version. This allows us to
// determine the state of the profile icon for icon format changes. // determine the state of the profile icon for icon format changes.
const char kProfileIconVersion[] = "profile.icon_version"; const char kProfileIconVersion[] = "profile.icon_version";
......
...@@ -25,6 +25,7 @@ extern const char kManagedModeManualHosts[]; ...@@ -25,6 +25,7 @@ extern const char kManagedModeManualHosts[];
extern const char kManagedModeManualURLs[]; extern const char kManagedModeManualURLs[];
extern const char kManagedUserCustodianEmail[]; extern const char kManagedUserCustodianEmail[];
extern const char kManagedUserCustodianName[]; extern const char kManagedUserCustodianName[];
extern const char kManagedUserSharedSettings[];
extern const char kProfileIconVersion[]; extern const char kProfileIconVersion[];
extern const char kRestoreOnStartup[]; extern const char kRestoreOnStartup[];
extern const char kRestoreOnStartupMigrated[]; extern const char kRestoreOnStartupMigrated[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment