| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/dom_distiller/core/dom_distiller_database.h" | 5 #include "components/leveldb_proto/core/proto_database_impl.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
| 12 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
| 13 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
| 14 #include "components/dom_distiller/core/article_entry.h" | 14 #include "components/leveldb_proto/testing/proto/test.pb.h" |
| 15 #include "testing/gmock/include/gmock/gmock.h" | 15 #include "testing/gmock/include/gmock/gmock.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 | 17 |
| 18 using base::MessageLoop; | 18 using base::MessageLoop; |
| 19 using base::ScopedTempDir; | 19 using base::ScopedTempDir; |
| 20 using testing::Invoke; | 20 using testing::Invoke; |
| 21 using testing::Return; | 21 using testing::Return; |
| 22 using testing::_; | 22 using testing::_; |
| 23 | 23 |
| 24 namespace dom_distiller { | 24 namespace leveldb_proto { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 typedef std::map<std::string, ArticleEntry> EntryMap; | 28 typedef std::map<std::string, TestProto> EntryMap; |
| 29 | 29 |
| 30 class MockDB : public DomDistillerDatabase::Database { | 30 class MockDB : public ProtoDatabaseImpl<TestProto>::Database { |
| 31 public: | 31 public: |
| 32 MOCK_METHOD1(Init, bool(const base::FilePath&)); | 32 MOCK_METHOD1(Init, bool(const base::FilePath&)); |
| 33 MOCK_METHOD2(Save, bool(const EntryVector&, const EntryVector&)); | 33 MOCK_METHOD2(Save, bool(const ProtoDatabase<TestProto>::KeyEntryVector&, |
| 34 MOCK_METHOD1(Load, bool(EntryVector*)); | 34 const std::vector<std::string>&)); |
| 35 MOCK_METHOD1(Load, bool(std::vector<TestProto>*)); |
| 35 | 36 |
| 36 MockDB() { | 37 MockDB() { |
| 37 ON_CALL(*this, Init(_)).WillByDefault(Return(true)); | 38 ON_CALL(*this, Init(_)).WillByDefault(Return(true)); |
| 38 ON_CALL(*this, Save(_, _)).WillByDefault(Return(true)); | 39 ON_CALL(*this, Save(_, _)).WillByDefault(Return(true)); |
| 39 ON_CALL(*this, Load(_)).WillByDefault(Return(true)); | 40 ON_CALL(*this, Load(_)).WillByDefault(Return(true)); |
| 40 } | 41 } |
| 41 | 42 |
| 42 bool LoadEntries(EntryVector* entries); | 43 bool LoadEntries(std::vector<TestProto>* entries); |
| 43 }; | 44 }; |
| 44 | 45 |
| 45 class MockDatabaseCaller { | 46 class MockDatabaseCaller { |
| 46 public: | 47 public: |
| 47 MOCK_METHOD1(InitCallback, void(bool)); | 48 MOCK_METHOD1(InitCallback, void(bool)); |
| 48 MOCK_METHOD1(SaveCallback, void(bool)); | 49 MOCK_METHOD1(SaveCallback, void(bool)); |
| 49 void LoadCallback(bool success, scoped_ptr<EntryVector> entries) { | 50 void LoadCallback(bool success, scoped_ptr<std::vector<TestProto>> entries) { |
| 50 LoadCallback1(success, entries.get()); | 51 LoadCallback1(success, entries.get()); |
| 51 } | 52 } |
| 52 MOCK_METHOD2(LoadCallback1, void(bool, EntryVector*)); | 53 MOCK_METHOD2(LoadCallback1, void(bool, std::vector<TestProto>*)); |
| 53 }; | 54 }; |
| 54 | 55 |
| 55 } // namespace | 56 } // namespace |
| 56 | 57 |
| 57 EntryMap GetSmallModel() { | 58 EntryMap GetSmallModel() { |
| 58 EntryMap model; | 59 EntryMap model; |
| 59 | 60 |
| 60 model["key0"].set_entry_id("key0"); | 61 model["0"].set_id("0"); |
| 61 model["key0"].add_pages()->set_url("http://foo.com/1"); | 62 model["0"].set_data("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"); | |
| 64 | 63 |
| 65 model["key1"].set_entry_id("key1"); | 64 model["1"].set_id("1"); |
| 66 model["key1"].add_pages()->set_url("http://bar.com/all"); | 65 model["1"].set_data("http://bar.com/all"); |
| 67 | 66 |
| 68 model["key2"].set_entry_id("key2"); | 67 model["2"].set_id("2"); |
| 69 model["key2"].add_pages()->set_url("http://baz.com/1"); | 68 model["2"].set_data("http://baz.com/1"); |
| 70 | 69 |
| 71 return model; | 70 return model; |
| 72 } | 71 } |
| 73 | 72 |
| 74 void ExpectEntryPointersEquals(EntryMap expected, const EntryVector& actual) { | 73 void ExpectEntryPointersEquals(EntryMap expected, |
| 74 const std::vector<TestProto>& actual) { |
| 75 EXPECT_EQ(expected.size(), actual.size()); | 75 EXPECT_EQ(expected.size(), actual.size()); |
| 76 for (size_t i = 0; i < actual.size(); i++) { | 76 for (size_t i = 0; i < actual.size(); i++) { |
| 77 EntryMap::iterator expected_it = | 77 EntryMap::iterator expected_it = expected.find(actual[i].id()); |
| 78 expected.find(std::string(actual[i].entry_id())); | |
| 79 EXPECT_TRUE(expected_it != expected.end()); | 78 EXPECT_TRUE(expected_it != expected.end()); |
| 80 std::string serialized_expected = expected_it->second.SerializeAsString(); | 79 std::string serialized_expected = expected_it->second.SerializeAsString(); |
| 81 std::string serialized_actual = actual[i].SerializeAsString(); | 80 std::string serialized_actual = actual[i].SerializeAsString(); |
| 82 EXPECT_EQ(serialized_expected, serialized_actual); | 81 EXPECT_EQ(serialized_expected, serialized_actual); |
| 83 expected.erase(expected_it); | 82 expected.erase(expected_it); |
| 84 } | 83 } |
| 85 } | 84 } |
| 86 | 85 |
| 87 class DomDistillerDatabaseTest : public testing::Test { | 86 class ProtoDatabaseImplTest : public testing::Test { |
| 88 public: | 87 public: |
| 89 virtual void SetUp() { | 88 virtual void SetUp() { |
| 90 main_loop_.reset(new MessageLoop()); | 89 main_loop_.reset(new MessageLoop()); |
| 91 db_.reset(new DomDistillerDatabase(main_loop_->message_loop_proxy())); | 90 db_.reset( |
| 91 new ProtoDatabaseImpl<TestProto>(main_loop_->message_loop_proxy())); |
| 92 } | 92 } |
| 93 | 93 |
| 94 virtual void TearDown() { | 94 virtual void TearDown() { |
| 95 db_.reset(); | 95 db_.reset(); |
| 96 base::RunLoop().RunUntilIdle(); | 96 base::RunLoop().RunUntilIdle(); |
| 97 main_loop_.reset(); | 97 main_loop_.reset(); |
| 98 } | 98 } |
| 99 | 99 |
| 100 scoped_ptr<DomDistillerDatabase> db_; | 100 scoped_ptr<ProtoDatabaseImpl<TestProto>> db_; |
| 101 scoped_ptr<MessageLoop> main_loop_; | 101 scoped_ptr<MessageLoop> main_loop_; |
| 102 }; | 102 }; |
| 103 | 103 |
| 104 // Test that DomDistillerDatabase calls Init on the underlying database and that | 104 // Test that ProtoDatabaseImpl calls Init on the underlying database and that |
| 105 // the caller's InitCallback is called with the correct value. | 105 // the caller's InitCallback is called with the correct value. |
| 106 TEST_F(DomDistillerDatabaseTest, TestDBInitSuccess) { | 106 TEST_F(ProtoDatabaseImplTest, TestDBInitSuccess) { |
| 107 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 107 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 108 | 108 |
| 109 MockDB* mock_db = new MockDB(); | 109 MockDB* mock_db = new MockDB(); |
| 110 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(true)); | 110 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(true)); |
| 111 | 111 |
| 112 MockDatabaseCaller caller; | 112 MockDatabaseCaller caller; |
| 113 EXPECT_CALL(caller, InitCallback(true)); | 113 EXPECT_CALL(caller, InitCallback(true)); |
| 114 | 114 |
| 115 db_->InitWithDatabase( | 115 db_->InitWithDatabase( |
| 116 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 116 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 117 base::FilePath(path), | 117 base::FilePath(path), |
| 118 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 118 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 119 | 119 |
| 120 base::RunLoop().RunUntilIdle(); | 120 base::RunLoop().RunUntilIdle(); |
| 121 } | 121 } |
| 122 | 122 |
| 123 TEST_F(DomDistillerDatabaseTest, TestDBInitFailure) { | 123 TEST_F(ProtoDatabaseImplTest, TestDBInitFailure) { |
| 124 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 124 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 125 | 125 |
| 126 MockDB* mock_db = new MockDB(); | 126 MockDB* mock_db = new MockDB(); |
| 127 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(false)); | 127 EXPECT_CALL(*mock_db, Init(path)).WillOnce(Return(false)); |
| 128 | 128 |
| 129 MockDatabaseCaller caller; | 129 MockDatabaseCaller caller; |
| 130 EXPECT_CALL(caller, InitCallback(false)); | 130 EXPECT_CALL(caller, InitCallback(false)); |
| 131 | 131 |
| 132 db_->InitWithDatabase( | 132 db_->InitWithDatabase( |
| 133 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 133 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 134 base::FilePath(path), | 134 base::FilePath(path), |
| 135 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 135 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 136 | 136 |
| 137 base::RunLoop().RunUntilIdle(); | 137 base::RunLoop().RunUntilIdle(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 ACTION_P(AppendLoadEntries, model) { | 140 ACTION_P(AppendLoadEntries, model) { |
| 141 EntryVector* output = arg0; | 141 std::vector<TestProto>* output = arg0; |
| 142 for (EntryMap::const_iterator it = model.begin(); it != model.end(); ++it) { | 142 for (EntryMap::const_iterator it = model.begin(); it != model.end(); ++it) { |
| 143 output->push_back(it->second); | 143 output->push_back(it->second); |
| 144 } | 144 } |
| 145 return true; | 145 return true; |
| 146 } | 146 } |
| 147 | 147 |
| 148 ACTION_P(VerifyLoadEntries, expected) { | 148 ACTION_P(VerifyLoadEntries, expected) { |
| 149 EntryVector* actual = arg1; | 149 std::vector<TestProto>* actual = arg1; |
| 150 ExpectEntryPointersEquals(expected, *actual); | 150 ExpectEntryPointersEquals(expected, *actual); |
| 151 } | 151 } |
| 152 | 152 |
| 153 // Test that DomDistillerDatabase calls Load on the underlying database and that | 153 // Test that ProtoDatabaseImpl calls Load on the underlying database and that |
| 154 // the caller's LoadCallback is called with the correct success value. Also | 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 | 155 // confirms that on success, the expected entries are passed to the caller's |
| 156 // LoadCallback. | 156 // LoadCallback. |
| 157 TEST_F(DomDistillerDatabaseTest, TestDBLoadSuccess) { | 157 TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) { |
| 158 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 158 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 159 | 159 |
| 160 MockDB* mock_db = new MockDB(); | 160 MockDB* mock_db = new MockDB(); |
| 161 MockDatabaseCaller caller; | 161 MockDatabaseCaller caller; |
| 162 EntryMap model = GetSmallModel(); | 162 EntryMap model = GetSmallModel(); |
| 163 | 163 |
| 164 EXPECT_CALL(*mock_db, Init(_)); | 164 EXPECT_CALL(*mock_db, Init(_)); |
| 165 EXPECT_CALL(caller, InitCallback(_)); | 165 EXPECT_CALL(caller, InitCallback(_)); |
| 166 db_->InitWithDatabase( | 166 db_->InitWithDatabase( |
| 167 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 167 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 168 base::FilePath(path), | 168 base::FilePath(path), |
| 169 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 169 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 170 | 170 |
| 171 EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model)); | 171 EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model)); |
| 172 EXPECT_CALL(caller, LoadCallback1(true, _)) | 172 EXPECT_CALL(caller, LoadCallback1(true, _)) |
| 173 .WillOnce(VerifyLoadEntries(testing::ByRef(model))); | 173 .WillOnce(VerifyLoadEntries(testing::ByRef(model))); |
| 174 db_->LoadEntries( | 174 db_->LoadEntries( |
| 175 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller))); | 175 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller))); |
| 176 | 176 |
| 177 base::RunLoop().RunUntilIdle(); | 177 base::RunLoop().RunUntilIdle(); |
| 178 } | 178 } |
| 179 | 179 |
| 180 TEST_F(DomDistillerDatabaseTest, TestDBLoadFailure) { | 180 TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) { |
| 181 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 181 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 182 | 182 |
| 183 MockDB* mock_db = new MockDB(); | 183 MockDB* mock_db = new MockDB(); |
| 184 MockDatabaseCaller caller; | 184 MockDatabaseCaller caller; |
| 185 | 185 |
| 186 EXPECT_CALL(*mock_db, Init(_)); | 186 EXPECT_CALL(*mock_db, Init(_)); |
| 187 EXPECT_CALL(caller, InitCallback(_)); | 187 EXPECT_CALL(caller, InitCallback(_)); |
| 188 db_->InitWithDatabase( | 188 db_->InitWithDatabase( |
| 189 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 189 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 190 base::FilePath(path), | 190 base::FilePath(path), |
| 191 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 191 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 192 | 192 |
| 193 EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false)); | 193 EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false)); |
| 194 EXPECT_CALL(caller, LoadCallback1(false, _)); | 194 EXPECT_CALL(caller, LoadCallback1(false, _)); |
| 195 db_->LoadEntries( | 195 db_->LoadEntries( |
| 196 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller))); | 196 base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller))); |
| 197 | 197 |
| 198 base::RunLoop().RunUntilIdle(); | 198 base::RunLoop().RunUntilIdle(); |
| 199 } | 199 } |
| 200 | 200 |
| 201 ACTION_P(VerifyUpdateEntries, expected) { | 201 ACTION_P(VerifyUpdateEntries, expected) { |
| 202 const EntryVector& actual = arg0; | 202 const ProtoDatabase<TestProto>::KeyEntryVector& actual = arg0; |
| 203 ExpectEntryPointersEquals(expected, actual); | 203 // Create a vector of TestProto from |actual| to reuse the comparison |
| 204 // function. |
| 205 std::vector<TestProto> extracted_entries; |
| 206 for (ProtoDatabase<TestProto>::KeyEntryVector::const_iterator it = |
| 207 actual.begin(); |
| 208 it != actual.end(); ++it) { |
| 209 extracted_entries.push_back(it->second); |
| 210 } |
| 211 ExpectEntryPointersEquals(expected, extracted_entries); |
| 204 return true; | 212 return true; |
| 205 } | 213 } |
| 206 | 214 |
| 207 // Test that DomDistillerDatabase calls Save on the underlying database with the | 215 // Test that ProtoDatabaseImpl calls Save on the underlying database with the |
| 208 // correct entries to save and that the caller's SaveCallback is called with the | 216 // correct entries to save and that the caller's SaveCallback is called with the |
| 209 // correct success value. | 217 // correct success value. |
| 210 TEST_F(DomDistillerDatabaseTest, TestDBSaveSuccess) { | 218 TEST_F(ProtoDatabaseImplTest, TestDBSaveSuccess) { |
| 211 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 219 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 212 | 220 |
| 213 MockDB* mock_db = new MockDB(); | 221 MockDB* mock_db = new MockDB(); |
| 214 MockDatabaseCaller caller; | 222 MockDatabaseCaller caller; |
| 215 EntryMap model = GetSmallModel(); | 223 EntryMap model = GetSmallModel(); |
| 216 | 224 |
| 217 EXPECT_CALL(*mock_db, Init(_)); | 225 EXPECT_CALL(*mock_db, Init(_)); |
| 218 EXPECT_CALL(caller, InitCallback(_)); | 226 EXPECT_CALL(caller, InitCallback(_)); |
| 219 db_->InitWithDatabase( | 227 db_->InitWithDatabase( |
| 220 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 228 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 221 base::FilePath(path), | 229 base::FilePath(path), |
| 222 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 230 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 223 | 231 |
| 224 scoped_ptr<EntryVector> entries(new EntryVector()); | 232 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries( |
| 233 new ProtoDatabase<TestProto>::KeyEntryVector()); |
| 225 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) { | 234 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) { |
| 226 entries->push_back(it->second); | 235 entries->push_back(std::make_pair(it->second.id(), it->second)); |
| 227 } | 236 } |
| 228 scoped_ptr<EntryVector> entries_to_remove(new EntryVector()); | 237 scoped_ptr<std::vector<std::string>> keys_to_remove( |
| 238 new std::vector<std::string>()); |
| 229 | 239 |
| 230 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(VerifyUpdateEntries(model)); | 240 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(VerifyUpdateEntries(model)); |
| 231 EXPECT_CALL(caller, SaveCallback(true)); | 241 EXPECT_CALL(caller, SaveCallback(true)); |
| 232 db_->UpdateEntries( | 242 db_->UpdateEntries( |
| 233 entries.Pass(), | 243 entries.Pass(), keys_to_remove.Pass(), |
| 234 entries_to_remove.Pass(), | |
| 235 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); | 244 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); |
| 236 | 245 |
| 237 base::RunLoop().RunUntilIdle(); | 246 base::RunLoop().RunUntilIdle(); |
| 238 } | 247 } |
| 239 | 248 |
| 240 TEST_F(DomDistillerDatabaseTest, TestDBSaveFailure) { | 249 TEST_F(ProtoDatabaseImplTest, TestDBSaveFailure) { |
| 241 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 250 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 242 | 251 |
| 243 MockDB* mock_db = new MockDB(); | 252 MockDB* mock_db = new MockDB(); |
| 244 MockDatabaseCaller caller; | 253 MockDatabaseCaller caller; |
| 245 scoped_ptr<EntryVector> entries(new EntryVector()); | 254 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries( |
| 246 scoped_ptr<EntryVector> entries_to_remove(new EntryVector()); | 255 new ProtoDatabase<TestProto>::KeyEntryVector()); |
| 256 scoped_ptr<std::vector<std::string>> keys_to_remove( |
| 257 new std::vector<std::string>()); |
| 247 | 258 |
| 248 EXPECT_CALL(*mock_db, Init(_)); | 259 EXPECT_CALL(*mock_db, Init(_)); |
| 249 EXPECT_CALL(caller, InitCallback(_)); | 260 EXPECT_CALL(caller, InitCallback(_)); |
| 250 db_->InitWithDatabase( | 261 db_->InitWithDatabase( |
| 251 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 262 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 252 base::FilePath(path), | 263 base::FilePath(path), |
| 253 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 264 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 254 | 265 |
| 255 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false)); | 266 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false)); |
| 256 EXPECT_CALL(caller, SaveCallback(false)); | 267 EXPECT_CALL(caller, SaveCallback(false)); |
| 257 db_->UpdateEntries( | 268 db_->UpdateEntries( |
| 258 entries.Pass(), | 269 entries.Pass(), keys_to_remove.Pass(), |
| 259 entries_to_remove.Pass(), | |
| 260 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); | 270 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); |
| 261 | 271 |
| 262 base::RunLoop().RunUntilIdle(); | 272 base::RunLoop().RunUntilIdle(); |
| 263 } | 273 } |
| 264 | 274 |
| 265 ACTION_P(VerifyRemoveEntries, expected) { | 275 // Test that ProtoDatabaseImpl calls Save on the underlying database with the |
| 266 const EntryVector& actual = arg1; | |
| 267 ExpectEntryPointersEquals(expected, actual); | |
| 268 return true; | |
| 269 } | |
| 270 | |
| 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 | 276 // correct entries to delete and that the caller's SaveCallback is called with |
| 273 // the correct success value. | 277 // the correct success value. |
| 274 TEST_F(DomDistillerDatabaseTest, TestDBRemoveSuccess) { | 278 TEST_F(ProtoDatabaseImplTest, TestDBRemoveSuccess) { |
| 275 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 279 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 276 | 280 |
| 277 MockDB* mock_db = new MockDB(); | 281 MockDB* mock_db = new MockDB(); |
| 278 MockDatabaseCaller caller; | 282 MockDatabaseCaller caller; |
| 279 EntryMap model = GetSmallModel(); | 283 EntryMap model = GetSmallModel(); |
| 280 | 284 |
| 281 EXPECT_CALL(*mock_db, Init(_)); | 285 EXPECT_CALL(*mock_db, Init(_)); |
| 282 EXPECT_CALL(caller, InitCallback(_)); | 286 EXPECT_CALL(caller, InitCallback(_)); |
| 283 db_->InitWithDatabase( | 287 db_->InitWithDatabase( |
| 284 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 288 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 285 base::FilePath(path), | 289 base::FilePath(path), |
| 286 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 290 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 287 | 291 |
| 288 scoped_ptr<EntryVector> entries(new EntryVector()); | 292 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries( |
| 289 scoped_ptr<EntryVector> entries_to_remove(new EntryVector()); | 293 new ProtoDatabase<TestProto>::KeyEntryVector()); |
| 294 scoped_ptr<std::vector<std::string>> keys_to_remove( |
| 295 new std::vector<std::string>()); |
| 290 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) { | 296 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) { |
| 291 entries_to_remove->push_back(it->second); | 297 keys_to_remove->push_back(it->second.id()); |
| 292 } | 298 } |
| 293 | 299 |
| 294 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(VerifyRemoveEntries(model)); | 300 std::vector<std::string> keys_copy(*keys_to_remove.get()); |
| 301 EXPECT_CALL(*mock_db, Save(_, keys_copy)).WillOnce(Return(true)); |
| 295 EXPECT_CALL(caller, SaveCallback(true)); | 302 EXPECT_CALL(caller, SaveCallback(true)); |
| 296 db_->UpdateEntries( | 303 db_->UpdateEntries( |
| 297 entries.Pass(), | 304 entries.Pass(), keys_to_remove.Pass(), |
| 298 entries_to_remove.Pass(), | |
| 299 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); | 305 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); |
| 300 | 306 |
| 301 base::RunLoop().RunUntilIdle(); | 307 base::RunLoop().RunUntilIdle(); |
| 302 } | 308 } |
| 303 | 309 |
| 304 TEST_F(DomDistillerDatabaseTest, TestDBRemoveFailure) { | 310 TEST_F(ProtoDatabaseImplTest, TestDBRemoveFailure) { |
| 305 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); | 311 base::FilePath path(FILE_PATH_LITERAL("/fake/path")); |
| 306 | 312 |
| 307 MockDB* mock_db = new MockDB(); | 313 MockDB* mock_db = new MockDB(); |
| 308 MockDatabaseCaller caller; | 314 MockDatabaseCaller caller; |
| 309 scoped_ptr<EntryVector> entries(new EntryVector()); | 315 scoped_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries( |
| 310 scoped_ptr<EntryVector> entries_to_remove(new EntryVector()); | 316 new ProtoDatabase<TestProto>::KeyEntryVector()); |
| 317 scoped_ptr<std::vector<std::string>> keys_to_remove( |
| 318 new std::vector<std::string>()); |
| 311 | 319 |
| 312 EXPECT_CALL(*mock_db, Init(_)); | 320 EXPECT_CALL(*mock_db, Init(_)); |
| 313 EXPECT_CALL(caller, InitCallback(_)); | 321 EXPECT_CALL(caller, InitCallback(_)); |
| 314 db_->InitWithDatabase( | 322 db_->InitWithDatabase( |
| 315 scoped_ptr<DomDistillerDatabase::Database>(mock_db), | 323 scoped_ptr<ProtoDatabaseImpl<TestProto>::Database>(mock_db), |
| 316 base::FilePath(path), | 324 base::FilePath(path), |
| 317 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | 325 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); |
| 318 | 326 |
| 319 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false)); | 327 EXPECT_CALL(*mock_db, Save(_, _)).WillOnce(Return(false)); |
| 320 EXPECT_CALL(caller, SaveCallback(false)); | 328 EXPECT_CALL(caller, SaveCallback(false)); |
| 321 db_->UpdateEntries( | 329 db_->UpdateEntries( |
| 322 entries.Pass(), | 330 entries.Pass(), keys_to_remove.Pass(), |
| 323 entries_to_remove.Pass(), | |
| 324 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); | 331 base::Bind(&MockDatabaseCaller::SaveCallback, base::Unretained(&caller))); |
| 325 | 332 |
| 326 base::RunLoop().RunUntilIdle(); | 333 base::RunLoop().RunUntilIdle(); |
| 327 } | 334 } |
| 328 | 335 |
| 329 | |
| 330 // This tests that normal usage of the real database does not cause any | 336 // This tests that normal usage of the real database does not cause any |
| 331 // threading violations. | 337 // threading violations. |
| 332 TEST(DomDistillerDatabaseThreadingTest, TestDBDestruction) { | 338 TEST(ProtoDatabaseImplThreadingTest, TestDBDestruction) { |
| 333 base::MessageLoop main_loop; | 339 base::MessageLoop main_loop; |
| 334 | 340 |
| 335 ScopedTempDir temp_dir; | 341 ScopedTempDir temp_dir; |
| 336 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 342 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 337 | 343 |
| 338 base::Thread db_thread("dbthread"); | 344 base::Thread db_thread("dbthread"); |
| 339 ASSERT_TRUE(db_thread.Start()); | 345 ASSERT_TRUE(db_thread.Start()); |
| 340 | 346 |
| 341 scoped_ptr<DomDistillerDatabase> db( | 347 scoped_ptr<ProtoDatabaseImpl<TestProto>> db( |
| 342 new DomDistillerDatabase(db_thread.message_loop_proxy())); | 348 new ProtoDatabaseImpl<TestProto>(db_thread.message_loop_proxy())); |
| 343 | 349 |
| 344 MockDatabaseCaller caller; | 350 MockDatabaseCaller caller; |
| 345 EXPECT_CALL(caller, InitCallback(_)); | 351 EXPECT_CALL(caller, InitCallback(_)); |
| 346 db->Init( | 352 db->Init(temp_dir.path(), base::Bind(&MockDatabaseCaller::InitCallback, |
| 347 temp_dir.path(), | 353 base::Unretained(&caller))); |
| 348 base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); | |
| 349 | 354 |
| 350 db.reset(); | 355 db.reset(); |
| 351 | 356 |
| 352 base::RunLoop run_loop; | 357 base::RunLoop run_loop; |
| 353 db_thread.message_loop_proxy()->PostTaskAndReply( | 358 db_thread.message_loop_proxy()->PostTaskAndReply( |
| 354 FROM_HERE, base::Bind(base::DoNothing), run_loop.QuitClosure()); | 359 FROM_HERE, base::Bind(base::DoNothing), run_loop.QuitClosure()); |
| 355 run_loop.Run(); | 360 run_loop.Run(); |
| 356 } | 361 } |
| 357 | 362 |
| 358 // Test that the LevelDB properly saves entries and that load returns the saved | 363 // 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 | 364 // 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. | 365 // saving and then re-opened to ensure that the data is properly persisted. |
| 361 void TestLevelDBSaveAndLoad(bool close_after_save) { | 366 void TestLevelDBSaveAndLoad(bool close_after_save) { |
| 362 ScopedTempDir temp_dir; | 367 ScopedTempDir temp_dir; |
| 363 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 368 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 364 | 369 |
| 365 EntryMap model = GetSmallModel(); | 370 EntryMap model = GetSmallModel(); |
| 366 EntryVector save_entries; | 371 |
| 367 EntryVector load_entries; | 372 ProtoDatabase<TestProto>::KeyEntryVector save_entries; |
| 368 EntryVector remove_entries; | 373 std::vector<TestProto> load_entries; |
| 374 std::vector<std::string> remove_keys; |
| 369 | 375 |
| 370 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) { | 376 for (EntryMap::iterator it = model.begin(); it != model.end(); ++it) { |
| 371 save_entries.push_back(it->second); | 377 save_entries.push_back(std::make_pair(it->second.id(), it->second)); |
| 372 } | 378 } |
| 373 | 379 |
| 374 scoped_ptr<DomDistillerDatabase::LevelDB> db( | 380 scoped_ptr<ProtoDatabaseImpl<TestProto>::LevelDB> db( |
| 375 new DomDistillerDatabase::LevelDB()); | 381 new ProtoDatabaseImpl<TestProto>::LevelDB()); |
| 376 EXPECT_TRUE(db->Init(temp_dir.path())); | 382 EXPECT_TRUE(db->Init(temp_dir.path())); |
| 377 EXPECT_TRUE(db->Save(save_entries, remove_entries)); | 383 EXPECT_TRUE(db->Save(save_entries, remove_keys)); |
| 378 | 384 |
| 379 if (close_after_save) { | 385 if (close_after_save) { |
| 380 db.reset(new DomDistillerDatabase::LevelDB()); | 386 db.reset(new ProtoDatabaseImpl<TestProto>::LevelDB()); |
| 381 EXPECT_TRUE(db->Init(temp_dir.path())); | 387 EXPECT_TRUE(db->Init(temp_dir.path())); |
| 382 } | 388 } |
| 383 | 389 |
| 384 EXPECT_TRUE(db->Load(&load_entries)); | 390 EXPECT_TRUE(db->Load(&load_entries)); |
| 385 | 391 |
| 386 ExpectEntryPointersEquals(model, load_entries); | 392 ExpectEntryPointersEquals(model, load_entries); |
| 387 } | 393 } |
| 388 | 394 |
| 389 TEST(DomDistillerDatabaseLevelDBTest, TestDBSaveAndLoad) { | 395 TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) { |
| 390 TestLevelDBSaveAndLoad(false); | 396 TestLevelDBSaveAndLoad(false); |
| 391 } | 397 } |
| 392 | 398 |
| 393 TEST(DomDistillerDatabaseLevelDBTest, TestDBCloseAndReopen) { | 399 TEST(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) { |
| 394 TestLevelDBSaveAndLoad(true); | 400 TestLevelDBSaveAndLoad(true); |
| 395 } | 401 } |
| 396 | 402 |
| 397 } // namespace dom_distiller | 403 } // namespace leveldb_proto |
| OLD | NEW |