Chromium Code Reviews| Index: content/browser/leveldb_wrapper_impl_unittest.cc |
| diff --git a/content/browser/leveldb_wrapper_impl_unittest.cc b/content/browser/leveldb_wrapper_impl_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..579690e78a49b3b9b96ca6f02f77a9e8a28ff9c9 |
| --- /dev/null |
| +++ b/content/browser/leveldb_wrapper_impl_unittest.cc |
| @@ -0,0 +1,317 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/leveldb_wrapper_impl.h" |
| + |
| +#include "base/debug/stack_trace.h" |
| + |
| +#include "components/leveldb/public/cpp/util.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +using leveldb::StdStringToUint8Vector; |
| +using leveldb::Uint8VectorToStdString; |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +const char* kTestPrefix = "abc"; |
| +const char* kTestSource = "source"; |
| +const size_t kTestSizeLimit = 512; |
| + |
| +leveldb::mojom::KeyValuePtr CreateKeyValue(std::vector<uint8_t> key, |
| + std::vector<uint8_t> value) { |
| + leveldb::mojom::KeyValuePtr result = leveldb::mojom::KeyValue::New(); |
| + result->key = std::move(key); |
| + result->value = std::move(value); |
| + return result; |
| +} |
| + |
| +base::StringPiece ToStringPiece(const std::vector<uint8_t> data) { |
| + return base::StringPiece(reinterpret_cast<const char*>(data.data()), |
| + data.size()); |
| +} |
| + |
| +bool StartsWith(const std::vector<uint8_t>& key, |
| + const std::vector<uint8_t>& prefix) { |
| + return base::StartsWith(ToStringPiece(key), ToStringPiece(prefix), |
| + base::CompareCase::SENSITIVE); |
| +} |
| + |
| +class MockLevelDBDatabase : public leveldb::mojom::LevelDBDatabase { |
| + public: |
| + 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.
|
| + std::map<std::vector<uint8_t>, std::vector<uint8_t>>* mock_data) |
| + : mock_data_(*mock_data) {} |
| + |
| + void Put(const std::vector<uint8_t>& key, |
| + const std::vector<uint8_t>& value, |
| + const PutCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void Delete(const std::vector<uint8_t>& key, |
| + const DeleteCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void DeletePrefixed(const std::vector<uint8_t>& key_prefix, |
| + const DeletePrefixedCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void Write(std::vector<leveldb::mojom::BatchedOperationPtr> operations, |
| + const WriteCallback& callback) override { |
| + for (const auto& op : operations) { |
| + switch (op->type) { |
| + case leveldb::mojom::BatchOperationType::PUT_KEY: |
| + mock_data_[op->key] = *op->value; |
| + break; |
| + case leveldb::mojom::BatchOperationType::DELETE_KEY: |
| + mock_data_.erase(op->key); |
| + break; |
| + case leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY: |
| + FAIL(); |
| + break; |
| + } |
| + } |
| + callback.Run(leveldb::mojom::DatabaseError::OK); |
| + } |
| + |
| + void Get(const std::vector<uint8_t>& key, |
| + const GetCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void GetPrefixed(const std::vector<uint8_t>& key_prefix, |
| + const GetPrefixedCallback& callback) override { |
| + std::vector<leveldb::mojom::KeyValuePtr> data; |
| + for (const auto& row : mock_data_) { |
| + if (StartsWith(row.first, key_prefix)) { |
| + data.push_back(CreateKeyValue(row.first, row.second)); |
| + } |
| + } |
| + callback.Run(leveldb::mojom::DatabaseError::OK, std::move(data)); |
| + } |
| + |
| + void GetSnapshot(const GetSnapshotCallback& callback) override { FAIL(); } |
| + |
| + void ReleaseSnapshot(const base::UnguessableToken& snapshot) override { |
| + FAIL(); |
| + } |
| + |
| + void GetFromSnapshot(const base::UnguessableToken& snapshot, |
| + const std::vector<uint8_t>& key, |
| + const GetCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void NewIterator(const NewIteratorCallback& callback) override { FAIL(); } |
| + |
| + void NewIteratorFromSnapshot( |
| + const base::UnguessableToken& snapshot, |
| + const NewIteratorFromSnapshotCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void ReleaseIterator(const base::UnguessableToken& iterator) override { |
| + FAIL(); |
| + } |
| + |
| + void IteratorSeekToFirst( |
| + const base::UnguessableToken& iterator, |
| + const IteratorSeekToFirstCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void IteratorSeekToLast(const base::UnguessableToken& iterator, |
| + const IteratorSeekToLastCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void IteratorSeek(const base::UnguessableToken& iterator, |
| + const std::vector<uint8_t>& target, |
| + const IteratorSeekToLastCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void IteratorNext(const base::UnguessableToken& iterator, |
| + const IteratorNextCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + void IteratorPrev(const base::UnguessableToken& iterator, |
| + const IteratorPrevCallback& callback) override { |
| + FAIL(); |
| + } |
| + |
| + private: |
| + std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data_; |
| +}; |
| + |
| +void NoOp() {} |
| + |
| +void GetCallback(bool* called, |
| + bool* success_out, |
| + std::vector<uint8_t>* value_out, |
| + bool success, |
| + const std::vector<uint8_t>& value) { |
| + *called = true; |
| + *success_out = success; |
| + *value_out = value; |
| +} |
| + |
| +void GetAllCallback(bool* called, |
| + leveldb::mojom::DatabaseError* status_out, |
| + std::vector<mojom::KeyValuePtr>* data_out, |
| + leveldb::mojom::DatabaseError status, |
| + std::vector<mojom::KeyValuePtr> data) { |
| + *called = true; |
| + *status_out = status; |
| + *data_out = std::move(data); |
| +} |
| + |
| +void SuccessCallback(bool* called, bool* success_out, bool success) { |
| + *called = true; |
| + *success_out = success; |
| +} |
| + |
| +void NoOpSuccess(bool success) {} |
| + |
| +} // namespace |
| + |
| +class LevelDBWrapperImplTest : public testing::Test { |
| + public: |
| + LevelDBWrapperImplTest() |
| + : db_(&mock_data_), |
| + level_db_wrapper_(&db_, |
| + kTestPrefix, |
| + kTestSizeLimit, |
| + base::TimeDelta::FromSeconds(5), |
| + 10 * 1024 * 1024 /* max_bytes_per_hour */, |
| + 60 /* max_commits_per_hour */, |
| + base::Bind(&NoOp)) { |
| + set_mock_data(std::string(kTestPrefix) + "def", "defdata"); |
| + set_mock_data(std::string(kTestPrefix) + "123", "123data"); |
| + set_mock_data("123", "baddata"); |
| + } |
| + |
| + void set_mock_data(const std::string& key, const std::string& value) { |
| + mock_data_[StdStringToUint8Vector(key)] = StdStringToUint8Vector(value); |
| + } |
| + |
| + bool has_mock_data(const std::string& key) { |
| + return mock_data_.find(StdStringToUint8Vector(key)) != mock_data_.end(); |
| + } |
| + |
| + std::string get_mock_data(const std::string& key) { |
| + return has_mock_data(key) |
| + ? Uint8VectorToStdString(mock_data_[StdStringToUint8Vector(key)]) |
| + : ""; |
| + } |
| + |
| + mojom::LevelDBWrapper* wrapper() { return &level_db_wrapper_; } |
| + |
| + void CommitChanges() { |
| + ASSERT_TRUE(level_db_wrapper_.commit_batch_); |
| + level_db_wrapper_.CommitChanges(); |
| + } |
| + |
| + private: |
| + TestBrowserThreadBundle thread_bundle_; |
| + std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_; |
| + MockLevelDBDatabase db_; |
| + LevelDBWrapperImpl level_db_wrapper_; |
| +}; |
| + |
| +TEST_F(LevelDBWrapperImplTest, GetLoadedFromMap) { |
| + bool called = false; |
| + bool success; |
| + std::vector<uint8_t> result; |
| + wrapper()->Get(StdStringToUint8Vector("123"), |
| + base::Bind(&GetCallback, &called, &success, &result)); |
| + ASSERT_TRUE(called); |
| + EXPECT_TRUE(success); |
| + EXPECT_EQ(StdStringToUint8Vector("123data"), result); |
| + |
| + called = false; |
| + wrapper()->Get(StdStringToUint8Vector("x"), |
| + base::Bind(&GetCallback, &called, &success, &result)); |
| + ASSERT_TRUE(called); |
| + EXPECT_FALSE(success); |
| +} |
| + |
| +TEST_F(LevelDBWrapperImplTest, GetFromPutOverwrite) { |
| + std::vector<uint8_t> key = StdStringToUint8Vector("123"); |
| + std::vector<uint8_t> value = StdStringToUint8Vector("foo"); |
| + |
| + bool called = false; |
| + bool success; |
| + wrapper()->Put(key, value, kTestSource, |
| + base::Bind(&SuccessCallback, &called, &success)); |
| + ASSERT_TRUE(called); |
| + EXPECT_TRUE(success); |
| + |
| + called = false; |
| + std::vector<uint8_t> result; |
| + wrapper()->Get(key, base::Bind(&GetCallback, &called, &success, &result)); |
| + ASSERT_TRUE(called); |
| + EXPECT_TRUE(success); |
| + EXPECT_EQ(value, result); |
| +} |
| + |
| +TEST_F(LevelDBWrapperImplTest, GetFromPutNewKey) { |
| + std::vector<uint8_t> key = StdStringToUint8Vector("newkey"); |
| + std::vector<uint8_t> value = StdStringToUint8Vector("foo"); |
| + |
| + bool called = false; |
| + bool success; |
| + wrapper()->Put(key, value, kTestSource, |
| + base::Bind(&SuccessCallback, &called, &success)); |
| + ASSERT_TRUE(called); |
| + EXPECT_TRUE(success); |
| + |
| + called = false; |
| + std::vector<uint8_t> result; |
| + wrapper()->Get(key, base::Bind(&GetCallback, &called, &success, &result)); |
| + ASSERT_TRUE(called); |
| + EXPECT_TRUE(success); |
| + EXPECT_EQ(value, result); |
| +} |
| + |
| +TEST_F(LevelDBWrapperImplTest, GetAll) { |
| + bool called = false; |
| + leveldb::mojom::DatabaseError status; |
| + std::vector<mojom::KeyValuePtr> data; |
| + wrapper()->GetAll(kTestSource, |
| + base::Bind(&GetAllCallback, &called, &status, &data)); |
| + ASSERT_TRUE(called); |
| + EXPECT_EQ(leveldb::mojom::DatabaseError::OK, status); |
| + EXPECT_EQ(2u, data.size()); |
| +} |
| + |
| +TEST_F(LevelDBWrapperImplTest, CommitPutToDB) { |
| + std::string key1 = "123"; |
| + std::string value1 = "foo"; |
| + std::string key2 = "abc"; |
| + std::string value2 = "data abc"; |
| + |
| + wrapper()->Put(StdStringToUint8Vector(key1), StdStringToUint8Vector(value1), |
| + kTestSource, base::Bind(&NoOpSuccess)); |
| + wrapper()->Put(StdStringToUint8Vector(key2), |
| + StdStringToUint8Vector("old value"), kTestSource, |
| + base::Bind(&NoOpSuccess)); |
| + wrapper()->Put(StdStringToUint8Vector(key2), StdStringToUint8Vector(value2), |
| + kTestSource, base::Bind(&NoOpSuccess)); |
| + |
| + CommitChanges(); |
| + |
| + EXPECT_TRUE(has_mock_data(kTestPrefix + key1)); |
| + EXPECT_EQ(value1, get_mock_data(kTestPrefix + key1)); |
| + EXPECT_TRUE(has_mock_data(kTestPrefix + key2)); |
| + EXPECT_EQ(value2, get_mock_data(kTestPrefix + key2)); |
| +} |
| + |
| +} // namespace content |