blob: 2f88067d6ded26282fa0716c793c24aea783768b [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "shill/fake_store.h"
#include <typeinfo>
#include <vector>
#include "shill/logging.h"
using std::set;
using std::string;
using std::vector;
namespace shill {
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kStorage;
static string ObjectID(const FakeStore* j) {
return "(unknown)";
}
} // namespace Logging
namespace {
bool DoesGroupContainProperties(
const brillo::VariantDictionary& group,
const brillo::VariantDictionary& required_properties) {
for (const auto& required_property_name_and_value : required_properties) {
const auto& required_key = required_property_name_and_value.first;
const auto& required_value = required_property_name_and_value.second;
const auto& group_it = group.find(required_key);
if (group_it == group.end() || group_it->second != required_value) {
return false;
}
}
return true;
}
} // namespace
FakeStore::FakeStore() = default;
bool FakeStore::IsEmpty() const {
// For now, the choice for return value is arbitrary. Revisit if we
// find tests depend on this behaving correctly. (i.e., if any tests
// require this to return true after a Close().)
return true;
}
bool FakeStore::Open() {
return true;
}
bool FakeStore::Close() {
return true;
}
bool FakeStore::Flush() {
return true;
}
bool FakeStore::MarkAsCorrupted() {
return true;
}
set<string> FakeStore::GetGroups() const {
set<string> matching_groups;
for (const auto& group_name_and_settings : group_name_to_settings_) {
matching_groups.insert(group_name_and_settings.first);
}
return matching_groups;
}
// Returns a set so that caller can easily test whether a particular group
// is contained within this collection.
set<string> FakeStore::GetGroupsWithKey(const string& key) const {
set<string> matching_groups;
// iterate over groups, find ones with matching key
for (const auto& group_name_and_settings : group_name_to_settings_) {
const auto& group_name = group_name_and_settings.first;
const auto& group_settings = group_name_and_settings.second;
if (group_settings.find(key) != group_settings.end()) {
matching_groups.insert(group_name);
}
}
return matching_groups;
}
set<string> FakeStore::GetGroupsWithProperties(
const KeyValueStore& properties) const {
set<string> matching_groups;
const brillo::VariantDictionary& properties_dict(properties.properties());
for (const auto& group_name_and_settings : group_name_to_settings_) {
const auto& group_name = group_name_and_settings.first;
const auto& group_settings = group_name_and_settings.second;
if (DoesGroupContainProperties(group_settings, properties_dict)) {
matching_groups.insert(group_name);
}
}
return matching_groups;
}
bool FakeStore::ContainsGroup(const string& group) const {
const auto& it = group_name_to_settings_.find(group);
return it != group_name_to_settings_.end();
}
bool FakeStore::DeleteKey(const string& group, const string& key) {
const auto& group_name_and_settings = group_name_to_settings_.find(group);
if (group_name_and_settings == group_name_to_settings_.end()) {
LOG(ERROR) << "Could not find group |" << group << "|.";
return false;
}
auto& group_settings = group_name_and_settings->second;
auto property_it = group_settings.find(key);
if (property_it != group_settings.end()) {
group_settings.erase(property_it);
}
return true;
}
bool FakeStore::DeleteGroup(const string& group) {
auto group_name_and_settings = group_name_to_settings_.find(group);
if (group_name_and_settings != group_name_to_settings_.end()) {
group_name_to_settings_.erase(group_name_and_settings);
}
return true;
}
bool FakeStore::SetHeader(const string& header) {
return true;
}
bool FakeStore::GetString(const string& group,
const string& key,
string* value) const {
return ReadSetting(group, key, value);
}
bool FakeStore::SetString(const string& group,
const string& key,
const string& value) {
return WriteSetting(group, key, value);
}
bool FakeStore::GetBool(const string& group,
const string& key,
bool* value) const {
return ReadSetting(group, key, value);
}
bool FakeStore::SetBool(const string& group, const string& key, bool value) {
return WriteSetting(group, key, value);
}
bool FakeStore::GetInt(const string& group,
const string& key,
int* value) const {
return ReadSetting(group, key, value);
}
bool FakeStore::SetInt(const string& group, const string& key, int value) {
return WriteSetting(group, key, value);
}
bool FakeStore::GetUint64(const string& group,
const string& key,
uint64_t* value) const {
return ReadSetting(group, key, value);
}
bool FakeStore::SetUint64(const string& group,
const string& key,
uint64_t value) {
return WriteSetting(group, key, value);
}
bool FakeStore::GetStringList(const string& group,
const string& key,
vector<string>* value) const {
return ReadSetting(group, key, value);
}
bool FakeStore::SetStringList(const string& group,
const string& key,
const vector<string>& value) {
return WriteSetting(group, key, value);
}
bool FakeStore::GetCryptedString(const string& group,
const string& key,
string* value) const {
return GetString(group, key, value);
}
bool FakeStore::SetCryptedString(const string& group,
const string& key,
const string& value) {
return SetString(group, key, value);
}
// Private methods.
template <typename T>
bool FakeStore::ReadSetting(const string& group,
const string& key,
T* out) const {
const auto& group_name_and_settings = group_name_to_settings_.find(group);
if (group_name_and_settings == group_name_to_settings_.end()) {
SLOG(this, 10) << "Could not find group |" << group << "|.";
return false;
}
const auto& group_settings = group_name_and_settings->second;
const auto& property_name_and_value = group_settings.find(key);
if (property_name_and_value == group_settings.end()) {
SLOG(this, 10) << "Could not find property |" << key << "|.";
return false;
}
if (!property_name_and_value->second.IsTypeCompatible<T>()) {
// We assume that the reader and the writer agree on the exact
// type. So we do not allow implicit conversion.
LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<T>()
<< "| from |"
<< property_name_and_value->second.GetUndecoratedTypeName()
<< "|.";
return false;
}
if (out) {
return property_name_and_value->second.GetValue(out);
} else {
return true;
}
}
template <typename T>
bool FakeStore::WriteSetting(const string& group,
const string& key,
const T& new_value) {
auto group_name_and_settings = group_name_to_settings_.find(group);
if (group_name_and_settings == group_name_to_settings_.end()) {
group_name_to_settings_[group][key] = new_value;
return true;
}
auto& group_settings = group_name_and_settings->second;
auto property_name_and_value = group_settings.find(key);
if (property_name_and_value == group_settings.end()) {
group_settings[key] = new_value;
return true;
}
if (!property_name_and_value->second.IsTypeCompatible<T>()) {
SLOG(this, 10) << "New type |" << brillo::GetUndecoratedTypeName<T>()
<< "| differs from current type |"
<< property_name_and_value->second.GetUndecoratedTypeName()
<< "|.";
return false;
} else {
property_name_and_value->second = new_value;
return true;
}
}
} // namespace shill