Home | History | Annotate | Download | only in shill
      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:
     55   JsonStoreTest()
     56       : kStringWithEmbeddedNulls({0, 'a', 0, 'z'}),
     57         kNonUtf8String("ab\xc0") {}
     58 
     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 
     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 
     85 void JsonStoreTest::SetVerboseLevel(int new_level) {
     86   ScopeLogger::GetInstance()->set_verbose_level(new_level);
     87 }
     88 
     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.
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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.
    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 
    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 
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    495 TEST_F(JsonStoreTest, ContainsGroupFindsExistingGroup) {
    496   store_->SetBool("group_a", "knob_1", bool());
    497   EXPECT_TRUE(store_->ContainsGroup("group_a"));
    498 }
    499 
    500 TEST_F(JsonStoreTest, ContainsGroupDoesNotFabricateGroups) {
    501   EXPECT_FALSE(store_->ContainsGroup("group_a"));
    502 }
    503 
    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 
    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 
    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.
    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 
    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.
    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 
    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 
    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.
    569 TEST_F(JsonStoreTest, OpenSucceedsOnEmptySettings) {
    570   SetJsonFileContents("{\"settings\": {}}");
    571   EXPECT_TRUE(store_->Open());
    572 }
    573 
    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.
    583 TEST_F(JsonStoreTest, OpenSucceedsOnEmptyGroup) {
    584   SetJsonFileContents(
    585       "{\"settings\": {"
    586       "    \"group_a\": {}"
    587       "}}");
    588   EXPECT_TRUE(store_->Open());
    589 }
    590 
    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.
    606 TEST_F(JsonStoreTest, OpenSucceedsOnSettingWithBooleanValue) {
    607   SetJsonFileContents(
    608       "{\"settings\": {"
    609       "    \"group_a\": {"
    610       "        \"knob_1\": true"
    611       "}}}");
    612   EXPECT_TRUE(store_->Open());
    613 }
    614 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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.
    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.
    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 
    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.
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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.
   1100 TEST_F(JsonStoreTest, MarkAsCorruptedFailsWhenStoreHasNotBeenPersisted) {
   1101   EXPECT_CALL(log_,
   1102               Log(logging::LOG_ERROR, _, HasSubstr("rename failed")));
   1103   EXPECT_FALSE(store_->MarkAsCorrupted());
   1104 }
   1105 
   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