//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#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() {}
bool FakeStore::IsNonEmpty() 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 false;
}
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) {
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