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/json_store.h"
18
19 #include <array>
20 #include <limits>
21 #include <memory>
22 #include <set>
23 #include <string>
24 #include <utility>
25 #include <vector>
26
27 #include <base/files/file_enumerator.h>
28 #include <base/files/file_util.h>
29 #include <base/files/scoped_temp_dir.h>
30 #include <base/strings/string_util.h>
31 #include <gtest/gtest.h>
32
33 #include "shill/mock_log.h"
34
35 using base::FileEnumerator;
36 using base::FilePath;
37 using base::ScopedTempDir;
38 using std::array;
39 using std::pair;
40 using std::set;
41 using std::string;
42 using std::unique_ptr;
43 using std::vector;
44 using testing::_;
45 using testing::AnyNumber;
46 using testing::ContainsRegex;
47 using testing::HasSubstr;
48 using testing::StartsWith;
49 using testing::Test;
50
51 namespace shill {
52
53 class JsonStoreTest : public Test {
54 public:
JsonStoreTest()55 JsonStoreTest()
56 : kStringWithEmbeddedNulls({0, 'a', 0, 'z'}),
57 kNonUtf8String("ab\xc0") {}
58
SetUp()59 virtual void SetUp() {
60 ScopeLogger::GetInstance()->EnableScopesByName("+storage");
61 ASSERT_FALSE(base::IsStringUTF8(kNonUtf8String));
62 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
63 test_file_ = temp_dir_.path().Append("test-json-store");
64 store_.reset(new JsonStore(test_file_));
65 EXPECT_CALL(log_, Log(_, _, _)).Times(AnyNumber());
66 }
67
TearDown()68 virtual void TearDown() {
69 ScopeLogger::GetInstance()->EnableScopesByName("-storage");
70 ScopeLogger::GetInstance()->set_verbose_level(0);
71 }
72
73 protected:
74 void SetVerboseLevel(int new_level);
75 void SetJsonFileContents(const string& data);
76
77 const string kStringWithEmbeddedNulls;
78 const string kNonUtf8String;
79 ScopedTempDir temp_dir_;
80 FilePath test_file_;
81 unique_ptr<JsonStore> store_;
82 ScopedMockLog log_;
83 };
84
SetVerboseLevel(int new_level)85 void JsonStoreTest::SetVerboseLevel(int new_level) {
86 ScopeLogger::GetInstance()->set_verbose_level(new_level);
87 }
88
SetJsonFileContents(const string & data)89 void JsonStoreTest::SetJsonFileContents(const string& data) {
90 EXPECT_EQ(data.size(),
91 base::WriteFile(test_file_, data.data(), data.size()));
92 }
93
94 // In memory operations: basic storage and retrieval.
TEST_F(JsonStoreTest,StringsCanBeStoredInMemory)95 TEST_F(JsonStoreTest, StringsCanBeStoredInMemory) {
96 const array<string, 5> our_values{
97 {"", "hello", "world\n", kStringWithEmbeddedNulls, kNonUtf8String}};
98 for (const auto& our_value : our_values) {
99 string value_from_store;
100 EXPECT_TRUE(store_->SetString("group_a", "knob_1", our_value));
101 EXPECT_TRUE(store_->GetString("group_a", "knob_1", &value_from_store));
102 EXPECT_EQ(our_value, value_from_store);
103 }
104 }
105
TEST_F(JsonStoreTest,BoolsCanBeStoredInMemory)106 TEST_F(JsonStoreTest, BoolsCanBeStoredInMemory) {
107 const array<bool, 2> our_values{{false, true}};
108 for (const auto& our_value : our_values) {
109 bool value_from_store;
110 EXPECT_TRUE(store_->SetBool("group_a", "knob_1", our_value));
111 EXPECT_TRUE(store_->GetBool("group_a", "knob_1", &value_from_store));
112 EXPECT_EQ(our_value, value_from_store);
113 }
114 }
115
TEST_F(JsonStoreTest,IntsCanBeStoredInMemory)116 TEST_F(JsonStoreTest, IntsCanBeStoredInMemory) {
117 const array<int, 3> our_values{{
118 std::numeric_limits<int>::min(), 0, std::numeric_limits<int>::max()}};
119 for (const auto& our_value : our_values) {
120 int value_from_store;
121 EXPECT_TRUE(store_->SetInt("group_a", "knob_1", our_value));
122 EXPECT_TRUE(store_->GetInt("group_a", "knob_1", &value_from_store));
123 EXPECT_EQ(our_value, value_from_store);
124 }
125 }
126
TEST_F(JsonStoreTest,Uint64sCanBeStoredInMemory)127 TEST_F(JsonStoreTest, Uint64sCanBeStoredInMemory) {
128 const array<uint64_t, 3> our_values{{
129 std::numeric_limits<uint64_t>::min(),
130 0,
131 std::numeric_limits<uint64_t>::max()}};
132 for (const auto& our_value : our_values) {
133 uint64_t value_from_store;
134 EXPECT_TRUE(store_->SetUint64("group_a", "knob_1", our_value));
135 EXPECT_TRUE(store_->GetUint64("group_a", "knob_1", &value_from_store));
136 EXPECT_EQ(our_value, value_from_store);
137 }
138 }
139
TEST_F(JsonStoreTest,StringListsCanBeStoredInMemory)140 TEST_F(JsonStoreTest, StringListsCanBeStoredInMemory) {
141 const array<vector<string>, 7> our_values{{
142 vector<string>{},
143 vector<string>{""},
144 vector<string>{"a"},
145 vector<string>{"", "a"},
146 vector<string>{"a", ""},
147 vector<string>{"", "a", ""},
148 vector<string>{"a", "b", "c", kStringWithEmbeddedNulls, kNonUtf8String}}};
149 for (const auto& our_value : our_values) {
150 vector<string> value_from_store;
151 EXPECT_TRUE(store_->SetStringList("group_a", "knob_1", our_value));
152 EXPECT_TRUE(store_->GetStringList("group_a", "knob_1", &value_from_store));
153 EXPECT_EQ(our_value, value_from_store);
154 }
155 }
156
TEST_F(JsonStoreTest,CryptedStringsCanBeStoredInMemory)157 TEST_F(JsonStoreTest, CryptedStringsCanBeStoredInMemory) {
158 const array<string, 5> our_values{{
159 string(), string("some stuff"), kStringWithEmbeddedNulls, kNonUtf8String
160 }};
161 for (const auto& our_value : our_values) {
162 string value_from_store;
163 EXPECT_TRUE(store_->SetCryptedString("group_a", "knob_1", our_value));
164 EXPECT_TRUE(
165 store_->GetCryptedString("group_a", "knob_1", &value_from_store));
166 EXPECT_EQ(our_value, value_from_store);
167 }
168 }
169
TEST_F(JsonStoreTest,RawValuesOfCryptedStringsDifferFromOriginalValues)170 TEST_F(JsonStoreTest, RawValuesOfCryptedStringsDifferFromOriginalValues) {
171 const array<string, 3> our_values{{
172 string("simple string"), kStringWithEmbeddedNulls, kNonUtf8String
173 }};
174 for (const auto& our_value : our_values) {
175 string raw_value_from_store;
176 EXPECT_TRUE(store_->SetCryptedString("group_a", "knob_1", our_value));
177 EXPECT_TRUE(store_->GetString("group_a", "knob_1", &raw_value_from_store));
178 EXPECT_NE(our_value, raw_value_from_store);
179 }
180 }
181
TEST_F(JsonStoreTest,DifferentGroupsCanHaveDifferentValuesForSameKey)182 TEST_F(JsonStoreTest, DifferentGroupsCanHaveDifferentValuesForSameKey) {
183 store_->SetString("group_a", "knob_1", "value_1");
184 store_->SetString("group_b", "knob_1", "value_2");
185
186 string value_from_store;
187 EXPECT_TRUE(store_->GetString("group_a", "knob_1", &value_from_store));
188 EXPECT_EQ("value_1", value_from_store);
189 EXPECT_TRUE(store_->GetString("group_b", "knob_1", &value_from_store));
190 EXPECT_EQ("value_2", value_from_store);
191 }
192
193 // In memory operations: presence checking.
TEST_F(JsonStoreTest,CanUseNullptrToCheckPresenceOfKey)194 TEST_F(JsonStoreTest, CanUseNullptrToCheckPresenceOfKey) {
195 SetVerboseLevel(10);
196
197 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group"))).Times(6);
198 EXPECT_FALSE(store_->GetString("group_a", "string_knob", nullptr));
199 EXPECT_FALSE(store_->GetBool("group_a", "bool_knob", nullptr));
200 EXPECT_FALSE(store_->GetInt("group_a", "int_knob", nullptr));
201 EXPECT_FALSE(store_->GetUint64("group_a", "uint64_knob", nullptr));
202 EXPECT_FALSE(store_->GetStringList("group_a", "string_list_knob", nullptr));
203 EXPECT_FALSE(
204 store_->GetCryptedString("group_a", "crypted_string_knob", nullptr));
205
206 ASSERT_TRUE(store_->SetString("group_a", "random_knob", "random value"));
207 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find property"))).Times(6);
208 EXPECT_FALSE(store_->GetString("group_a", "string_knob", nullptr));
209 EXPECT_FALSE(store_->GetBool("group_a", "bool_knob", nullptr));
210 EXPECT_FALSE(store_->GetInt("group_a", "int_knob", nullptr));
211 EXPECT_FALSE(store_->GetUint64("group_a", "uint64_knob", nullptr));
212 EXPECT_FALSE(store_->GetStringList("group_a", "string_list_knob", nullptr));
213 EXPECT_FALSE(
214 store_->GetCryptedString("group_a", "crypted_string_knob", nullptr));
215
216 ASSERT_TRUE(store_->SetString("group_a", "string_knob", "stuff goes here"));
217 ASSERT_TRUE(store_->SetBool("group_a", "bool_knob", true));
218 ASSERT_TRUE(store_->SetInt("group_a", "int_knob", -1));
219 ASSERT_TRUE(store_->SetUint64("group_a", "uint64_knob", 1));
220 ASSERT_TRUE(store_->SetStringList(
221 "group_a", "string_list_knob", vector<string>{{"hello"}}));
222 ASSERT_TRUE(
223 store_->SetCryptedString("group_a", "crypted_string_knob", "s3kr!t"));
224
225 EXPECT_TRUE(store_->GetString("group_a", "string_knob", nullptr));
226 EXPECT_TRUE(store_->GetBool("group_a", "bool_knob", nullptr));
227 EXPECT_TRUE(store_->GetInt("group_a", "int_knob", nullptr));
228 EXPECT_TRUE(store_->GetUint64("group_a", "uint64_knob", nullptr));
229 EXPECT_TRUE(store_->GetStringList("group_a", "string_list_knob", nullptr));
230 EXPECT_TRUE(
231 store_->GetCryptedString("group_a", "crypted_string_knob", nullptr));
232 }
233
234 // In memory operations: access to missing elements.
TEST_F(JsonStoreTest,GetFromEmptyStoreFails)235 TEST_F(JsonStoreTest, GetFromEmptyStoreFails) {
236 bool value_from_store;
237 SetVerboseLevel(10);
238 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group")));
239 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", &value_from_store));
240 }
241
TEST_F(JsonStoreTest,GetFromNonexistentGroupAndKeyFails)242 TEST_F(JsonStoreTest, GetFromNonexistentGroupAndKeyFails) {
243 bool value_from_store;
244 SetVerboseLevel(10);
245 EXPECT_TRUE(store_->SetBool("group_a", "knob_1", true));
246 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group")));
247 EXPECT_FALSE(store_->GetBool("group_b", "knob_1", &value_from_store));
248 }
249
TEST_F(JsonStoreTest,GetOfNonexistentPropertyFails)250 TEST_F(JsonStoreTest, GetOfNonexistentPropertyFails) {
251 bool value_from_store;
252 SetVerboseLevel(10);
253 EXPECT_TRUE(store_->SetBool("group_a", "knob_1", true));
254 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find property")));
255 EXPECT_FALSE(store_->GetBool("group_a", "knob_2", &value_from_store));
256 }
257
TEST_F(JsonStoreTest,GetOfPropertyFromWrongGroupFails)258 TEST_F(JsonStoreTest, GetOfPropertyFromWrongGroupFails) {
259 bool value_from_store;
260 SetVerboseLevel(10);
261 EXPECT_TRUE(store_->SetBool("group_a", "knob_1", true));
262 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group")));
263 EXPECT_FALSE(store_->GetBool("group_b", "knob_1", &value_from_store));
264 }
265
TEST_F(JsonStoreTest,GetDoesNotMatchOnValue)266 TEST_F(JsonStoreTest, GetDoesNotMatchOnValue) {
267 string value_from_store;
268 SetVerboseLevel(10);
269 EXPECT_TRUE(store_->SetString("group_a", "knob_1", "value_1"));
270 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find property")));
271 EXPECT_FALSE(store_->GetString("group_a", "value_1", &value_from_store));
272 }
273
274 // In memory operations: type conversions on read.
TEST_F(JsonStoreTest,ConversionFromStringIsProhibited)275 TEST_F(JsonStoreTest, ConversionFromStringIsProhibited) {
276 EXPECT_CALL(
277 log_,
278 Log(logging::LOG_ERROR, _,
279 ContainsRegex("Can not read \\|.+\\| from \\|.+\\|"))).Times(4);
280 EXPECT_TRUE(store_->SetString("group_a", "knob_1", "stuff goes here"));
281 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
282 EXPECT_FALSE(store_->GetInt("group_a", "knob_1", nullptr));
283 EXPECT_FALSE(store_->GetUint64("group_a", "knob_1", nullptr));
284 EXPECT_FALSE(store_->GetStringList("group_a", "knob_1", nullptr));
285 // We deliberately omit checking store_->GetCryptedString(). While
286 // this "works" right now, it's not something we're committed to.
287 }
288
TEST_F(JsonStoreTest,ConversionFromBoolIsProhibited)289 TEST_F(JsonStoreTest, ConversionFromBoolIsProhibited) {
290 EXPECT_CALL(
291 log_,
292 Log(logging::LOG_ERROR, _,
293 ContainsRegex("Can not read \\|.+\\| from \\|.+\\|"))).Times(5);
294 EXPECT_TRUE(store_->SetBool("group_a", "knob_1", true));
295 EXPECT_FALSE(store_->GetString("group_a", "knob_1", nullptr));
296 EXPECT_FALSE(store_->GetInt("group_a", "knob_1", nullptr));
297 EXPECT_FALSE(store_->GetUint64("group_a", "knob_1", nullptr));
298 EXPECT_FALSE(store_->GetStringList("group_a", "knob_1", nullptr));
299 EXPECT_FALSE(store_->GetCryptedString("group_a", "knob_1", nullptr));
300 }
301
TEST_F(JsonStoreTest,ConversionFromIntIsProhibited)302 TEST_F(JsonStoreTest, ConversionFromIntIsProhibited) {
303 EXPECT_CALL(
304 log_,
305 Log(logging::LOG_ERROR, _,
306 ContainsRegex("Can not read \\|.+\\| from \\|.+\\|"))).Times(5);
307 EXPECT_TRUE(store_->SetInt("group_a", "knob_1", -1));
308 EXPECT_FALSE(store_->GetString("group_a", "knob_1", nullptr));
309 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
310 EXPECT_FALSE(store_->GetUint64("group_a", "knob_1", nullptr));
311 EXPECT_FALSE(store_->GetStringList("group_a", "knob_1", nullptr));
312 EXPECT_FALSE(store_->GetCryptedString("group_a", "knob_1", nullptr));
313 }
314
TEST_F(JsonStoreTest,ConversionFromUint64IsProhibited)315 TEST_F(JsonStoreTest, ConversionFromUint64IsProhibited) {
316 EXPECT_CALL(
317 log_,
318 Log(logging::LOG_ERROR, _,
319 ContainsRegex("Can not read \\|.+\\| from \\|.+\\|"))).Times(5);
320 EXPECT_TRUE(store_->SetUint64("group_a", "knob_1", 1));
321 EXPECT_FALSE(store_->GetString("group_a", "knob_1", nullptr));
322 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
323 EXPECT_FALSE(store_->GetInt("group_a", "knob_1", nullptr));
324 EXPECT_FALSE(store_->GetStringList("group_a", "knob_1", nullptr));
325 EXPECT_FALSE(store_->GetCryptedString("group_a", "knob_1", nullptr));
326 }
327
TEST_F(JsonStoreTest,ConversionFromStringListIsProhibited)328 TEST_F(JsonStoreTest, ConversionFromStringListIsProhibited) {
329 EXPECT_CALL(
330 log_,
331 Log(logging::LOG_ERROR, _,
332 ContainsRegex("Can not read \\|.+\\| from \\|.+\\|"))).Times(5);
333 EXPECT_TRUE(store_->SetStringList(
334 "group_a", "knob_1", vector<string>{{"hello"}}));
335 EXPECT_FALSE(store_->GetString("group_a", "knob_1", nullptr));
336 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
337 EXPECT_FALSE(store_->GetInt("group_a", "knob_1", nullptr));
338 EXPECT_FALSE(store_->GetUint64("group_a", "knob_1", nullptr));
339 EXPECT_FALSE(store_->GetCryptedString("group_a", "knob_1", nullptr));
340 }
341
TEST_F(JsonStoreTest,ConversionFromCryptedStringIsProhibited)342 TEST_F(JsonStoreTest, ConversionFromCryptedStringIsProhibited) {
343 EXPECT_CALL(
344 log_,
345 Log(logging::LOG_ERROR, _,
346 ContainsRegex("Can not read \\|.+\\| from \\|.+\\|"))).Times(4);
347 EXPECT_TRUE(store_->SetCryptedString("group_a", "knob_1", "s3kr!t"));
348 // We deliberately omit checking store_->GetString(). While this
349 // "works" right now, it's not something we're committed to.
350 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
351 EXPECT_FALSE(store_->GetInt("group_a", "knob_1", nullptr));
352 EXPECT_FALSE(store_->GetUint64("group_a", "knob_1", nullptr));
353 EXPECT_FALSE(store_->GetStringList("group_a", "knob_1", nullptr));
354 }
355
356 // In memory operations: key deletion.
TEST_F(JsonStoreTest,DeleteKeyDeletesExistingKey)357 TEST_F(JsonStoreTest, DeleteKeyDeletesExistingKey) {
358 SetVerboseLevel(10);
359 store_->SetBool("group_a", "knob_1", bool());
360 EXPECT_TRUE(store_->DeleteKey("group_a", "knob_1"));
361 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find property")));
362 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
363 }
364
TEST_F(JsonStoreTest,DeleteKeyDeletesOnlySpecifiedKey)365 TEST_F(JsonStoreTest, DeleteKeyDeletesOnlySpecifiedKey) {
366 store_->SetBool("group_a", "knob_1", bool());
367 store_->SetBool("group_a", "knob_2", bool());
368 EXPECT_TRUE(store_->DeleteKey("group_a", "knob_1"));
369 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
370 EXPECT_TRUE(store_->GetBool("group_a", "knob_2", nullptr));
371 }
372
TEST_F(JsonStoreTest,DeleteKeySucceedsOnMissingKey)373 TEST_F(JsonStoreTest, DeleteKeySucceedsOnMissingKey) {
374 store_->SetBool("group_a", "knob_1", bool());
375 EXPECT_TRUE(store_->DeleteKey("group_a", "knob_2"));
376 EXPECT_TRUE(store_->GetBool("group_a", "knob_1", nullptr));
377 }
378
TEST_F(JsonStoreTest,DeleteKeyFailsWhenGivenWrongGroup)379 TEST_F(JsonStoreTest, DeleteKeyFailsWhenGivenWrongGroup) {
380 SetVerboseLevel(10);
381 store_->SetBool("group_a", "knob_1", bool());
382 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group")));
383 EXPECT_FALSE(store_->DeleteKey("group_b", "knob_1"));
384 EXPECT_TRUE(store_->GetBool("group_a", "knob_1", nullptr));
385 }
386
387 // In memory operations: group operations.
TEST_F(JsonStoreTest,EmptyStoreReturnsNoGroups)388 TEST_F(JsonStoreTest, EmptyStoreReturnsNoGroups) {
389 EXPECT_EQ(set<string>(), store_->GetGroups());
390 EXPECT_EQ(set<string>(), store_->GetGroupsWithKey("knob_1"));
391 EXPECT_EQ(set<string>(), store_->GetGroupsWithProperties(KeyValueStore()));
392 }
393
TEST_F(JsonStoreTest,GetGroupsReturnsAllGroups)394 TEST_F(JsonStoreTest, GetGroupsReturnsAllGroups) {
395 store_->SetBool("group_a", "knob_1", bool());
396 store_->SetBool("group_b", "knob_1", bool());
397 EXPECT_EQ(set<string>({"group_a", "group_b"}), store_->GetGroups());
398 }
399
TEST_F(JsonStoreTest,GetGroupsWithKeyReturnsAllMatchingGroups)400 TEST_F(JsonStoreTest, GetGroupsWithKeyReturnsAllMatchingGroups) {
401 store_->SetBool("group_a", "knob_1", bool());
402 store_->SetBool("group_b", "knob_1", bool());
403 EXPECT_EQ(set<string>({"group_a", "group_b"}),
404 store_->GetGroupsWithKey("knob_1"));
405 }
406
TEST_F(JsonStoreTest,GetGroupsWithKeyReturnsOnlyMatchingGroups)407 TEST_F(JsonStoreTest, GetGroupsWithKeyReturnsOnlyMatchingGroups) {
408 store_->SetBool("group_a", "knob_1", bool());
409 store_->SetBool("group_b", "knob_2", bool());
410 EXPECT_EQ(set<string>({"group_a"}), store_->GetGroupsWithKey("knob_1"));
411 }
412
TEST_F(JsonStoreTest,GetGroupsWithPropertiesReturnsAllMatchingGroups)413 TEST_F(JsonStoreTest, GetGroupsWithPropertiesReturnsAllMatchingGroups) {
414 store_->SetBool("group_a", "knob_1", true);
415 store_->SetBool("group_b", "knob_1", true);
416
417 KeyValueStore required_properties;
418 required_properties.SetBool("knob_1", true);
419 EXPECT_EQ(set<string>({"group_a", "group_b"}),
420 store_->GetGroupsWithProperties(required_properties));
421 }
422
TEST_F(JsonStoreTest,GetGroupsWithPropertiesReturnsOnlyMatchingGroups)423 TEST_F(JsonStoreTest, GetGroupsWithPropertiesReturnsOnlyMatchingGroups) {
424 store_->SetBool("group_a", "knob_1", true);
425 store_->SetBool("group_b", "knob_1", false);
426
427 KeyValueStore required_properties;
428 required_properties.SetBool("knob_1", true);
429 EXPECT_EQ(set<string>({"group_a"}),
430 store_->GetGroupsWithProperties(required_properties));
431 }
432
TEST_F(JsonStoreTest,GetGroupsWithPropertiesCanMatchOnMultipleProperties)433 TEST_F(JsonStoreTest, GetGroupsWithPropertiesCanMatchOnMultipleProperties) {
434 store_->SetBool("group_a", "knob_1", true);
435 store_->SetBool("group_a", "knob_2", true);
436 store_->SetBool("group_b", "knob_1", true);
437 store_->SetBool("group_b", "knob_2", false);
438
439 KeyValueStore required_properties;
440 required_properties.SetBool("knob_1", true);
441 required_properties.SetBool("knob_2", true);
442 EXPECT_EQ(set<string>({"group_a"}),
443 store_->GetGroupsWithProperties(required_properties));
444 }
445
TEST_F(JsonStoreTest,GetGroupsWithPropertiesChecksValuesForBoolIntAndString)446 TEST_F(JsonStoreTest, GetGroupsWithPropertiesChecksValuesForBoolIntAndString) {
447 // Documentation in StoreInterface says GetGroupsWithProperties
448 // checks only Bool, Int, and String properties. For now, we interpret
449 // that permissively. i.e., checking other types is not guaranteed one
450 // way or the other.
451 //
452 // Said differently: we test that that Bool, Int, and String are
453 // supported. But we don't test that other types are ignored. (In
454 // fact, JsonStore supports filtering on uint64 and StringList as
455 // well. JsonStore does not, however, support filtering on
456 // CryptedStrings.)
457 //
458 // This should be fine, as StoreInterface clients currently only use
459 // String value filtering.
460 const brillo::VariantDictionary exact_matcher({
461 {"knob_1", string("good-string")},
462 {"knob_2", bool{true}},
463 {"knob_3", int{1}},
464 });
465 store_->SetString("group_a", "knob_1", "good-string");
466 store_->SetBool("group_a", "knob_2", true);
467 store_->SetInt("group_a", "knob_3", 1);
468
469 {
470 KeyValueStore correct_properties;
471 KeyValueStore::ConvertFromVariantDictionary(
472 exact_matcher, &correct_properties);
473 EXPECT_EQ(set<string>({"group_a"}),
474 store_->GetGroupsWithProperties(correct_properties));
475 }
476
477 const vector<pair<string, brillo::Any>> bad_matchers({
478 {"knob_1", string("bad-string")},
479 {"knob_2", bool{false}},
480 {"knob_3", int{2}},
481 });
482 for (const auto& match_key_and_value : bad_matchers) {
483 const auto& match_key = match_key_and_value.first;
484 const auto& match_value = match_key_and_value.second;
485 brillo::VariantDictionary bad_matcher_dict(exact_matcher);
486 KeyValueStore bad_properties;
487 bad_matcher_dict[match_key] = match_value;
488 KeyValueStore::ConvertFromVariantDictionary(
489 bad_matcher_dict, &bad_properties);
490 EXPECT_EQ(set<string>(), store_->GetGroupsWithProperties(bad_properties))
491 << "Failing match key: " << match_key;
492 }
493 }
494
TEST_F(JsonStoreTest,ContainsGroupFindsExistingGroup)495 TEST_F(JsonStoreTest, ContainsGroupFindsExistingGroup) {
496 store_->SetBool("group_a", "knob_1", bool());
497 EXPECT_TRUE(store_->ContainsGroup("group_a"));
498 }
499
TEST_F(JsonStoreTest,ContainsGroupDoesNotFabricateGroups)500 TEST_F(JsonStoreTest, ContainsGroupDoesNotFabricateGroups) {
501 EXPECT_FALSE(store_->ContainsGroup("group_a"));
502 }
503
TEST_F(JsonStoreTest,DeleteGroupDeletesExistingGroup)504 TEST_F(JsonStoreTest, DeleteGroupDeletesExistingGroup) {
505 SetVerboseLevel(10);
506 store_->SetBool("group_a", "knob_1", bool());
507 store_->SetBool("group_a", "knob_2", bool());
508 EXPECT_TRUE(store_->DeleteGroup("group_a"));
509 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group"))).Times(2);
510 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
511 EXPECT_FALSE(store_->GetBool("group_a", "knob_2", nullptr));
512 }
513
TEST_F(JsonStoreTest,DeleteGroupDeletesOnlySpecifiedGroup)514 TEST_F(JsonStoreTest, DeleteGroupDeletesOnlySpecifiedGroup) {
515 store_->SetBool("group_a", "knob_1", bool());
516 store_->SetBool("group_b", "knob_1", bool());
517 EXPECT_TRUE(store_->DeleteGroup("group_a"));
518 EXPECT_FALSE(store_->GetBool("group_a", "knob_1", nullptr));
519 EXPECT_TRUE(store_->GetBool("group_b", "knob_1", nullptr));
520 }
521
TEST_F(JsonStoreTest,DeleteGroupSucceedsOnMissingGroup)522 TEST_F(JsonStoreTest, DeleteGroupSucceedsOnMissingGroup) {
523 store_->SetBool("group_a", "knob_1", bool());
524 EXPECT_TRUE(store_->DeleteGroup("group_b"));
525 EXPECT_TRUE(store_->GetBool("group_a", "knob_1", nullptr));
526 }
527
528 // File open: basic file structure.
TEST_F(JsonStoreTest,OpenSucceedsOnNonExistentFile)529 TEST_F(JsonStoreTest, OpenSucceedsOnNonExistentFile) {
530 // If the file does not already exist, we assume the caller will
531 // give us data later.
532 EXPECT_TRUE(store_->Open());
533 }
534
TEST_F(JsonStoreTest,OpenFailsOnNonJsonData)535 TEST_F(JsonStoreTest, OpenFailsOnNonJsonData) {
536 SetJsonFileContents("some random junk");
537 EXPECT_CALL(log_,
538 Log(logging::LOG_ERROR, _,
539 StartsWith("Failed to parse JSON data")));
540 EXPECT_FALSE(store_->Open());
541 }
542
543 // File open: root element handling.
TEST_F(JsonStoreTest,OpenFailsWhenRootIsNonDictionary)544 TEST_F(JsonStoreTest, OpenFailsWhenRootIsNonDictionary) {
545 SetJsonFileContents("\"a string\"");
546 EXPECT_CALL(log_,
547 Log(logging::LOG_ERROR, _,
548 StartsWith("JSON value is not a dictionary")));
549 EXPECT_FALSE(store_->Open());
550 }
551
TEST_F(JsonStoreTest,OpenWarnsOnRootDictionaryWithNonStringDescription)552 TEST_F(JsonStoreTest, OpenWarnsOnRootDictionaryWithNonStringDescription) {
553 SetJsonFileContents("{\"description\": 1}");
554 EXPECT_CALL(
555 log_,
556 Log(logging::LOG_WARNING, _, HasSubstr("|description| is not a string")));
557 store_->Open();
558 }
559
TEST_F(JsonStoreTest,OpenFailsOnRootDictionaryWithoutSettings)560 TEST_F(JsonStoreTest, OpenFailsOnRootDictionaryWithoutSettings) {
561 SetJsonFileContents("{}");
562 EXPECT_CALL(log_,
563 Log(logging::LOG_ERROR, _,
564 StartsWith("Property |settings| is missing")));
565 EXPECT_FALSE(store_->Open());
566 }
567
568 // File open: settings element handling.
TEST_F(JsonStoreTest,OpenSucceedsOnEmptySettings)569 TEST_F(JsonStoreTest, OpenSucceedsOnEmptySettings) {
570 SetJsonFileContents("{\"settings\": {}}");
571 EXPECT_TRUE(store_->Open());
572 }
573
TEST_F(JsonStoreTest,OpenFailsWhenSettingsIsNonDictionary)574 TEST_F(JsonStoreTest, OpenFailsWhenSettingsIsNonDictionary) {
575 SetJsonFileContents("{\"settings\": 1}");
576 EXPECT_CALL(log_,
577 Log(logging::LOG_ERROR, _,
578 StartsWith("Property |settings| is not a dictionary")));
579 EXPECT_FALSE(store_->Open());
580 }
581
582 // File open: group structure.
TEST_F(JsonStoreTest,OpenSucceedsOnEmptyGroup)583 TEST_F(JsonStoreTest, OpenSucceedsOnEmptyGroup) {
584 SetJsonFileContents(
585 "{\"settings\": {"
586 " \"group_a\": {}"
587 "}}");
588 EXPECT_TRUE(store_->Open());
589 }
590
TEST_F(JsonStoreTest,OpenFailsWhenGroupIsNonDictionary)591 TEST_F(JsonStoreTest, OpenFailsWhenGroupIsNonDictionary) {
592 SetJsonFileContents(
593 "{\"settings\": {"
594 " \"group_a\": 1"
595 "}}");
596 EXPECT_CALL(log_,
597 Log(logging::LOG_ERROR, _,
598 StartsWith("Group |group_a| is not a dictionary")));
599 EXPECT_FALSE(store_->Open());
600 }
601
602 // File open: each supported property type (with selected valid
603 // values for each type), ordered by base::Value::Type enum. Types
604 // which are not supported by base::Value are ordered as
605 // TYPE_DICTIONARY.
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithBooleanValue)606 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithBooleanValue) {
607 SetJsonFileContents(
608 "{\"settings\": {"
609 " \"group_a\": {"
610 " \"knob_1\": true"
611 "}}}");
612 EXPECT_TRUE(store_->Open());
613 }
614
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithMinIntegerValue)615 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithMinIntegerValue) {
616 SetJsonFileContents(
617 "{\"settings\": {"
618 " \"group_a\": {"
619 " \"knob_1\": -2147483648" // -2^31
620 "}}}");
621 EXPECT_TRUE(store_->Open());
622 }
623
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithMaxIntegerValue)624 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithMaxIntegerValue) {
625 SetJsonFileContents(
626 "{\"settings\": {"
627 " \"group_a\": {"
628 " \"knob_1\": 2147483647" // 2^31-1
629 "}}}");
630 EXPECT_TRUE(store_->Open());
631 }
632
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithStringValue)633 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithStringValue) {
634 SetJsonFileContents(
635 "{\"settings\": {"
636 " \"group_a\": {"
637 " \"knob_1\": \"this is \\\"a\\\" string\\n\""
638 "}}}");
639 EXPECT_TRUE(store_->Open());
640 }
641
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithEscapedStringValue)642 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithEscapedStringValue) {
643 SetJsonFileContents(
644 "{\"settings\": {"
645 " \"group_a\": {"
646 " \"knob_1\": {"
647 " \"_native_type\": \"non_ascii_string\","
648 " \"_encoded_value\": \"0001020304\""
649 "}}}}");
650 EXPECT_TRUE(store_->Open());
651 }
652
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithMinUint64Value)653 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithMinUint64Value) {
654 SetJsonFileContents(
655 "{\"settings\": {"
656 " \"group_a\": {"
657 " \"knob_1\": {"
658 " \"_native_type\": \"uint64\","
659 " \"_encoded_value\": \"0\"" // 2^64-1
660 "}}}}");
661 EXPECT_TRUE(store_->Open());
662 }
663
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithMaxUint64Value)664 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithMaxUint64Value) {
665 SetJsonFileContents(
666 "{\"settings\": {"
667 " \"group_a\": {"
668 " \"knob_1\": {"
669 " \"_native_type\": \"uint64\","
670 " \"_encoded_value\": \"18446744073709551615\"" // 2^64-1
671 "}}}}");
672 EXPECT_TRUE(store_->Open());
673 }
674
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithEmptyListValue)675 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithEmptyListValue) {
676 // Empty list is presumed to be an empty string list.
677 SetJsonFileContents(
678 "{\"settings\": {"
679 " \"group_a\": {"
680 " \"knob_1\": []"
681 "}}}");
682 EXPECT_TRUE(store_->Open());
683 }
684
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithStringListValueWithSingleItem)685 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithStringListValueWithSingleItem) {
686 SetJsonFileContents(
687 "{\"settings\": {"
688 " \"group_a\": {"
689 " \"knob_1\": [ \"a string\" ]"
690 "}}}");
691 EXPECT_TRUE(store_->Open());
692 }
693
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWithStringListValueWithMultipleItems)694 TEST_F(
695 JsonStoreTest, OpenSucceedsOnSettingWithStringListValueWithMultipleItems) {
696 SetJsonFileContents(
697 "{\"settings\": {"
698 " \"group_a\": {"
699 " \"knob_1\": [ \"string 1\", \"string 2\\n\" ]"
700 "}}}");
701 EXPECT_TRUE(store_->Open());
702 }
703
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWhenStringListHasEscapedItem)704 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWhenStringListHasEscapedItem) {
705 SetJsonFileContents(
706 "{\"settings\": {"
707 " \"group_a\": {"
708 " \"knob_1\": [{"
709 " \"_native_type\": \"non_ascii_string\","
710 " \"_encoded_value\": \"0001020304\""
711 "}]}}}");
712 EXPECT_TRUE(store_->Open());
713 }
714
TEST_F(JsonStoreTest,OpenSucceedsOnSettingWhenStringListHasEscapedAndUnescapedItems)715 TEST_F(JsonStoreTest,
716 OpenSucceedsOnSettingWhenStringListHasEscapedAndUnescapedItems) {
717 SetJsonFileContents(
718 "{\"settings\": {"
719 " \"group_a\": {"
720 " \"knob_1\": ["
721 " {\"_native_type\": \"non_ascii_string\","
722 " \"_encoded_value\": \"0001020304\"},"
723 " \"normal string\""
724 "]}}}");
725 EXPECT_TRUE(store_->Open());
726 }
727
728 // File open: unsupported types, and invalid values. Ordered by
729 // base::Value::Type enum. Types which are supported by JsonStore,
730 // but not directly supported by base::Value, are ordered as
731 // TYPE_DICTIONARY.
TEST_F(JsonStoreTest,OpenFailsOnSettingWithNullValue)732 TEST_F(JsonStoreTest, OpenFailsOnSettingWithNullValue) {
733 SetJsonFileContents(
734 "{\"settings\": {"
735 " \"group_a\": {"
736 " \"knob_1\": null"
737 "}}}");
738 EXPECT_CALL(log_,
739 Log(logging::LOG_ERROR, _,
740 HasSubstr("has unsupported TYPE_NULL")));
741 EXPECT_FALSE(store_->Open());
742 }
743
TEST_F(JsonStoreTest,OpenFailsOnSettingWithBadBooleanValue)744 TEST_F(JsonStoreTest, OpenFailsOnSettingWithBadBooleanValue) {
745 SetJsonFileContents(
746 "{\"settings\": {"
747 " \"group_a\": {"
748 " \"knob_1\": truthy"
749 "}}}");
750 EXPECT_CALL(log_,
751 Log(logging::LOG_ERROR, _, StartsWith("Failed to parse JSON")));
752 EXPECT_FALSE(store_->Open());
753 }
754
TEST_F(JsonStoreTest,OpenFailsOnSettingWithOverlySmallInteger)755 TEST_F(JsonStoreTest, OpenFailsOnSettingWithOverlySmallInteger) {
756 SetJsonFileContents(
757 "{\"settings\": {"
758 " \"group_a\": {"
759 " \"knob_1\": -2147483649" // -2^31-1
760 "}}}");
761 EXPECT_CALL(log_,
762 Log(logging::LOG_ERROR, _, HasSubstr("unsupported TYPE_DOUBLE")));
763 EXPECT_FALSE(store_->Open());
764 }
765
TEST_F(JsonStoreTest,OpenFailsOnSettingWithOverlyLargeInteger)766 TEST_F(JsonStoreTest, OpenFailsOnSettingWithOverlyLargeInteger) {
767 SetJsonFileContents(
768 "{\"settings\": {"
769 " \"group_a\": {"
770 " \"knob_1\": 2147483648" // 2^31
771 "}}}");
772 EXPECT_CALL(log_,
773 Log(logging::LOG_ERROR, _, HasSubstr("unsupported TYPE_DOUBLE")));
774 EXPECT_FALSE(store_->Open());
775 }
776
TEST_F(JsonStoreTest,OpenFailsOnSettingWithDoubleValue)777 TEST_F(JsonStoreTest, OpenFailsOnSettingWithDoubleValue) {
778 SetJsonFileContents(
779 "{\"settings\": {"
780 " \"group_a\": {"
781 " \"knob_1\": 1.234"
782 "}}}");
783 EXPECT_CALL(log_,
784 Log(logging::LOG_ERROR, _, HasSubstr("unsupported TYPE_DOUBLE")));
785 EXPECT_FALSE(store_->Open());
786 }
787
TEST_F(JsonStoreTest,OpenFailsOnSettingWithDictionaryValue)788 TEST_F(JsonStoreTest, OpenFailsOnSettingWithDictionaryValue) {
789 SetJsonFileContents(
790 "{\"settings\": {"
791 " \"group_a\": {"
792 " \"knob_1\": {}"
793 "}}}");
794 EXPECT_CALL(log_,
795 Log(logging::LOG_ERROR, _,
796 HasSubstr("unsupported TYPE_DICTIONARY")));
797 EXPECT_FALSE(store_->Open());
798 }
799
TEST_F(JsonStoreTest,OpenFailsOnSettingWithOverlayLargeUint64Value)800 TEST_F(JsonStoreTest, OpenFailsOnSettingWithOverlayLargeUint64Value) {
801 SetJsonFileContents(
802 "{\"settings\": {"
803 " \"group_a\": {"
804 " \"knob_1\": {"
805 " \"_native_type\": \"uint64\","
806 " \"_encoded_value\": \"18446744073709551616\"" // 2^64
807 "}}}}");
808 EXPECT_CALL(log_,
809 Log(logging::LOG_ERROR, _, StartsWith("Failed to parse uint64")));
810 EXPECT_FALSE(store_->Open());
811 }
812
TEST_F(JsonStoreTest,OpenFailsOnSettingWithOverlaySmallUint64Value)813 TEST_F(JsonStoreTest, OpenFailsOnSettingWithOverlaySmallUint64Value) {
814 SetJsonFileContents(
815 "{\"settings\": {"
816 " \"group_a\": {"
817 " \"knob_1\": {"
818 " \"_native_type\": \"uint64\","
819 " \"_encoded_value\": \"-1\""
820 "}}}}");
821 EXPECT_CALL(log_,
822 Log(logging::LOG_ERROR, _, StartsWith("Failed to parse uint64")));
823 EXPECT_FALSE(store_->Open());
824 }
825
TEST_F(JsonStoreTest,OpenFailsWhenSettingHasEscapedStringWithInvalidHex)826 TEST_F(JsonStoreTest, OpenFailsWhenSettingHasEscapedStringWithInvalidHex) {
827 SetJsonFileContents(
828 "{\"settings\": {"
829 " \"group_a\": {"
830 " \"knob_1\": {"
831 " \"_native_type\": \"non_ascii_string\","
832 " \"_encoded_value\": \"-1\""
833 "}}}}");
834 EXPECT_CALL(log_,
835 Log(logging::LOG_ERROR, _, StartsWith("Failed to decode hex")));
836 EXPECT_FALSE(store_->Open());
837 }
838
TEST_F(JsonStoreTest,OpenFailsWhenSettingHasEscapedStringListItemWithInvalidHex)839 TEST_F(JsonStoreTest,
840 OpenFailsWhenSettingHasEscapedStringListItemWithInvalidHex) {
841 SetJsonFileContents(
842 "{\"settings\": {"
843 " \"group_a\": {"
844 " \"knob_1\": [{"
845 " \"_native_type\": \"non_ascii_string\","
846 " \"_encoded_value\": \"-1\""
847 "}]}}}");
848 EXPECT_CALL(log_,
849 Log(logging::LOG_ERROR, _, StartsWith("Failed to decode hex")));
850 EXPECT_FALSE(store_->Open());
851 }
852
TEST_F(JsonStoreTest,OpenFailsOnCoercedSettingWithBadNativeType)853 TEST_F(JsonStoreTest, OpenFailsOnCoercedSettingWithBadNativeType) {
854 SetJsonFileContents(
855 "{\"settings\": {"
856 " \"group_a\": {"
857 " \"knob_1\": {"
858 " \"_native_type\": true,"
859 " \"_encoded_value\": \"1234\""
860 "}}}}");
861 EXPECT_CALL(log_,
862 Log(logging::LOG_ERROR, _,
863 StartsWith("Property |_native_type| is not a string")));
864 EXPECT_FALSE(store_->Open());
865 }
866
TEST_F(JsonStoreTest,OpenFailsOnCoercedSettingWhenEncodedValueIsNotAString)867 TEST_F(JsonStoreTest, OpenFailsOnCoercedSettingWhenEncodedValueIsNotAString) {
868 SetJsonFileContents(
869 "{\"settings\": {"
870 " \"group_a\": {"
871 " \"knob_1\": {"
872 " \"_native_type\": \"uint64\","
873 " \"_encoded_value\": 1234"
874 "}}}}");
875 EXPECT_CALL(log_,
876 Log(logging::LOG_ERROR, _,
877 StartsWith("Property |_encoded_value| is not a string")));
878 EXPECT_FALSE(store_->Open());
879 }
880
TEST_F(JsonStoreTest,OpenFailsOnSettingWithIntListValue)881 TEST_F(JsonStoreTest, OpenFailsOnSettingWithIntListValue) {
882 SetJsonFileContents(
883 "{\"settings\": {"
884 " \"group_a\": {"
885 " \"knob_1\": [ 1 ]"
886 "}}}");
887 EXPECT_CALL(log_,
888 Log(logging::LOG_ERROR, _,
889 HasSubstr("instead of expected type")));
890 EXPECT_FALSE(store_->Open());
891 }
892
893 // File open: miscellaneous.
TEST_F(JsonStoreTest,OpenClearsExistingInMemoryData)894 TEST_F(JsonStoreTest, OpenClearsExistingInMemoryData) {
895 store_->SetString("group_a", "knob_1", "watch me disappear");
896 ASSERT_TRUE(store_->GetString("group_a", "knob_1", nullptr));
897
898 SetJsonFileContents(
899 "{\"settings\": {"
900 " \"group_a\": {"
901 " \"knob_2\": \"new stuff\""
902 "}}}");
903 ASSERT_TRUE(store_->Open());
904 EXPECT_FALSE(store_->GetString("group_a", "knob_1", nullptr));
905 EXPECT_TRUE(store_->GetString("group_a", "knob_2", nullptr));
906 }
907
TEST_F(JsonStoreTest,OpenClearsExistingInMemoryGroups)908 TEST_F(JsonStoreTest, OpenClearsExistingInMemoryGroups) {
909 store_->SetString("group_a", "knob_1", "watch me disappear");
910 ASSERT_FALSE(store_->GetGroups().empty());
911
912 // In the delete case, we're non-comittal about whether empty groups
913 // are garbage collected. But, in the Open() case, we commit to
914 // fully clearing in-memory data.
915 SetJsonFileContents("{\"settings\": {}}");
916 ASSERT_TRUE(store_->Open());
917 EXPECT_TRUE(store_->GetGroups().empty());
918 }
919
920 // File operations: Close() basic functionality.
TEST_F(JsonStoreTest,ClosePersistsData)921 TEST_F(JsonStoreTest, ClosePersistsData) {
922 ASSERT_FALSE(store_->IsNonEmpty());
923 ASSERT_TRUE(store_->Close());
924
925 // Verify that the file actually got written with the right name.
926 FileEnumerator file_enumerator(temp_dir_.path(),
927 false /* not recursive */,
928 FileEnumerator::FILES);
929 EXPECT_EQ(test_file_.value(), file_enumerator.Next().value());
930
931 // Verify that the profile is a regular file, readable and writeable by the
932 // owner only.
933 FileEnumerator::FileInfo file_info = file_enumerator.GetInfo();
934 EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, file_info.stat().st_mode);
935 }
936
937 // File operations: Flush() basics.
TEST_F(JsonStoreTest,FlushCreatesPersistentStore)938 TEST_F(JsonStoreTest, FlushCreatesPersistentStore) {
939 ASSERT_FALSE(store_->IsNonEmpty());
940 ASSERT_TRUE(store_->Flush());
941
942 // Verify that the file actually got written with the right name.
943 FileEnumerator file_enumerator(temp_dir_.path(),
944 false /* not recursive */,
945 FileEnumerator::FILES);
946 EXPECT_EQ(test_file_.value(), file_enumerator.Next().value());
947
948 // Verify that the profile is a regular file, readable and writeable by the
949 // owner only.
950 FileEnumerator::FileInfo file_info = file_enumerator.GetInfo();
951 EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, file_info.stat().st_mode);
952 }
953
TEST_F(JsonStoreTest,FlushFailsWhenPathIsNotWriteable)954 TEST_F(JsonStoreTest, FlushFailsWhenPathIsNotWriteable) {
955 ASSERT_TRUE(base::CreateDirectory(test_file_));
956 EXPECT_CALL(log_,
957 Log(logging::LOG_ERROR, _, StartsWith("Failed to write")));
958 EXPECT_FALSE(store_->Flush());
959 }
960
961 // File operations: writing.
962 //
963 // The ordering of groups, and the ordering of keys within a group,
964 // are decided by the JSON writer. Hence, we can not simply compare
965 // the written data to an expected literal value.
966 //
967 // Instead, we write the data out, and verify that reading the data
968 // yields the same groups, keys, and values.
TEST_F(JsonStoreTest,CanPersistAndRestoreHeader)969 TEST_F(JsonStoreTest, CanPersistAndRestoreHeader) {
970 store_->SetHeader("rosetta stone");
971 ASSERT_EQ("rosetta stone", store_->file_description_);
972 store_->Flush();
973
974 JsonStore persisted_data(test_file_);
975 persisted_data.Open();
976 EXPECT_EQ(
977 store_->file_description_, persisted_data.file_description_);
978 }
979
TEST_F(JsonStoreTest,CanPersistAndRestoreAllTypes)980 TEST_F(JsonStoreTest, CanPersistAndRestoreAllTypes) {
981 store_->SetString("group_a", "string_knob", "our string");
982 store_->SetBool("group_a", "bool_knob", true);
983 store_->SetInt("group_a", "int_knob", 1);
984 store_->SetUint64(
985 "group_a", "uint64_knob", std::numeric_limits<uint64_t>::max());
986 store_->SetStringList(
987 "group_a", "stringlist_knob", vector<string>{"a", "b", "c"});
988 store_->SetCryptedString("group_a", "cryptedstring_knob", "s3kr!t");
989 store_->Flush();
990
991 JsonStore persisted_data(test_file_);
992 persisted_data.Open();
993 EXPECT_EQ(
994 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
995 }
996
TEST_F(JsonStoreTest,CanPersistAndRestoreNonUtf8Strings)997 TEST_F(JsonStoreTest, CanPersistAndRestoreNonUtf8Strings) {
998 store_->SetString("group_a", "string_knob", kNonUtf8String);
999 store_->Flush();
1000
1001 JsonStore persisted_data(test_file_);
1002 persisted_data.Open();
1003 EXPECT_EQ(
1004 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
1005 }
1006
TEST_F(JsonStoreTest,CanPersistAndRestoreNonUtf8StringList)1007 TEST_F(JsonStoreTest, CanPersistAndRestoreNonUtf8StringList) {
1008 store_->SetStringList(
1009 "group_a", "string_knob", vector<string>({kNonUtf8String}));
1010 store_->Flush();
1011
1012 JsonStore persisted_data(test_file_);
1013 persisted_data.Open();
1014 EXPECT_EQ(
1015 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
1016 }
1017
TEST_F(JsonStoreTest,CanPersistAndRestoreStringsWithEmbeddedNulls)1018 TEST_F(JsonStoreTest, CanPersistAndRestoreStringsWithEmbeddedNulls) {
1019 store_->SetString("group_a", "string_knob", kStringWithEmbeddedNulls);
1020 store_->Flush();
1021
1022 JsonStore persisted_data(test_file_);
1023 persisted_data.Open();
1024 EXPECT_EQ(
1025 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
1026 }
1027
TEST_F(JsonStoreTest,CanPersistAndRestoreStringListWithEmbeddedNulls)1028 TEST_F(JsonStoreTest, CanPersistAndRestoreStringListWithEmbeddedNulls) {
1029 store_->SetStringList(
1030 "group_a", "string_knob", vector<string>({kStringWithEmbeddedNulls}));
1031 store_->Flush();
1032
1033 JsonStore persisted_data(test_file_);
1034 persisted_data.Open();
1035 EXPECT_EQ(
1036 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
1037 }
1038
TEST_F(JsonStoreTest,CanPersistAndRestoreMultipleGroups)1039 TEST_F(JsonStoreTest, CanPersistAndRestoreMultipleGroups) {
1040 store_->SetString("group_a", "knob_1", "first string");
1041 store_->SetString("group_b", "knob_2", "second string");
1042 store_->Flush();
1043
1044 JsonStore persisted_data(test_file_);
1045 persisted_data.Open();
1046 EXPECT_EQ(
1047 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
1048 }
1049
TEST_F(JsonStoreTest,CanPersistAndRestoreMultipleGroupsWithSameKeys)1050 TEST_F(JsonStoreTest, CanPersistAndRestoreMultipleGroupsWithSameKeys) {
1051 store_->SetString("group_a", "knob_1", "first string");
1052 store_->SetString("group_a", "knob_2", "second string");
1053 store_->SetString("group_b", "knob_1", "frist post!");
1054 store_->SetStringList("group_b", "knob_2", vector<string>{"2nd try"});
1055 store_->Flush();
1056
1057 JsonStore persisted_data(test_file_);
1058 persisted_data.Open();
1059 EXPECT_EQ(
1060 store_->group_name_to_settings_, persisted_data.group_name_to_settings_);
1061 }
1062
TEST_F(JsonStoreTest,CanDeleteKeyFromPersistedData)1063 TEST_F(JsonStoreTest, CanDeleteKeyFromPersistedData) {
1064 store_->SetString("group_a", "knob_1", "first string");
1065 store_->Flush();
1066
1067 JsonStore persisted_data_v1(test_file_);
1068 persisted_data_v1.Open();
1069 ASSERT_TRUE(persisted_data_v1.GetString("group_a", "knob_1", nullptr));
1070 store_->DeleteKey("group_a", "knob_1");
1071 store_->Flush();
1072
1073 JsonStore persisted_data_v2(test_file_);
1074 SetVerboseLevel(10);
1075 // Whether an empty group is written or not is an implementation
1076 // detail. Hence, we don't care if the error message is about a
1077 // missing group, or a missing property.
1078 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find")));
1079 EXPECT_FALSE(persisted_data_v2.GetString("group_a", "knob_1", nullptr));
1080 }
1081
TEST_F(JsonStoreTest,CanDeleteGroupFromPersistedData)1082 TEST_F(JsonStoreTest, CanDeleteGroupFromPersistedData) {
1083 store_->SetString("group_a", "knob_1", "first string");
1084 store_->Flush();
1085
1086 JsonStore persisted_data_v1(test_file_);
1087 persisted_data_v1.Open();
1088 ASSERT_TRUE(persisted_data_v1.GetString("group_a", "knob_1", nullptr));
1089 store_->DeleteGroup("group_a");
1090 store_->Flush();
1091
1092 JsonStore persisted_data_v2(test_file_);
1093 SetVerboseLevel(10);
1094 persisted_data_v2.Open();
1095 EXPECT_CALL(log_, Log(_, _, HasSubstr("Could not find group")));
1096 EXPECT_FALSE(persisted_data_v2.GetString("group_a", "knob_1", nullptr));
1097 }
1098
1099 // File operations: file management.
TEST_F(JsonStoreTest,MarkAsCorruptedFailsWhenStoreHasNotBeenPersisted)1100 TEST_F(JsonStoreTest, MarkAsCorruptedFailsWhenStoreHasNotBeenPersisted) {
1101 EXPECT_CALL(log_,
1102 Log(logging::LOG_ERROR, _, HasSubstr("rename failed")));
1103 EXPECT_FALSE(store_->MarkAsCorrupted());
1104 }
1105
TEST_F(JsonStoreTest,MarkAsCorruptedMovesCorruptStore)1106 TEST_F(JsonStoreTest, MarkAsCorruptedMovesCorruptStore) {
1107 store_->Flush();
1108 ASSERT_TRUE(store_->IsNonEmpty());
1109 ASSERT_TRUE(base::PathExists(test_file_));
1110
1111 EXPECT_TRUE(store_->MarkAsCorrupted());
1112 EXPECT_FALSE(store_->IsNonEmpty());
1113 EXPECT_FALSE(base::PathExists(test_file_));
1114 EXPECT_TRUE(base::PathExists(FilePath(test_file_.value() + ".corrupted")));
1115 }
1116
1117 } // namespace shill
1118