Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 "content/browser/leveldb_wrapper_impl.h" | |
| 6 | |
| 7 #include "base/debug/stack_trace.h" | |
| 8 | |
| 9 #include "components/leveldb/public/cpp/util.h" | |
| 10 #include "content/public/test/test_browser_thread_bundle.h" | |
| 11 #include "testing/gtest/include/gtest/gtest.h" | |
| 12 | |
| 13 using leveldb::StdStringToUint8Vector; | |
| 14 using leveldb::Uint8VectorToStdString; | |
| 15 | |
| 16 namespace content { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 const char* kTestPrefix = "abc"; | |
| 21 const char* kTestSource = "source"; | |
| 22 const size_t kTestSizeLimit = 512; | |
| 23 | |
| 24 leveldb::mojom::KeyValuePtr CreateKeyValue(std::vector<uint8_t> key, | |
| 25 std::vector<uint8_t> value) { | |
| 26 leveldb::mojom::KeyValuePtr result = leveldb::mojom::KeyValue::New(); | |
| 27 result->key = std::move(key); | |
| 28 result->value = std::move(value); | |
| 29 return result; | |
| 30 } | |
| 31 | |
| 32 base::StringPiece ToStringPiece(const std::vector<uint8_t> data) { | |
| 33 return base::StringPiece(reinterpret_cast<const char*>(data.data()), | |
| 34 data.size()); | |
| 35 } | |
| 36 | |
| 37 bool StartsWith(const std::vector<uint8_t>& key, | |
| 38 const std::vector<uint8_t>& prefix) { | |
| 39 return base::StartsWith(ToStringPiece(key), ToStringPiece(prefix), | |
| 40 base::CompareCase::SENSITIVE); | |
| 41 } | |
| 42 | |
| 43 class MockLevelDBDatabase : public leveldb::mojom::LevelDBDatabase { | |
| 44 public: | |
| 45 explicit MockLevelDBDatabase( | |
|
jam
2016/12/19 19:19:09
nit: no need for explicit
Marijn Kruisselbrink
2016/12/20 01:19:46
Why not? It's a single argument constructor.
| |
| 46 std::map<std::vector<uint8_t>, std::vector<uint8_t>>* mock_data) | |
| 47 : mock_data_(*mock_data) {} | |
| 48 | |
| 49 void Put(const std::vector<uint8_t>& key, | |
| 50 const std::vector<uint8_t>& value, | |
| 51 const PutCallback& callback) override { | |
| 52 FAIL(); | |
| 53 } | |
| 54 | |
| 55 void Delete(const std::vector<uint8_t>& key, | |
| 56 const DeleteCallback& callback) override { | |
| 57 FAIL(); | |
| 58 } | |
| 59 | |
| 60 void DeletePrefixed(const std::vector<uint8_t>& key_prefix, | |
| 61 const DeletePrefixedCallback& callback) override { | |
| 62 FAIL(); | |
| 63 } | |
| 64 | |
| 65 void Write(std::vector<leveldb::mojom::BatchedOperationPtr> operations, | |
| 66 const WriteCallback& callback) override { | |
| 67 for (const auto& op : operations) { | |
| 68 switch (op->type) { | |
| 69 case leveldb::mojom::BatchOperationType::PUT_KEY: | |
| 70 mock_data_[op->key] = *op->value; | |
| 71 break; | |
| 72 case leveldb::mojom::BatchOperationType::DELETE_KEY: | |
| 73 mock_data_.erase(op->key); | |
| 74 break; | |
| 75 case leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY: | |
| 76 FAIL(); | |
| 77 break; | |
| 78 } | |
| 79 } | |
| 80 callback.Run(leveldb::mojom::DatabaseError::OK); | |
| 81 } | |
| 82 | |
| 83 void Get(const std::vector<uint8_t>& key, | |
| 84 const GetCallback& callback) override { | |
| 85 FAIL(); | |
| 86 } | |
| 87 | |
| 88 void GetPrefixed(const std::vector<uint8_t>& key_prefix, | |
| 89 const GetPrefixedCallback& callback) override { | |
| 90 std::vector<leveldb::mojom::KeyValuePtr> data; | |
| 91 for (const auto& row : mock_data_) { | |
| 92 if (StartsWith(row.first, key_prefix)) { | |
| 93 data.push_back(CreateKeyValue(row.first, row.second)); | |
| 94 } | |
| 95 } | |
| 96 callback.Run(leveldb::mojom::DatabaseError::OK, std::move(data)); | |
| 97 } | |
| 98 | |
| 99 void GetSnapshot(const GetSnapshotCallback& callback) override { FAIL(); } | |
| 100 | |
| 101 void ReleaseSnapshot(const base::UnguessableToken& snapshot) override { | |
| 102 FAIL(); | |
| 103 } | |
| 104 | |
| 105 void GetFromSnapshot(const base::UnguessableToken& snapshot, | |
| 106 const std::vector<uint8_t>& key, | |
| 107 const GetCallback& callback) override { | |
| 108 FAIL(); | |
| 109 } | |
| 110 | |
| 111 void NewIterator(const NewIteratorCallback& callback) override { FAIL(); } | |
| 112 | |
| 113 void NewIteratorFromSnapshot( | |
| 114 const base::UnguessableToken& snapshot, | |
| 115 const NewIteratorFromSnapshotCallback& callback) override { | |
| 116 FAIL(); | |
| 117 } | |
| 118 | |
| 119 void ReleaseIterator(const base::UnguessableToken& iterator) override { | |
| 120 FAIL(); | |
| 121 } | |
| 122 | |
| 123 void IteratorSeekToFirst( | |
| 124 const base::UnguessableToken& iterator, | |
| 125 const IteratorSeekToFirstCallback& callback) override { | |
| 126 FAIL(); | |
| 127 } | |
| 128 | |
| 129 void IteratorSeekToLast(const base::UnguessableToken& iterator, | |
| 130 const IteratorSeekToLastCallback& callback) override { | |
| 131 FAIL(); | |
| 132 } | |
| 133 | |
| 134 void IteratorSeek(const base::UnguessableToken& iterator, | |
| 135 const std::vector<uint8_t>& target, | |
| 136 const IteratorSeekToLastCallback& callback) override { | |
| 137 FAIL(); | |
| 138 } | |
| 139 | |
| 140 void IteratorNext(const base::UnguessableToken& iterator, | |
| 141 const IteratorNextCallback& callback) override { | |
| 142 FAIL(); | |
| 143 } | |
| 144 | |
| 145 void IteratorPrev(const base::UnguessableToken& iterator, | |
| 146 const IteratorPrevCallback& callback) override { | |
| 147 FAIL(); | |
| 148 } | |
| 149 | |
| 150 private: | |
| 151 std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data_; | |
| 152 }; | |
| 153 | |
| 154 void NoOp() {} | |
| 155 | |
| 156 void GetCallback(bool* called, | |
| 157 bool* success_out, | |
| 158 std::vector<uint8_t>* value_out, | |
| 159 bool success, | |
| 160 const std::vector<uint8_t>& value) { | |
| 161 *called = true; | |
| 162 *success_out = success; | |
| 163 *value_out = value; | |
| 164 } | |
| 165 | |
| 166 void GetAllCallback(bool* called, | |
| 167 leveldb::mojom::DatabaseError* status_out, | |
| 168 std::vector<mojom::KeyValuePtr>* data_out, | |
| 169 leveldb::mojom::DatabaseError status, | |
| 170 std::vector<mojom::KeyValuePtr> data) { | |
| 171 *called = true; | |
| 172 *status_out = status; | |
| 173 *data_out = std::move(data); | |
| 174 } | |
| 175 | |
| 176 void SuccessCallback(bool* called, bool* success_out, bool success) { | |
| 177 *called = true; | |
| 178 *success_out = success; | |
| 179 } | |
| 180 | |
| 181 void NoOpSuccess(bool success) {} | |
| 182 | |
| 183 } // namespace | |
| 184 | |
| 185 class LevelDBWrapperImplTest : public testing::Test { | |
| 186 public: | |
| 187 LevelDBWrapperImplTest() | |
| 188 : db_(&mock_data_), | |
| 189 level_db_wrapper_(&db_, | |
| 190 kTestPrefix, | |
| 191 kTestSizeLimit, | |
| 192 base::TimeDelta::FromSeconds(5), | |
| 193 10 * 1024 * 1024 /* max_bytes_per_hour */, | |
| 194 60 /* max_commits_per_hour */, | |
| 195 base::Bind(&NoOp)) { | |
| 196 set_mock_data(std::string(kTestPrefix) + "def", "defdata"); | |
| 197 set_mock_data(std::string(kTestPrefix) + "123", "123data"); | |
| 198 set_mock_data("123", "baddata"); | |
| 199 } | |
| 200 | |
| 201 void set_mock_data(const std::string& key, const std::string& value) { | |
| 202 mock_data_[StdStringToUint8Vector(key)] = StdStringToUint8Vector(value); | |
| 203 } | |
| 204 | |
| 205 bool has_mock_data(const std::string& key) { | |
| 206 return mock_data_.find(StdStringToUint8Vector(key)) != mock_data_.end(); | |
| 207 } | |
| 208 | |
| 209 std::string get_mock_data(const std::string& key) { | |
| 210 return has_mock_data(key) | |
| 211 ? Uint8VectorToStdString(mock_data_[StdStringToUint8Vector(key)]) | |
| 212 : ""; | |
| 213 } | |
| 214 | |
| 215 mojom::LevelDBWrapper* wrapper() { return &level_db_wrapper_; } | |
| 216 | |
| 217 void CommitChanges() { | |
| 218 ASSERT_TRUE(level_db_wrapper_.commit_batch_); | |
| 219 level_db_wrapper_.CommitChanges(); | |
| 220 } | |
| 221 | |
| 222 private: | |
| 223 TestBrowserThreadBundle thread_bundle_; | |
| 224 std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_; | |
| 225 MockLevelDBDatabase db_; | |
| 226 LevelDBWrapperImpl level_db_wrapper_; | |
| 227 }; | |
| 228 | |
| 229 TEST_F(LevelDBWrapperImplTest, GetLoadedFromMap) { | |
| 230 bool called = false; | |
| 231 bool success; | |
| 232 std::vector<uint8_t> result; | |
| 233 wrapper()->Get(StdStringToUint8Vector("123"), | |
| 234 base::Bind(&GetCallback, &called, &success, &result)); | |
| 235 ASSERT_TRUE(called); | |
| 236 EXPECT_TRUE(success); | |
| 237 EXPECT_EQ(StdStringToUint8Vector("123data"), result); | |
| 238 | |
| 239 called = false; | |
| 240 wrapper()->Get(StdStringToUint8Vector("x"), | |
| 241 base::Bind(&GetCallback, &called, &success, &result)); | |
| 242 ASSERT_TRUE(called); | |
| 243 EXPECT_FALSE(success); | |
| 244 } | |
| 245 | |
| 246 TEST_F(LevelDBWrapperImplTest, GetFromPutOverwrite) { | |
| 247 std::vector<uint8_t> key = StdStringToUint8Vector("123"); | |
| 248 std::vector<uint8_t> value = StdStringToUint8Vector("foo"); | |
| 249 | |
| 250 bool called = false; | |
| 251 bool success; | |
| 252 wrapper()->Put(key, value, kTestSource, | |
| 253 base::Bind(&SuccessCallback, &called, &success)); | |
| 254 ASSERT_TRUE(called); | |
| 255 EXPECT_TRUE(success); | |
| 256 | |
| 257 called = false; | |
| 258 std::vector<uint8_t> result; | |
| 259 wrapper()->Get(key, base::Bind(&GetCallback, &called, &success, &result)); | |
| 260 ASSERT_TRUE(called); | |
| 261 EXPECT_TRUE(success); | |
| 262 EXPECT_EQ(value, result); | |
| 263 } | |
| 264 | |
| 265 TEST_F(LevelDBWrapperImplTest, GetFromPutNewKey) { | |
| 266 std::vector<uint8_t> key = StdStringToUint8Vector("newkey"); | |
| 267 std::vector<uint8_t> value = StdStringToUint8Vector("foo"); | |
| 268 | |
| 269 bool called = false; | |
| 270 bool success; | |
| 271 wrapper()->Put(key, value, kTestSource, | |
| 272 base::Bind(&SuccessCallback, &called, &success)); | |
| 273 ASSERT_TRUE(called); | |
| 274 EXPECT_TRUE(success); | |
| 275 | |
| 276 called = false; | |
| 277 std::vector<uint8_t> result; | |
| 278 wrapper()->Get(key, base::Bind(&GetCallback, &called, &success, &result)); | |
| 279 ASSERT_TRUE(called); | |
| 280 EXPECT_TRUE(success); | |
| 281 EXPECT_EQ(value, result); | |
| 282 } | |
| 283 | |
| 284 TEST_F(LevelDBWrapperImplTest, GetAll) { | |
| 285 bool called = false; | |
| 286 leveldb::mojom::DatabaseError status; | |
| 287 std::vector<mojom::KeyValuePtr> data; | |
| 288 wrapper()->GetAll(kTestSource, | |
| 289 base::Bind(&GetAllCallback, &called, &status, &data)); | |
| 290 ASSERT_TRUE(called); | |
| 291 EXPECT_EQ(leveldb::mojom::DatabaseError::OK, status); | |
| 292 EXPECT_EQ(2u, data.size()); | |
| 293 } | |
| 294 | |
| 295 TEST_F(LevelDBWrapperImplTest, CommitPutToDB) { | |
| 296 std::string key1 = "123"; | |
| 297 std::string value1 = "foo"; | |
| 298 std::string key2 = "abc"; | |
| 299 std::string value2 = "data abc"; | |
| 300 | |
| 301 wrapper()->Put(StdStringToUint8Vector(key1), StdStringToUint8Vector(value1), | |
| 302 kTestSource, base::Bind(&NoOpSuccess)); | |
| 303 wrapper()->Put(StdStringToUint8Vector(key2), | |
| 304 StdStringToUint8Vector("old value"), kTestSource, | |
| 305 base::Bind(&NoOpSuccess)); | |
| 306 wrapper()->Put(StdStringToUint8Vector(key2), StdStringToUint8Vector(value2), | |
| 307 kTestSource, base::Bind(&NoOpSuccess)); | |
| 308 | |
| 309 CommitChanges(); | |
| 310 | |
| 311 EXPECT_TRUE(has_mock_data(kTestPrefix + key1)); | |
| 312 EXPECT_EQ(value1, get_mock_data(kTestPrefix + key1)); | |
| 313 EXPECT_TRUE(has_mock_data(kTestPrefix + key2)); | |
| 314 EXPECT_EQ(value2, get_mock_data(kTestPrefix + key2)); | |
| 315 } | |
| 316 | |
| 317 } // namespace content | |
| OLD | NEW |