Make sure webrtc::VideoSource is released when WebRtcVideoTrackAdapter is destroyed.
[chromium-blink-merge.git] / components / dom_distiller / core / dom_distiller_database_unittest.cc
blob54c9043d440961f0ec561d976542481584eca0a6
1 // Copyright 2013 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/dom_distiller/core/dom_distiller_database.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/run_loop.h"
13 #include "base/threading/thread.h"
14 #include "components/dom_distiller/core/article_entry.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using base::MessageLoop;
19 using base::ScopedTempDir;
20 using testing::Invoke;
21 using testing::Return;
22 using testing::_;
24 namespace dom_distiller {
26 namespace {
28 typedef std::map<std::string, ArticleEntry> EntryMap;
30 class MockDB : public DomDistillerDatabase::Database {
31 public:
32 MOCK_METHOD1(Init, bool(const base::FilePath&));
33 MOCK_METHOD2(Save, bool(const EntryVector&, const EntryVector&));
34 MOCK_METHOD1(Load, bool(EntryVector*));
36 MockDB() {
37 ON_CALL(*this, Init(_)).WillByDefault(Return(true));
38 ON_CALL(*this, Save(_, _)).WillByDefault(Return(true));
39 ON_CALL(*this, Load(_)).WillByDefault(Return(true));
42 bool LoadEntries(EntryVector* entries);
45 class MockDatabaseCaller {
46 public:
47 MOCK_METHOD1(InitCallback, void(bool));
48 MOCK_METHOD1(SaveCallback, void(bool));
49 void LoadCallback(bool success, scoped_ptr<EntryVector> entries) {
50 LoadCallback1(success, entries.get());
52 MOCK_METHOD2(LoadCallback1, void(bool, EntryVector*));
55 } // namespace
57 EntryMap GetSmallModel() {
58 EntryMap model;
60 model["key0"].set_entry_id("key0");
61 model["key0"].add_pages()->set_url("http://foo.com/1");
62 model["key0"].add_pages()->set_url("http://foo.com/2");
63 model["key0"].add_pages()->set_url("http://foo.com/3");
65 model["key1"].set_entry_id("key1");
66 model["key1"].add_pages()->set_url("http://bar.com/all");
68 model["key2"].set_entry_id("key2");
69 model["key2"].add_pages()->set_url("http://baz.com/1");
71 return model;
74 void ExpectEntryPointersEquals(EntryMap expected, const EntryVector& actual) {
75 EXPECT_EQ(expected.size(), actual.size());
76 for (size_t i = 0; i < actual.size(); i++) {
77 EntryMap::iterator expected_it =
78 expected.find(std::string(actual[i].entry_id()));
79 EXPECT_TRUE(expected_it != expected.end());
80 std::string serialized_expected = expected_it->second.SerializeAsString();
81 std::string serialized_actual = actual[i].SerializeAsString();
82 EXPECT_EQ(serialized_expected, serialized_actual);
83 expected.erase(expected_it);
87 class DomDistillerDatabaseTest : public testing::Test {
88 public:
89 virtual void SetUp() {
90 main_loop_.reset(new MessageLoop());
91 db_.reset(new DomDistillerDatabase(main_loop_->message_loop_proxy()));
94 virtual void TearDown() {
95 db_.reset();
96 base::RunLoop().RunUntilIdle();
97 main_loop_.reset();
100 scoped_ptr<DomDistillerDatabase> db_;
101 scoped_ptr<MessageLoop> main_loop_;
104 // Test that DomDistillerDatabase calls Init on the underlying database and that
105 // the caller's InitCallback is called with the correct value.
106 TEST_F(DomDistillerDatabaseTest, TestDBInitSuccess) {
107 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
109 MockDB* mock_db = new MockDB();
110 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(true));
112 MockDatabaseCaller caller;
113 EXPECT_CALL(caller, InitCallback(true));
115 db_->InitWithDatabase(
116 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
117 base::FilePath(path),
118 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
120 base::RunLoop().RunUntilIdle();
123 TEST_F(DomDistillerDatabaseTest, TestDBInitFailure) {
124 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
126 MockDB* mock_db = new MockDB();
127 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(false));
129 MockDatabaseCaller caller;
130 EXPECT_CALL(caller, InitCallback(false));
132 db_->InitWithDatabase(
133 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
134 base::FilePath(path),
135 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
137 base::RunLoop().RunUntilIdle();
140 ACTION_P(AppendLoadEntries, model) {
141 EntryVector* output = arg0;
142 for (EntryMap::const_iterator it = model.begin(); it != model.end(); ++it) {
143 output->push_back(it->second);
145 return true;
148 ACTION_P(VerifyLoadEntries, expected) {
149 EntryVector* actual = arg1;
150 ExpectEntryPointersEquals(expected, *actual);
153 // Test that DomDistillerDatabase calls Load on the underlying database and that
154 // the caller's LoadCallback is called with the correct success value. Also
155 // confirms that on success, the expected entries are passed to the caller's
156 // LoadCallback.
157 TEST_F(DomDistillerDatabaseTest, TestDBLoadSuccess) {
158 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
160 MockDB* mock_db = new MockDB();
161 MockDatabaseCaller caller;
162 EntryMap model = GetSmallModel();
164 EXPECT_CALL(*mock_db, Init(_));
165 EXPECT_CALL(caller, InitCallback(_));
166 db_->InitWithDatabase(
167 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
168 base::FilePath(path),
169 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
171 EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model));
172 EXPECT_CALL(caller, LoadCallback1(true, _))
173 .WillOnce(VerifyLoadEntries(testing::ByRef(model)));
174 db_->LoadEntries(
175 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller)));
177 base::RunLoop().RunUntilIdle();
180 TEST_F(DomDistillerDatabaseTest, TestDBLoadFailure) {
181 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
183 MockDB* mock_db = new MockDB();
184 MockDatabaseCaller caller;
186 EXPECT_CALL(*mock_db, Init(_));
187 EXPECT_CALL(caller, InitCallback(_));
188 db_->InitWithDatabase(
189 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
190 base::FilePath(path),
191 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
193 EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false));
194 EXPECT_CALL(caller, LoadCallback1(false, _));
195 db_->LoadEntries(
196 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller)));
198 base::RunLoop().RunUntilIdle();
201 ACTION_P(VerifyUpdateEntries, expected) {
202 const EntryVector& actual = arg0;
203 ExpectEntryPointersEquals(expected, actual);
204 return true;
207 // Test that DomDistillerDatabase calls Save on the underlying database with the
208 // correct entries to save and that the caller's SaveCallback is called with the
209 // correct success value.
210 TEST_F(DomDistillerDatabaseTest, TestDBSaveSuccess) {
211 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
213 MockDB* mock_db = new MockDB();
214 MockDatabaseCaller caller;
215 EntryMap model = GetSmallModel();
217 EXPECT_CALL(*mock_db, Init(_));
218 EXPECT_CALL(caller, InitCallback(_));
219 db_->InitWithDatabase(
220 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
221 base::FilePath(path),
222 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
224 scoped_ptr<EntryVector> entries(new EntryVector());
225 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) {
226 entries->push_back(it->second);
228 scoped_ptr<EntryVector> entries_to_remove(new EntryVector());
230 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(VerifyUpdateEntries(model));
231 EXPECT_CALL(caller, SaveCallback(true));
232 db_->UpdateEntries(
233 entries.Pass(),
234 entries_to_remove.Pass(),
235 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
237 base::RunLoop().RunUntilIdle();
240 TEST_F(DomDistillerDatabaseTest, TestDBSaveFailure) {
241 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
243 MockDB* mock_db = new MockDB();
244 MockDatabaseCaller caller;
245 scoped_ptr<EntryVector> entries(new EntryVector());
246 scoped_ptr<EntryVector> entries_to_remove(new EntryVector());
248 EXPECT_CALL(*mock_db, Init(_));
249 EXPECT_CALL(caller, InitCallback(_));
250 db_->InitWithDatabase(
251 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
252 base::FilePath(path),
253 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
255 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false));
256 EXPECT_CALL(caller, SaveCallback(false));
257 db_->UpdateEntries(
258 entries.Pass(),
259 entries_to_remove.Pass(),
260 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
262 base::RunLoop().RunUntilIdle();
265 ACTION_P(VerifyRemoveEntries, expected) {
266 const EntryVector& actual = arg1;
267 ExpectEntryPointersEquals(expected, actual);
268 return true;
271 // Test that DomDistillerDatabase 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(DomDistillerDatabaseTest, 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 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
285 base::FilePath(path),
286 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
288 scoped_ptr<EntryVector> entries(new EntryVector());
289 scoped_ptr<EntryVector> entries_to_remove(new EntryVector());
290 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) {
291 entries_to_remove->push_back(it->second);
294 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(VerifyRemoveEntries(model));
295 EXPECT_CALL(caller, SaveCallback(true));
296 db_->UpdateEntries(
297 entries.Pass(),
298 entries_to_remove.Pass(),
299 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
301 base::RunLoop().RunUntilIdle();
304 TEST_F(DomDistillerDatabaseTest, TestDBRemoveFailure) {
305 base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
307 MockDB* mock_db = new MockDB();
308 MockDatabaseCaller caller;
309 scoped_ptr<EntryVector> entries(new EntryVector());
310 scoped_ptr<EntryVector> entries_to_remove(new EntryVector());
312 EXPECT_CALL(*mock_db, Init(_));
313 EXPECT_CALL(caller, InitCallback(_));
314 db_->InitWithDatabase(
315 scoped_ptr<DomDistillerDatabase::Database>(mock_db),
316 base::FilePath(path),
317 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
319 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false));
320 EXPECT_CALL(caller, SaveCallback(false));
321 db_->UpdateEntries(
322 entries.Pass(),
323 entries_to_remove.Pass(),
324 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller)));
326 base::RunLoop().RunUntilIdle();
330 // This tests that normal usage of the real database does not cause any
331 // threading violations.
332 TEST(DomDistillerDatabaseThreadingTest, TestDBDestruction) {
333 base::MessageLoop main_loop;
335 ScopedTempDir temp_dir;
336 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
338 base::Thread db_thread("dbthread");
339 ASSERT_TRUE(db_thread.Start());
341 scoped_ptr<DomDistillerDatabase> db(
342 new DomDistillerDatabase(db_thread.message_loop_proxy()));
344 MockDatabaseCaller caller;
345 EXPECT_CALL(caller, InitCallback(_));
346 db->Init(
347 temp_dir.path(),
348 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
350 db.reset();
352 base::RunLoop run_loop;
353 db_thread.message_loop_proxy()->PostTaskAndReply(
354 FROM_HERE, base::Bind(base::DoNothing), run_loop.QuitClosure());
355 run_loop.Run();
358 // Test that the LevelDB properly saves entries and that load returns the saved
359 // entries. If |close_after_save| is true, the database will be closed after
360 // saving and then re-opened to ensure that the data is properly persisted.
361 void TestLevelDBSaveAndLoad(bool close_after_save) {
362 ScopedTempDir temp_dir;
363 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
365 EntryMap model = GetSmallModel();
366 EntryVector save_entries;
367 EntryVector load_entries;
368 EntryVector remove_entries;
370 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) {
371 save_entries.push_back(it->second);
374 scoped_ptr<DomDistillerDatabase::LevelDB> db(
375 new DomDistillerDatabase::LevelDB());
376 EXPECT_TRUE(db->Init(temp_dir.path()));
377 EXPECT_TRUE(db->Save(save_entries, remove_entries));
379 if (close_after_save) {
380 db.reset(new DomDistillerDatabase::LevelDB());
381 EXPECT_TRUE(db->Init(temp_dir.path()));
384 EXPECT_TRUE(db->Load(&load_entries));
386 ExpectEntryPointersEquals(model, load_entries);
389 TEST(DomDistillerDatabaseLevelDBTest, TestDBSaveAndLoad) {
390 TestLevelDBSaveAndLoad(false);
393 TEST(DomDistillerDatabaseLevelDBTest, TestDBCloseAndReopen) {
394 TestLevelDBSaveAndLoad(true);
397 } // namespace dom_distiller