• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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