123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- // Copyright 2020 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 "components/sqlite_proto/key_value_data.h"
- #include "base/memory/scoped_refptr.h"
- #include "base/test/task_environment.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "components/sqlite_proto/table_manager.h"
- #include "components/sqlite_proto/test_proto.pb.h"
- #include "sql/database.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace sqlite_proto {
- namespace {
- template <typename T>
- class FakeKeyValueTable : public KeyValueTable<T> {
- public:
- FakeKeyValueTable() : sqlite_proto::KeyValueTable<T>("") {}
- void GetAllData(std::map<std::string, T>* data_map,
- sql::Database* db) const override {
- *data_map = data_;
- }
- void UpdateData(const std::string& key,
- const T& data,
- sql::Database* db) override {
- data_[key] = data;
- }
- void DeleteData(const std::vector<std::string>& keys,
- sql::Database* db) override {
- for (const auto& key : keys)
- data_.erase(key);
- }
- void DeleteAllData(sql::Database* db) override { data_.clear(); }
- std::map<std::string, T> data_;
- };
- class FakeTableManager : public TableManager {
- public:
- FakeTableManager() : TableManager(base::ThreadTaskRunnerHandle::Get()) {}
- void ScheduleDBTask(const base::Location& from_here,
- base::OnceCallback<void(sql::Database*)> task) override {
- GetTaskRunner()->PostTask(
- from_here, base::BindOnce(&TableManager::ExecuteDBTaskOnDBSequence,
- this, std::move(task)));
- }
- void ExecuteDBTaskOnDBSequence(
- base::OnceCallback<void(sql::Database*)> task) override {
- ASSERT_TRUE(GetTaskRunner()->RunsTasksInCurrentSequence());
- std::move(task).Run(DB());
- }
- protected:
- ~FakeTableManager() override = default;
- // TableManager
- void CreateOrClearTablesIfNecessary() override {}
- void LogDatabaseStats() override {}
- };
- MATCHER_P(EqualsProto,
- message,
- "Match a proto Message equal to the matcher's argument.") {
- std::string expected_serialized, actual_serialized;
- message.SerializeToString(&expected_serialized);
- arg.SerializeToString(&actual_serialized);
- return expected_serialized == actual_serialized;
- }
- struct TestProtoCompare {
- bool operator()(const TestProto& lhs, const TestProto& rhs) {
- return lhs.value() < rhs.value();
- }
- };
- } // namespace
- class KeyValueDataTest : public ::testing::Test {
- public:
- KeyValueDataTest()
- : manager_(base::MakeRefCounted<FakeTableManager>()),
- data_(manager_, &table_, absl::nullopt, base::TimeDelta()) {
- // In these tests, we're using the current thread as the DB sequence.
- data_.InitializeOnDBSequence();
- }
- ~KeyValueDataTest() override = default;
- protected:
- base::test::TaskEnvironment env_;
- FakeKeyValueTable<TestProto> table_;
- scoped_refptr<TableManager> manager_ =
- base::MakeRefCounted<FakeTableManager>();
- KeyValueData<TestProto, TestProtoCompare> data_;
- };
- TEST_F(KeyValueDataTest, GetWhenEmpty) {
- TestProto result;
- EXPECT_FALSE(data_.TryGetData("nonexistent_key", &result));
- }
- TEST_F(KeyValueDataTest, PutAndGet) {
- TestProto first_entry, second_entry;
- first_entry.set_value(1);
- second_entry.set_value(1);
- data_.UpdateData("a", first_entry);
- data_.UpdateData("b", second_entry);
- TestProto result;
- ASSERT_TRUE(data_.TryGetData("a", &result));
- EXPECT_THAT(result, EqualsProto(first_entry));
- ASSERT_TRUE(data_.TryGetData("b", &result));
- EXPECT_THAT(result, EqualsProto(second_entry));
- }
- // Test that deleting one entry:
- // - makes that entry inaccessible, but
- // - does not affect the remaining entry.
- TEST_F(KeyValueDataTest, Delete) {
- TestProto first_entry, second_entry;
- first_entry.set_value(1);
- second_entry.set_value(1);
- data_.UpdateData("a", first_entry);
- data_.UpdateData("b", second_entry);
- TestProto result;
- data_.DeleteData(std::vector<std::string>{"b"});
- EXPECT_FALSE(data_.TryGetData("b", &result));
- ASSERT_TRUE(data_.TryGetData("a", &result));
- EXPECT_THAT(result, EqualsProto(first_entry));
- }
- TEST_F(KeyValueDataTest, DeleteAll) {
- TestProto first_entry, second_entry;
- first_entry.set_value(1);
- second_entry.set_value(1);
- data_.UpdateData("a", first_entry);
- data_.UpdateData("b", second_entry);
- data_.DeleteAllData();
- EXPECT_TRUE(data_.GetAllCached().empty());
- }
- TEST(KeyValueDataTestSize, CantAddToFullTable) {
- FakeKeyValueTable<TestProto> table;
- base::test::TaskEnvironment env;
- auto manager = base::MakeRefCounted<FakeTableManager>();
- KeyValueData<TestProto, TestProtoCompare> data(
- manager, &table, /*max_num_entries=*/2,
- /*flush_delay=*/base::TimeDelta());
- // In these tests, we're using the current thread as the DB sequence.
- data.InitializeOnDBSequence();
- TestProto one_entry, two_entry, three_entry;
- one_entry.set_value(1);
- two_entry.set_value(2);
- three_entry.set_value(3);
- data.UpdateData("a", one_entry);
- data.UpdateData("b", two_entry);
- data.UpdateData("c", three_entry);
- EXPECT_EQ(data.GetAllCached().size(), 2u);
- }
- // Test that building a KeyValueData on top of a backend table
- // with more than |max_num_entries| many entries leads to the table
- // being pruned down to a number of entries equal to the KeyValueData's
- // capacity.
- TEST(KeyValueDataTestSize, PrunesOverlargeTable) {
- FakeKeyValueTable<TestProto> table;
- base::test::TaskEnvironment env;
- auto manager = base::MakeRefCounted<FakeTableManager>();
- // Initialization: write a table of size 2 to |manager|'s backend.
- {
- KeyValueData<TestProto, TestProtoCompare> data(
- manager, &table, /*max_num_entries=*/absl::nullopt,
- /*flush_delay=*/base::TimeDelta());
- // In these tests, we're using the current thread as the DB sequence.
- data.InitializeOnDBSequence();
- TestProto one_entry, two_entry;
- one_entry.set_value(1);
- two_entry.set_value(2);
- data.UpdateData("a", one_entry);
- data.UpdateData("b", two_entry);
- // Write changes through to the "disk."
- env.RunUntilIdle();
- }
- {
- KeyValueData<TestProto, TestProtoCompare> data(
- manager, &table, /*max_num_entries=*/1,
- /*flush_delay=*/base::TimeDelta());
- // In these tests, we're using the current thread as the DB sequence.
- data.InitializeOnDBSequence();
- // A cache with size limit less than the size of the database
- // should load items up to its capacity (evicting the rest).
- EXPECT_EQ(data.GetAllCached().size(), 1u);
- }
- {
- KeyValueData<TestProto, TestProtoCompare> data(
- manager, &table, /*max_num_entries=*/absl::nullopt,
- /*flush_delay=*/base::TimeDelta());
- // In these tests, we're using the current thread as the DB sequence.
- data.InitializeOnDBSequence();
- // The second, max_num_elements=1, cache should have pruned
- // the database to a single element upon initialization.
- EXPECT_EQ(data.GetAllCached().size(), 1u);
- }
- }
- } // namespace sqlite_proto
|