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 5#include "extensions/browser/value_store/value_store_unittest.h" 6 7#include "base/files/file_enumerator.h" 8#include "base/files/file_util.h" 9#include "base/files/scoped_temp_dir.h" 10#include "base/memory/ref_counted.h" 11#include "base/message_loop/message_loop.h" 12#include "base/values.h" 13#include "content/public/test/test_browser_thread_bundle.h" 14#include "extensions/browser/value_store/leveldb_value_store.h" 15#include "testing/gtest/include/gtest/gtest.h" 16#include "third_party/leveldatabase/src/include/leveldb/db.h" 17#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 18 19namespace { 20 21ValueStore* Param(const base::FilePath& file_path) { 22 return new LeveldbValueStore(file_path); 23} 24 25} // namespace 26 27INSTANTIATE_TEST_CASE_P( 28 LeveldbValueStore, 29 ValueStoreTest, 30 testing::Values(&Param)); 31 32class LeveldbValueStoreUnitTest : public testing::Test { 33 public: 34 LeveldbValueStoreUnitTest() {} 35 virtual ~LeveldbValueStoreUnitTest() {} 36 37 protected: 38 virtual void SetUp() OVERRIDE { 39 ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); 40 OpenStore(); 41 ASSERT_FALSE(store_->Get()->HasError()); 42 } 43 44 virtual void TearDown() OVERRIDE { 45 store_->Clear(); 46 store_.reset(); 47 } 48 49 void CloseStore() { store_.reset(); } 50 51 void OpenStore() { store_.reset(new LeveldbValueStore(database_path())); } 52 53 LeveldbValueStore* store() { return store_.get(); } 54 const base::FilePath& database_path() { return database_dir_.path(); } 55 56 private: 57 scoped_ptr<LeveldbValueStore> store_; 58 base::ScopedTempDir database_dir_; 59 60 content::TestBrowserThreadBundle thread_bundle_; 61}; 62 63// Check that we can restore a single corrupted key in the LeveldbValueStore. 64TEST_F(LeveldbValueStoreUnitTest, RestoreKeyTest) { 65 const char kNotCorruptKey[] = "not-corrupt"; 66 const char kValue[] = "value"; 67 68 // Insert a valid pair. 69 scoped_ptr<base::Value> value(new base::StringValue(kValue)); 70 ASSERT_FALSE( 71 store()->Set(ValueStore::DEFAULTS, kNotCorruptKey, *value)->HasError()); 72 73 // Insert a corrupt pair. 74 const char kCorruptKey[] = "corrupt"; 75 leveldb::WriteBatch batch; 76 batch.Put(kCorruptKey, "[{(.*+\"\'\\"); 77 ASSERT_TRUE(store()->WriteToDbForTest(&batch)); 78 79 // Verify corruption. 80 ValueStore::ReadResult result = store()->Get(kCorruptKey); 81 ASSERT_TRUE(result->HasError()); 82 ASSERT_EQ(ValueStore::CORRUPTION, result->error().code); 83 84 // Restore and verify. 85 ASSERT_TRUE(store()->RestoreKey(kCorruptKey)); 86 result = store()->Get(kCorruptKey); 87 EXPECT_FALSE(result->HasError()); 88 EXPECT_TRUE(result->settings().empty()); 89 90 // Verify that the valid pair is still present. 91 result = store()->Get(kNotCorruptKey); 92 EXPECT_FALSE(result->HasError()); 93 EXPECT_TRUE(result->settings().HasKey(kNotCorruptKey)); 94 std::string value_string; 95 EXPECT_TRUE(result->settings().GetString(kNotCorruptKey, &value_string)); 96 EXPECT_EQ(kValue, value_string); 97} 98 99// Test that the Restore() method does not just delete the entire database 100// (unless absolutely necessary), and instead only removes corrupted keys. 101TEST_F(LeveldbValueStoreUnitTest, RestoreDoesMinimumNecessary) { 102 const char* kNotCorruptKeys[] = {"a", "n", "z"}; 103 const size_t kNotCorruptKeysSize = 3u; 104 const char kCorruptKey1[] = "f"; 105 const char kCorruptKey2[] = "s"; 106 const char kValue[] = "value"; 107 const char kCorruptValue[] = "[{(.*+\"\'\\"; 108 109 // Insert a collection of non-corrupted pairs. 110 scoped_ptr<base::Value> value(new base::StringValue(kValue)); 111 for (size_t i = 0; i < kNotCorruptKeysSize; ++i) { 112 ASSERT_FALSE(store() 113 ->Set(ValueStore::DEFAULTS, kNotCorruptKeys[i], *value) 114 ->HasError()); 115 } 116 117 // Insert a few corrupted pairs. 118 leveldb::WriteBatch batch; 119 batch.Put(kCorruptKey1, kCorruptValue); 120 batch.Put(kCorruptKey2, kCorruptValue); 121 ASSERT_TRUE(store()->WriteToDbForTest(&batch)); 122 123 // Verify that we broke it, and then fix it. 124 ValueStore::ReadResult result = store()->Get(); 125 ASSERT_TRUE(result->HasError()); 126 ASSERT_EQ(ValueStore::CORRUPTION, result->error().code); 127 128 ASSERT_TRUE(store()->Restore()); 129 130 // We should still have all valid pairs present in the database. 131 std::string value_string; 132 for (size_t i = 0; i < kNotCorruptKeysSize; ++i) { 133 result = store()->Get(kNotCorruptKeys[i]); 134 EXPECT_FALSE(result->HasError()); 135 EXPECT_TRUE(result->settings().HasKey(kNotCorruptKeys[i])); 136 EXPECT_TRUE( 137 result->settings().GetString(kNotCorruptKeys[i], &value_string)); 138 EXPECT_EQ(kValue, value_string); 139 } 140} 141 142// Test that the LeveldbValueStore can recover in the case of a CATastrophic 143// failure and we have total corruption. In this case, the database is plagued 144// by LolCats. 145// Full corruption has been known to happen occasionally in strange edge cases, 146// such as after users use Windows Restore. We can't prevent it, but we need to 147// be able to handle it smoothly. 148TEST_F(LeveldbValueStoreUnitTest, RestoreFullDatabase) { 149 const std::string kLolCats("I can haz leveldb filez?"); 150 const char* kNotCorruptKeys[] = {"a", "n", "z"}; 151 const size_t kNotCorruptKeysSize = 3u; 152 const char kValue[] = "value"; 153 154 // Generate a database. 155 scoped_ptr<base::Value> value(new base::StringValue(kValue)); 156 for (size_t i = 0; i < kNotCorruptKeysSize; ++i) { 157 ASSERT_FALSE(store() 158 ->Set(ValueStore::DEFAULTS, kNotCorruptKeys[i], *value) 159 ->HasError()); 160 } 161 162 // Close it (so we remove the lock), and replace all files with LolCats. 163 CloseStore(); 164 base::FileEnumerator enumerator( 165 database_path(), true /* recursive */, base::FileEnumerator::FILES); 166 for (base::FilePath file = enumerator.Next(); !file.empty(); 167 file = enumerator.Next()) { 168 // WriteFile() failure is a result of -1. 169 ASSERT_NE(base::WriteFile(file, kLolCats.c_str(), kLolCats.length()), 170 -1); 171 } 172 OpenStore(); 173 174 // We should definitely have an error. 175 ValueStore::ReadResult result = store()->Get(); 176 ASSERT_TRUE(result->HasError()); 177 ASSERT_EQ(ValueStore::CORRUPTION, result->error().code); 178 179 ASSERT_TRUE(store()->Restore()); 180 result = store()->Get(); 181 EXPECT_FALSE(result->HasError()); 182 // We couldn't recover anything, but we should be in a sane state again. 183 EXPECT_EQ(0u, result->settings().size()); 184} 185