key_value_data_unittest.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright 2020 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 "components/sqlite_proto/key_value_data.h"
  5. #include "base/memory/scoped_refptr.h"
  6. #include "base/test/task_environment.h"
  7. #include "base/threading/thread_task_runner_handle.h"
  8. #include "components/sqlite_proto/table_manager.h"
  9. #include "components/sqlite_proto/test_proto.pb.h"
  10. #include "sql/database.h"
  11. #include "testing/gmock/include/gmock/gmock.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. namespace sqlite_proto {
  14. namespace {
  15. template <typename T>
  16. class FakeKeyValueTable : public KeyValueTable<T> {
  17. public:
  18. FakeKeyValueTable() : sqlite_proto::KeyValueTable<T>("") {}
  19. void GetAllData(std::map<std::string, T>* data_map,
  20. sql::Database* db) const override {
  21. *data_map = data_;
  22. }
  23. void UpdateData(const std::string& key,
  24. const T& data,
  25. sql::Database* db) override {
  26. data_[key] = data;
  27. }
  28. void DeleteData(const std::vector<std::string>& keys,
  29. sql::Database* db) override {
  30. for (const auto& key : keys)
  31. data_.erase(key);
  32. }
  33. void DeleteAllData(sql::Database* db) override { data_.clear(); }
  34. std::map<std::string, T> data_;
  35. };
  36. class FakeTableManager : public TableManager {
  37. public:
  38. FakeTableManager() : TableManager(base::ThreadTaskRunnerHandle::Get()) {}
  39. void ScheduleDBTask(const base::Location& from_here,
  40. base::OnceCallback<void(sql::Database*)> task) override {
  41. GetTaskRunner()->PostTask(
  42. from_here, base::BindOnce(&TableManager::ExecuteDBTaskOnDBSequence,
  43. this, std::move(task)));
  44. }
  45. void ExecuteDBTaskOnDBSequence(
  46. base::OnceCallback<void(sql::Database*)> task) override {
  47. ASSERT_TRUE(GetTaskRunner()->RunsTasksInCurrentSequence());
  48. std::move(task).Run(DB());
  49. }
  50. protected:
  51. ~FakeTableManager() override = default;
  52. // TableManager
  53. void CreateOrClearTablesIfNecessary() override {}
  54. void LogDatabaseStats() override {}
  55. };
  56. MATCHER_P(EqualsProto,
  57. message,
  58. "Match a proto Message equal to the matcher's argument.") {
  59. std::string expected_serialized, actual_serialized;
  60. message.SerializeToString(&expected_serialized);
  61. arg.SerializeToString(&actual_serialized);
  62. return expected_serialized == actual_serialized;
  63. }
  64. struct TestProtoCompare {
  65. bool operator()(const TestProto& lhs, const TestProto& rhs) {
  66. return lhs.value() < rhs.value();
  67. }
  68. };
  69. } // namespace
  70. class KeyValueDataTest : public ::testing::Test {
  71. public:
  72. KeyValueDataTest()
  73. : manager_(base::MakeRefCounted<FakeTableManager>()),
  74. data_(manager_, &table_, absl::nullopt, base::TimeDelta()) {
  75. // In these tests, we're using the current thread as the DB sequence.
  76. data_.InitializeOnDBSequence();
  77. }
  78. ~KeyValueDataTest() override = default;
  79. protected:
  80. base::test::TaskEnvironment env_;
  81. FakeKeyValueTable<TestProto> table_;
  82. scoped_refptr<TableManager> manager_ =
  83. base::MakeRefCounted<FakeTableManager>();
  84. KeyValueData<TestProto, TestProtoCompare> data_;
  85. };
  86. TEST_F(KeyValueDataTest, GetWhenEmpty) {
  87. TestProto result;
  88. EXPECT_FALSE(data_.TryGetData("nonexistent_key", &result));
  89. }
  90. TEST_F(KeyValueDataTest, PutAndGet) {
  91. TestProto first_entry, second_entry;
  92. first_entry.set_value(1);
  93. second_entry.set_value(1);
  94. data_.UpdateData("a", first_entry);
  95. data_.UpdateData("b", second_entry);
  96. TestProto result;
  97. ASSERT_TRUE(data_.TryGetData("a", &result));
  98. EXPECT_THAT(result, EqualsProto(first_entry));
  99. ASSERT_TRUE(data_.TryGetData("b", &result));
  100. EXPECT_THAT(result, EqualsProto(second_entry));
  101. }
  102. // Test that deleting one entry:
  103. // - makes that entry inaccessible, but
  104. // - does not affect the remaining entry.
  105. TEST_F(KeyValueDataTest, Delete) {
  106. TestProto first_entry, second_entry;
  107. first_entry.set_value(1);
  108. second_entry.set_value(1);
  109. data_.UpdateData("a", first_entry);
  110. data_.UpdateData("b", second_entry);
  111. TestProto result;
  112. data_.DeleteData(std::vector<std::string>{"b"});
  113. EXPECT_FALSE(data_.TryGetData("b", &result));
  114. ASSERT_TRUE(data_.TryGetData("a", &result));
  115. EXPECT_THAT(result, EqualsProto(first_entry));
  116. }
  117. TEST_F(KeyValueDataTest, DeleteAll) {
  118. TestProto first_entry, second_entry;
  119. first_entry.set_value(1);
  120. second_entry.set_value(1);
  121. data_.UpdateData("a", first_entry);
  122. data_.UpdateData("b", second_entry);
  123. data_.DeleteAllData();
  124. EXPECT_TRUE(data_.GetAllCached().empty());
  125. }
  126. TEST(KeyValueDataTestSize, CantAddToFullTable) {
  127. FakeKeyValueTable<TestProto> table;
  128. base::test::TaskEnvironment env;
  129. auto manager = base::MakeRefCounted<FakeTableManager>();
  130. KeyValueData<TestProto, TestProtoCompare> data(
  131. manager, &table, /*max_num_entries=*/2,
  132. /*flush_delay=*/base::TimeDelta());
  133. // In these tests, we're using the current thread as the DB sequence.
  134. data.InitializeOnDBSequence();
  135. TestProto one_entry, two_entry, three_entry;
  136. one_entry.set_value(1);
  137. two_entry.set_value(2);
  138. three_entry.set_value(3);
  139. data.UpdateData("a", one_entry);
  140. data.UpdateData("b", two_entry);
  141. data.UpdateData("c", three_entry);
  142. EXPECT_EQ(data.GetAllCached().size(), 2u);
  143. }
  144. // Test that building a KeyValueData on top of a backend table
  145. // with more than |max_num_entries| many entries leads to the table
  146. // being pruned down to a number of entries equal to the KeyValueData's
  147. // capacity.
  148. TEST(KeyValueDataTestSize, PrunesOverlargeTable) {
  149. FakeKeyValueTable<TestProto> table;
  150. base::test::TaskEnvironment env;
  151. auto manager = base::MakeRefCounted<FakeTableManager>();
  152. // Initialization: write a table of size 2 to |manager|'s backend.
  153. {
  154. KeyValueData<TestProto, TestProtoCompare> data(
  155. manager, &table, /*max_num_entries=*/absl::nullopt,
  156. /*flush_delay=*/base::TimeDelta());
  157. // In these tests, we're using the current thread as the DB sequence.
  158. data.InitializeOnDBSequence();
  159. TestProto one_entry, two_entry;
  160. one_entry.set_value(1);
  161. two_entry.set_value(2);
  162. data.UpdateData("a", one_entry);
  163. data.UpdateData("b", two_entry);
  164. // Write changes through to the "disk."
  165. env.RunUntilIdle();
  166. }
  167. {
  168. KeyValueData<TestProto, TestProtoCompare> data(
  169. manager, &table, /*max_num_entries=*/1,
  170. /*flush_delay=*/base::TimeDelta());
  171. // In these tests, we're using the current thread as the DB sequence.
  172. data.InitializeOnDBSequence();
  173. // A cache with size limit less than the size of the database
  174. // should load items up to its capacity (evicting the rest).
  175. EXPECT_EQ(data.GetAllCached().size(), 1u);
  176. }
  177. {
  178. KeyValueData<TestProto, TestProtoCompare> data(
  179. manager, &table, /*max_num_entries=*/absl::nullopt,
  180. /*flush_delay=*/base::TimeDelta());
  181. // In these tests, we're using the current thread as the DB sequence.
  182. data.InitializeOnDBSequence();
  183. // The second, max_num_elements=1, cache should have pruned
  184. // the database to a single element upon initialization.
  185. EXPECT_EQ(data.GetAllCached().size(), 1u);
  186. }
  187. }
  188. } // namespace sqlite_proto