Roll src/third_party/WebKit 9f7fb92:f103b33 (svn 202621:202622)
[chromium-blink-merge.git] / components / leveldb_proto / proto_database_impl_unittest.cc
blob76b4ae510149f3950bfdec1f1333a5d3cff4a3d4
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.
5 #include "components/leveldb_proto/proto_database_impl.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/location.h"
13 #include "base/run_loop.h"
14 #include "base/threading/thread.h"
15 #include "components/leveldb_proto/leveldb_database.h"
16 #include "components/leveldb_proto/testing/proto/test.pb.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/leveldatabase/src/include/leveldb/options.h"
21 using base::MessageLoop;
22 using base::ScopedTempDir;
23 using testing::Invoke;
24 using testing::Return;
25 using testing::_;
27 namespace leveldb_proto {
29 namespace {
31 typedef std::map<std::string, TestProto> EntryMap;
33 class MockDB : public LevelDB {
34 public:
35 MOCK_METHOD1(Init, bool(const base::FilePath&));
36 MOCK_METHOD2(Save, bool(const KeyValueVector&, const KeyVector&));
37 MOCK_METHOD1(Load, bool(std::vector<std::string>*));
39 MockDB() {
40 ON_CALL(*this, Init(_)).WillByDefault(Return(true));
41 ON_CALL(*this, Save(_, _)).WillByDefault(Return(true));
42 ON_CALL(*this, Load(_)).WillByDefault(Return(true));
46 class MockDatabaseCaller {
47 public:
48 MOCK_METHOD1(InitCallback, void(bool));
49 MOCK_METHOD1(SaveCallback, void(bool));
50 void LoadCallback(bool success, scoped_ptr<std::vector<TestProto> > entries) {
51 LoadCallback1(success, entries.get());
53 MOCK_METHOD2(LoadCallback1, void(bool, std::vector<TestProto>*));
56 } // namespace
58 EntryMap GetSmallModel() {
59 EntryMap model;
61 model["0"].set_id("0");
62 model["0"].set_data("http://foo.com/1");
64 model["1"].set_id("1");
65 model["1"].set_data("http://bar.com/all");
67 model["2"].set_id("2");
68 model["2"].set_data("http://baz.com/1");
70 return model;
73 void ExpectEntryPointersEquals(EntryMap expected,
74 const std::vector<TestProto>& actual) {
75 EXPECT_EQ(expected.size(), actual.size());
76 for (size_t i = 0; i < actual.size(); i++) {
77 EntryMap::iterator expected_it = expected.find(actual[i].id());
78 EXPECT_TRUE(expected_it != expected.end());
79 std::string serialized_expected = expected_it->second.SerializeAsString();
80 std::string serialized_actual = actual[i].SerializeAsString();
81 EXPECT_EQ(serialized_expected, serialized_actual);
82 expected.erase(expected_it);
86 class ProtoDatabaseImplTest : public testing::Test {
87 public:
88 void SetUp() override {
89 main_loop_.reset(new MessageLoop());
90 db_.reset(new ProtoDatabaseImpl<TestProto>(main_loop_->task_runner()));
93 void TearDown() override {
94 db_.reset();
95 base::RunLoop().RunUntilIdle();
96 main_loop_.reset();
99 scoped_ptr<ProtoDatabaseImpl<TestProto> > db_;
100 scoped_ptr<MessageLoop> main_loop_;
103 // Test that ProtoDatabaseImpl calls Init on the underlying database and that
104 // the caller's InitCallback is called with the correct value.
105 TEST_F(ProtoDatabaseImplTest, TestDBInitSuccess) {
106 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
108 MockDB* mock_db = new MockDB();
109 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(true));
111 MockDatabaseCaller caller;
112 EXPECT_CALL(caller, InitCallback(true));
114 db_->InitWithDatabase(
115 make_scoped_ptr(mock_db), path,
116 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
118 base::RunLoop().RunUntilIdle();
121 TEST_F(ProtoDatabaseImplTest, TestDBInitFailure) {
122 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
124 MockDB* mock_db = new MockDB();
125 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(false));
127 MockDatabaseCaller caller;
128 EXPECT_CALL(caller, InitCallback(false));
130 db_->InitWithDatabase(
131 make_scoped_ptr(mock_db), path,
132 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
134 base::RunLoop().RunUntilIdle();
137 ACTION_P(AppendLoadEntries, model) {
138 std::vector<std::string>* output = arg0;
139 for (const auto& pair : model)
140 output->push_back(pair.second.SerializeAsString());
142 return true;
145 ACTION_P(VerifyLoadEntries, expected) {
146 std::vector<TestProto>* actual = arg1;
147 ExpectEntryPointersEquals(expected, *actual);
150 // Test that ProtoDatabaseImpl calls Load on the underlying database and that
151 // the caller's LoadCallback is called with the correct success value. Also
152 // confirms that on success, the expected entries are passed to the caller's
153 // LoadCallback.
154 TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) {
155 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
157 MockDB* mock_db = new MockDB();
158 MockDatabaseCaller caller;
159 EntryMap model = GetSmallModel();
161 EXPECT_CALL(*mock_db, Init(_));
162 EXPECT_CALL(caller, InitCallback(_));
163 db_->InitWithDatabase(
164 make_scoped_ptr(mock_db), path,
165 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
167 EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model));
168 EXPECT_CALL(caller, LoadCallback1(true, _))
169 .WillOnce(VerifyLoadEntries(testing::ByRef(model)));
170 db_->LoadEntries(
171 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller)));
173 base::RunLoop().RunUntilIdle();
176 TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) {
177 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
179 MockDB* mock_db = new MockDB();
180 MockDatabaseCaller caller;
182 EXPECT_CALL(*mock_db, Init(_));
183 EXPECT_CALL(caller, InitCallback(_));
184 db_->InitWithDatabase(
185 make_scoped_ptr(mock_db), path,
186 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
188 EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false));
189 EXPECT_CALL(caller, LoadCallback1(false, _));
190 db_->LoadEntries(
191 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller)));
193 base::RunLoop().RunUntilIdle();
196 ACTION_P(VerifyUpdateEntries, expected) {
197 const KeyValueVector actual = arg0;
198 // Create a vector of TestProto from |actual| to reuse the comparison
199 // function.
200 std::vector<TestProto> extracted_entries;
201 for (const auto& pair : actual) {
202 TestProto entry;
203 if (!entry.ParseFromString(pair.second)) {
204 ADD_FAILURE() << "Unable to deserialize the protobuf";
205 return false;
208 extracted_entries.push_back(entry);
211 ExpectEntryPointersEquals(expected, extracted_entries);
212 return true;
215 // Test that ProtoDatabaseImpl calls Save on the underlying database with the
216 // correct entries to save and that the caller's SaveCallback is called with the
217 // correct success value.
218 TEST_F(ProtoDatabaseImplTest, TestDBSaveSuccess) {
219 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
221 MockDB* mock_db = new MockDB();
222 MockDatabaseCaller caller;
223 EntryMap model = GetSmallModel();
225 EXPECT_CALL(*mock_db, Init(_));
226 EXPECT_CALL(caller, InitCallback(_));
227 db_->InitWithDatabase(
228 make_scoped_ptr(mock_db), path,
229 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
231 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
232 new ProtoDatabase<TestProto>::KeyEntryVector());
233 for (const auto& pair : model)
234 entries->push_back(std::make_pair(pair.second.id(), pair.second));
236 scoped_ptr<KeyVector> keys_to_remove(new KeyVector());
238 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(VerifyUpdateEntries(model));
239 EXPECT_CALL(caller, SaveCallback(true));
240 db_->UpdateEntries(
241 entries.Pass(), keys_to_remove.Pass(),
242 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
244 base::RunLoop().RunUntilIdle();
247 TEST_F(ProtoDatabaseImplTest, TestDBSaveFailure) {
248 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
250 MockDB* mock_db = new MockDB();
251 MockDatabaseCaller caller;
252 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
253 new ProtoDatabase<TestProto>::KeyEntryVector());
254 scoped_ptr<KeyVector> keys_to_remove(new KeyVector());
256 EXPECT_CALL(*mock_db, Init(_));
257 EXPECT_CALL(caller, InitCallback(_));
258 db_->InitWithDatabase(
259 make_scoped_ptr(mock_db), path,
260 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
262 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false));
263 EXPECT_CALL(caller, SaveCallback(false));
264 db_->UpdateEntries(
265 entries.Pass(), keys_to_remove.Pass(),
266 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
268 base::RunLoop().RunUntilIdle();
271 // Test that ProtoDatabaseImpl calls Save on the underlying database with the
272 // correct entries to delete and that the caller's SaveCallback is called with
273 // the correct success value.
274 TEST_F(ProtoDatabaseImplTest, TestDBRemoveSuccess) {
275 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
277 MockDB* mock_db = new MockDB();
278 MockDatabaseCaller caller;
279 EntryMap model = GetSmallModel();
281 EXPECT_CALL(*mock_db, Init(_));
282 EXPECT_CALL(caller, InitCallback(_));
283 db_->InitWithDatabase(
284 make_scoped_ptr(mock_db), path,
285 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
287 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
288 new ProtoDatabase<TestProto>::KeyEntryVector());
289 scoped_ptr<KeyVector> keys_to_remove(new KeyVector());
290 for (const auto& pair : model)
291 keys_to_remove->push_back(pair.second.id());
293 KeyVector keys_copy(*keys_to_remove.get());
294 EXPECT_CALL(*mock_db, Save(_, keys_copy)).WillOnce(Return(true));
295 EXPECT_CALL(caller, SaveCallback(true));
296 db_->UpdateEntries(
297 entries.Pass(), keys_to_remove.Pass(),
298 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
300 base::RunLoop().RunUntilIdle();
303 TEST_F(ProtoDatabaseImplTest, TestDBRemoveFailure) {
304 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
306 MockDB* mock_db = new MockDB();
307 MockDatabaseCaller caller;
308 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries(
309 new ProtoDatabase<TestProto>::KeyEntryVector());
310 scoped_ptr<KeyVector> keys_to_remove(new KeyVector());
312 EXPECT_CALL(*mock_db, Init(_));
313 EXPECT_CALL(caller, InitCallback(_));
314 db_->InitWithDatabase(
315 make_scoped_ptr(mock_db), path,
316 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
318 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false));
319 EXPECT_CALL(caller, SaveCallback(false));
320 db_->UpdateEntries(
321 entries.Pass(), keys_to_remove.Pass(),
322 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
324 base::RunLoop().RunUntilIdle();
327 // This tests that normal usage of the real database does not cause any
328 // threading violations.
329 TEST(ProtoDatabaseImplThreadingTest, TestDBDestruction) {
330 base::MessageLoop main_loop;
332 ScopedTempDir temp_dir;
333 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
335 base::Thread db_thread("dbthread");
336 ASSERT_TRUE(db_thread.Start());
338 scoped_ptr<ProtoDatabaseImpl<TestProto>> db(
339 new ProtoDatabaseImpl<TestProto>(db_thread.task_runner()));
341 MockDatabaseCaller caller;
342 EXPECT_CALL(caller, InitCallback(_));
343 db->Init(temp_dir.path(), base::Bind(&MockDatabaseCaller::InitCallback,
344 base::Unretained(&caller)));
346 db.reset();
348 base::RunLoop run_loop;
349 db_thread.task_runner()->PostTaskAndReply(
350 FROM_HERE, base::Bind(base::DoNothing), run_loop.QuitClosure());
351 run_loop.Run();
354 // Test that the LevelDB properly saves entries and that load returns the saved
355 // entries. If |close_after_save| is true, the database will be closed after
356 // saving and then re-opened to ensure that the data is properly persisted.
357 void TestLevelDBSaveAndLoad(bool close_after_save) {
358 ScopedTempDir temp_dir;
359 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
361 EntryMap model = GetSmallModel();
363 KeyValueVector save_entries;
364 std::vector<std::string> load_entries;
365 KeyVector remove_keys;
367 for (const auto& pair : model) {
368 save_entries.push_back(
369 std::make_pair(pair.second.id(), pair.second.SerializeAsString()));
372 scoped_ptr<LevelDB> db(new LevelDB());
373 EXPECT_TRUE(db->Init(temp_dir.path()));
374 EXPECT_TRUE(db->Save(save_entries, remove_keys));
376 if (close_after_save) {
377 db.reset(new LevelDB());
378 EXPECT_TRUE(db->Init(temp_dir.path()));
381 EXPECT_TRUE(db->Load(&load_entries));
383 // Convert the strings back to TestProto.
384 std::vector<TestProto> loaded_protos;
385 for (const auto& serialized_entry : load_entries) {
386 TestProto entry;
387 ASSERT_TRUE(entry.ParseFromString(serialized_entry));
388 loaded_protos.push_back(entry);
391 ExpectEntryPointersEquals(model, loaded_protos);
394 TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) {
395 TestLevelDBSaveAndLoad(false);
398 TEST(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) {
399 TestLevelDBSaveAndLoad(true);
402 TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
403 ScopedTempDir temp_dir;
404 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
406 leveldb::Options options;
407 options.create_if_missing = false;
408 scoped_ptr<LevelDB> db(new LevelDB());
410 KeyValueVector save_entries;
411 std::vector<std::string> load_entries;
412 KeyVector remove_keys;
414 EXPECT_FALSE(db->InitWithOptions(temp_dir.path(), options));
415 EXPECT_FALSE(db->Load(&load_entries));
416 EXPECT_FALSE(db->Save(save_entries, remove_keys));
419 TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
420 scoped_ptr<LevelDB> db(new LevelDB());
422 std::vector<std::string> load_entries;
424 ASSERT_TRUE(db->Init(base::FilePath()));
426 ASSERT_TRUE(db->Load(&load_entries));
427 EXPECT_EQ(0u, load_entries.size());
429 KeyValueVector save_entries(1, std::make_pair("foo", "bar"));
430 KeyVector remove_keys;
432 ASSERT_TRUE(db->Save(save_entries, remove_keys));
434 std::vector<std::string> second_load_entries;
436 ASSERT_TRUE(db->Load(&second_load_entries));
437 EXPECT_EQ(1u, second_load_entries.size());
440 } // namespace leveldb_proto