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