leveldb_value_store_unittest.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <memory>
  6. #include "base/files/file_enumerator.h"
  7. #include "base/files/file_util.h"
  8. #include "base/files/scoped_temp_dir.h"
  9. #include "base/memory/ref_counted.h"
  10. #include "base/test/task_environment.h"
  11. #include "base/values.h"
  12. #include "components/value_store/leveldb_value_store.h"
  13. #include "components/value_store/value_store_test_suite.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "third_party/leveldatabase/src/include/leveldb/db.h"
  16. #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
  17. namespace value_store {
  18. namespace {
  19. const char kDatabaseUMAClientName[] = "Test";
  20. ValueStore* Param(const base::FilePath& file_path) {
  21. return new LeveldbValueStore(kDatabaseUMAClientName, file_path);
  22. }
  23. } // namespace
  24. INSTANTIATE_TEST_SUITE_P(LeveldbValueStore,
  25. ValueStoreTestSuite,
  26. testing::Values(&Param));
  27. class LeveldbValueStoreUnitTest : public testing::Test {
  28. public:
  29. LeveldbValueStoreUnitTest() = default;
  30. ~LeveldbValueStoreUnitTest() override = default;
  31. protected:
  32. void SetUp() override {
  33. ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
  34. CreateStore();
  35. ASSERT_TRUE(store_->Get().status().ok());
  36. }
  37. void TearDown() override {
  38. if (!store_)
  39. return;
  40. store_->Clear();
  41. CloseStore();
  42. }
  43. void CloseStore() { store_.reset(); }
  44. void CreateStore() {
  45. store_ = std::make_unique<LeveldbValueStore>(kDatabaseUMAClientName,
  46. database_path());
  47. }
  48. LeveldbValueStore* store() { return store_.get(); }
  49. const base::FilePath& database_path() { return database_dir_.GetPath(); }
  50. private:
  51. base::test::TaskEnvironment task_environment_;
  52. std::unique_ptr<LeveldbValueStore> store_;
  53. base::ScopedTempDir database_dir_;
  54. };
  55. // Check that we can restore a single corrupted key in the LeveldbValueStore.
  56. TEST_F(LeveldbValueStoreUnitTest, RestoreKeyTest) {
  57. const char kNotCorruptKey[] = "not-corrupt";
  58. const char kValue[] = "value";
  59. // Insert a valid pair.
  60. std::unique_ptr<base::Value> value(new base::Value(kValue));
  61. ASSERT_TRUE(
  62. store()->Set(ValueStore::DEFAULTS, kNotCorruptKey, *value).status().ok());
  63. // Insert a corrupt pair.
  64. const char kCorruptKey[] = "corrupt";
  65. leveldb::WriteBatch batch;
  66. batch.Put(kCorruptKey, "[{(.*+\"\'\\");
  67. ASSERT_TRUE(store()->WriteToDbForTest(&batch));
  68. // Verify corruption (the first Get will return corruption).
  69. ValueStore::ReadResult result = store()->Get(kCorruptKey);
  70. ASSERT_FALSE(result.status().ok());
  71. ASSERT_EQ(ValueStore::CORRUPTION, result.status().code);
  72. // Verify restored (was deleted in the first Get).
  73. result = store()->Get(kCorruptKey);
  74. EXPECT_TRUE(result.status().ok())
  75. << "Get result not OK: " << result.status().message;
  76. EXPECT_TRUE(result.settings().empty());
  77. // Verify that the valid pair is still present.
  78. result = store()->Get(kNotCorruptKey);
  79. EXPECT_TRUE(result.status().ok());
  80. const std::string* value_string =
  81. result.settings().FindString(kNotCorruptKey);
  82. ASSERT_TRUE(value_string);
  83. EXPECT_EQ(kValue, *value_string);
  84. }
  85. // Test that the Restore() method does not just delete the entire database
  86. // (unless absolutely necessary), and instead only removes corrupted keys.
  87. TEST_F(LeveldbValueStoreUnitTest, RestoreDoesMinimumNecessary) {
  88. const char* kNotCorruptKeys[] = {"a", "n", "z"};
  89. const char kCorruptKey1[] = "f";
  90. const char kCorruptKey2[] = "s";
  91. const char kValue[] = "value";
  92. const char kCorruptValue[] = "[{(.*+\"\'\\";
  93. // Insert a collection of non-corrupted pairs.
  94. std::unique_ptr<base::Value> value(new base::Value(kValue));
  95. for (auto* kNotCorruptKey : kNotCorruptKeys) {
  96. ASSERT_TRUE(store()
  97. ->Set(ValueStore::DEFAULTS, kNotCorruptKey, *value)
  98. .status()
  99. .ok());
  100. }
  101. // Insert a few corrupted pairs.
  102. leveldb::WriteBatch batch;
  103. batch.Put(kCorruptKey1, kCorruptValue);
  104. batch.Put(kCorruptKey2, kCorruptValue);
  105. ASSERT_TRUE(store()->WriteToDbForTest(&batch));
  106. // Verify that we broke it and that it was repaired by the value store.
  107. ValueStore::ReadResult result = store()->Get();
  108. ASSERT_FALSE(result.status().ok());
  109. ASSERT_EQ(ValueStore::CORRUPTION, result.status().code);
  110. ASSERT_EQ(ValueStore::VALUE_RESTORE_DELETE_SUCCESS,
  111. result.status().restore_status);
  112. // We should still have all valid pairs present in the database.
  113. std::string* value_string;
  114. for (auto* kNotCorruptKey : kNotCorruptKeys) {
  115. result = store()->Get(kNotCorruptKey);
  116. EXPECT_TRUE(result.status().ok());
  117. ASSERT_EQ(ValueStore::RESTORE_NONE, result.status().restore_status);
  118. value_string = result.settings().FindString(kNotCorruptKey);
  119. ASSERT_TRUE(value_string);
  120. EXPECT_EQ(kValue, *value_string);
  121. }
  122. }
  123. // Test that the LeveldbValueStore can recover in the case of a CATastrophic
  124. // failure and we have total corruption. In this case, the database is plagued
  125. // by LolCats.
  126. // Full corruption has been known to happen occasionally in strange edge cases,
  127. // such as after users use Windows Restore. We can't prevent it, but we need to
  128. // be able to handle it smoothly.
  129. TEST_F(LeveldbValueStoreUnitTest, RestoreFullDatabase) {
  130. const std::string kLolCats("I can haz leveldb filez?");
  131. const char* kNotCorruptKeys[] = {"a", "n", "z"};
  132. const char kValue[] = "value";
  133. // Generate a database.
  134. std::unique_ptr<base::Value> value(new base::Value(kValue));
  135. for (auto* kNotCorruptKey : kNotCorruptKeys) {
  136. ASSERT_TRUE(store()
  137. ->Set(ValueStore::DEFAULTS, kNotCorruptKey, *value)
  138. .status()
  139. .ok());
  140. }
  141. // Close it (so we remove the lock), and replace all files with LolCats.
  142. CloseStore();
  143. base::FileEnumerator enumerator(database_path(), true /* recursive */,
  144. base::FileEnumerator::FILES);
  145. for (base::FilePath file = enumerator.Next(); !file.empty();
  146. file = enumerator.Next()) {
  147. // WriteFile() failure is a result of -1.
  148. ASSERT_NE(base::WriteFile(file, kLolCats.c_str(), kLolCats.length()), -1);
  149. }
  150. CreateStore();
  151. // We couldn't recover anything, but we should be in a sane state again.
  152. ValueStore::ReadResult result = store()->Get();
  153. ASSERT_EQ(ValueStore::DB_RESTORE_REPAIR_SUCCESS,
  154. result.status().restore_status);
  155. EXPECT_TRUE(result.status().ok());
  156. EXPECT_EQ(0u, result.settings().size());
  157. }
  158. } // namespace value_store