1 //
2 // Copyright (C) 2015 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "shill/fake_store.h"
18 
19 #include <typeinfo>
20 #include <vector>
21 
22 #include "shill/logging.h"
23 
24 using std::set;
25 using std::string;
26 using std::vector;
27 
28 namespace shill {
29 
30 namespace Logging {
31 
32 static auto kModuleLogScope = ScopeLogger::kStorage;
ObjectID(const FakeStore * j)33 static string ObjectID(const FakeStore* j) {
34   return "(unknown)";
35 }
36 
37 }  // namespace Logging
38 
39 namespace {
40 
DoesGroupContainProperties(const brillo::VariantDictionary & group,const brillo::VariantDictionary & required_properties)41 bool DoesGroupContainProperties(
42     const brillo::VariantDictionary& group,
43     const brillo::VariantDictionary& required_properties) {
44   for (const auto& required_property_name_and_value : required_properties) {
45     const auto& required_key = required_property_name_and_value.first;
46     const auto& required_value = required_property_name_and_value.second;
47     const auto& group_it = group.find(required_key);
48     if (group_it == group.end() || group_it->second != required_value) {
49       return false;
50     }
51   }
52   return true;
53 }
54 
55 }  // namespace
56 
FakeStore()57 FakeStore::FakeStore() {}
58 
IsNonEmpty() const59 bool FakeStore::IsNonEmpty() const {
60   // For now, the choice for return value is arbitrary. Revisit if we
61   // find tests depend on this behaving correctly. (i.e., if any tests
62   // require this to return true after a Close().)
63   return false;
64 }
65 
Open()66 bool FakeStore::Open() {
67   return true;
68 }
69 
Close()70 bool FakeStore::Close() {
71   return true;
72 }
73 
Flush()74 bool FakeStore::Flush() {
75   return true;
76 }
77 
MarkAsCorrupted()78 bool FakeStore::MarkAsCorrupted() {
79   return true;
80 }
81 
GetGroups() const82 set<string> FakeStore::GetGroups() const {
83   set<string> matching_groups;
84   for (const auto& group_name_and_settings : group_name_to_settings_) {
85     matching_groups.insert(group_name_and_settings.first);
86   }
87   return matching_groups;
88 }
89 
90 // Returns a set so that caller can easily test whether a particular group
91 // is contained within this collection.
GetGroupsWithKey(const string & key) const92 set<string> FakeStore::GetGroupsWithKey(const string& key) const {
93   set<string> matching_groups;
94   // iterate over groups, find ones with matching key
95   for (const auto& group_name_and_settings : group_name_to_settings_) {
96     const auto& group_name = group_name_and_settings.first;
97     const auto& group_settings = group_name_and_settings.second;
98     if (group_settings.find(key) != group_settings.end()) {
99       matching_groups.insert(group_name);
100     }
101   }
102   return matching_groups;
103 }
104 
GetGroupsWithProperties(const KeyValueStore & properties) const105 set<string> FakeStore::GetGroupsWithProperties(const KeyValueStore& properties)
106     const {
107   set<string> matching_groups;
108   const brillo::VariantDictionary& properties_dict(properties.properties());
109   for (const auto& group_name_and_settings : group_name_to_settings_) {
110     const auto& group_name = group_name_and_settings.first;
111     const auto& group_settings = group_name_and_settings.second;
112     if (DoesGroupContainProperties(group_settings, properties_dict)) {
113       matching_groups.insert(group_name);
114     }
115   }
116   return matching_groups;
117 }
118 
ContainsGroup(const string & group) const119 bool FakeStore::ContainsGroup(const string& group) const {
120   const auto& it = group_name_to_settings_.find(group);
121   return it != group_name_to_settings_.end();
122 }
123 
DeleteKey(const string & group,const string & key)124 bool FakeStore::DeleteKey(const string& group, const string& key) {
125   const auto& group_name_and_settings = group_name_to_settings_.find(group);
126   if (group_name_and_settings == group_name_to_settings_.end()) {
127     LOG(ERROR) << "Could not find group |" << group << "|.";
128     return false;
129   }
130 
131   auto& group_settings = group_name_and_settings->second;
132   auto property_it = group_settings.find(key);
133   if (property_it != group_settings.end()) {
134     group_settings.erase(property_it);
135   }
136 
137   return true;
138 }
139 
DeleteGroup(const string & group)140 bool FakeStore::DeleteGroup(const string& group) {
141   auto group_name_and_settings = group_name_to_settings_.find(group);
142   if (group_name_and_settings != group_name_to_settings_.end()) {
143     group_name_to_settings_.erase(group_name_and_settings);
144   }
145   return true;
146 }
147 
SetHeader(const string & header)148 bool FakeStore::SetHeader(const string& header) {
149   return true;
150 }
151 
GetString(const string & group,const string & key,string * value) const152 bool FakeStore::GetString(const string& group,
153                           const string& key,
154                           string* value) const {
155   return ReadSetting(group, key, value);
156 }
157 
SetString(const string & group,const string & key,const string & value)158 bool FakeStore::SetString(
159     const string& group, const string& key, const string& value) {
160   return WriteSetting(group, key, value);
161 }
162 
GetBool(const string & group,const string & key,bool * value) const163 bool FakeStore::GetBool(const string& group, const string& key, bool* value)
164     const {
165   return ReadSetting(group, key, value);
166 }
167 
SetBool(const string & group,const string & key,bool value)168 bool FakeStore::SetBool(const string& group, const string& key, bool value) {
169   return WriteSetting(group, key, value);
170 }
171 
GetInt(const string & group,const string & key,int * value) const172 bool FakeStore::GetInt(
173     const string& group, const string& key, int* value) const {
174   return ReadSetting(group, key, value);
175 }
176 
SetInt(const string & group,const string & key,int value)177 bool FakeStore::SetInt(const string& group, const string& key, int value) {
178   return WriteSetting(group, key, value);
179 }
180 
GetUint64(const string & group,const string & key,uint64_t * value) const181 bool FakeStore::GetUint64(
182     const string& group, const string& key, uint64_t* value) const {
183   return ReadSetting(group, key, value);
184 }
185 
SetUint64(const string & group,const string & key,uint64_t value)186 bool FakeStore::SetUint64(
187     const string& group, const string& key, uint64_t value) {
188   return WriteSetting(group, key, value);
189 }
190 
GetStringList(const string & group,const string & key,vector<string> * value) const191 bool FakeStore::GetStringList(
192     const string& group, const string& key, vector<string>* value) const {
193   return ReadSetting(group, key, value);
194 }
195 
SetStringList(const string & group,const string & key,const vector<string> & value)196 bool FakeStore::SetStringList(
197     const string& group, const string& key, const vector<string>& value) {
198   return WriteSetting(group, key, value);
199 }
200 
GetCryptedString(const string & group,const string & key,string * value)201 bool FakeStore::GetCryptedString(
202     const string& group, const string& key, string* value) {
203   return GetString(group, key, value);
204 }
205 
SetCryptedString(const string & group,const string & key,const string & value)206 bool FakeStore::SetCryptedString(
207     const string& group, const string& key, const string& value) {
208   return SetString(group, key, value);
209 }
210 
211 // Private methods.
212 template<typename T>
ReadSetting(const string & group,const string & key,T * out) const213 bool FakeStore::ReadSetting(
214     const string& group, const string& key, T* out) const {
215   const auto& group_name_and_settings = group_name_to_settings_.find(group);
216   if (group_name_and_settings == group_name_to_settings_.end()) {
217     SLOG(this, 10) << "Could not find group |" << group << "|.";
218     return false;
219   }
220 
221   const auto& group_settings = group_name_and_settings->second;
222   const auto& property_name_and_value = group_settings.find(key);
223   if (property_name_and_value == group_settings.end()) {
224     SLOG(this, 10) << "Could not find property |" << key << "|.";
225     return false;
226   }
227 
228   if (!property_name_and_value->second.IsTypeCompatible<T>()) {
229     // We assume that the reader and the writer agree on the exact
230     // type. So we do not allow implicit conversion.
231     LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<T>()
232                << "| from |"
233                << property_name_and_value->second.GetUndecoratedTypeName()
234                << "|.";
235     return false;
236   }
237 
238   if (out) {
239     return property_name_and_value->second.GetValue(out);
240   } else {
241     return true;
242   }
243 }
244 
245 template<typename T>
WriteSetting(const string & group,const string & key,const T & new_value)246 bool FakeStore::WriteSetting(
247     const string& group, const string& key, const T& new_value) {
248   auto group_name_and_settings = group_name_to_settings_.find(group);
249   if (group_name_and_settings == group_name_to_settings_.end()) {
250     group_name_to_settings_[group][key] = new_value;
251     return true;
252   }
253 
254   auto& group_settings = group_name_and_settings->second;
255   auto property_name_and_value = group_settings.find(key);
256   if (property_name_and_value == group_settings.end()) {
257     group_settings[key] = new_value;
258     return true;
259   }
260 
261   if (!property_name_and_value->second.IsTypeCompatible<T>()) {
262     SLOG(this, 10) << "New type |" << brillo::GetUndecoratedTypeName<T>()
263                    << "| differs from current type |"
264                    << property_name_and_value->second.GetUndecoratedTypeName()
265                    << "|.";
266     return false;
267   } else {
268     property_name_and_value->second = new_value;
269     return true;
270   }
271 }
272 
273 }  // namespace shill
274