Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 | |
| 5 #include "components/offline_pages/background/request_queue_store.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/files/file_path.h" | |
| 11 #include "base/files/scoped_temp_dir.h" | |
| 12 #include "base/test/test_simple_task_runner.h" | |
| 13 #include "base/threading/thread_task_runner_handle.h" | |
| 14 #include "components/offline_pages/background/request_queue_in_memory_store.h" | |
| 15 #include "components/offline_pages/background/request_queue_store_sql.h" | |
| 16 #include "components/offline_pages/background/save_page_request.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 namespace offline_pages { | |
| 20 | |
| 21 using UpdateStatus = RequestQueueStore::UpdateStatus; | |
| 22 | |
| 23 namespace { | |
| 24 const int64_t kRequestId = 42; | |
| 25 const GURL kUrl("http://example.com"); | |
| 26 const ClientId kClientId("bookmark", "1234"); | |
| 27 | |
| 28 enum class LastResult { | |
| 29 kNone, | |
| 30 kFalse, | |
| 31 kTrue, | |
| 32 }; | |
| 33 | |
| 34 bool operator==(const SavePageRequest& lhs, const SavePageRequest& rhs) { | |
| 35 return lhs.request_id() == rhs.request_id() && lhs.url() == rhs.url() && | |
| 36 lhs.client_id() == rhs.client_id() && | |
| 37 lhs.creation_time() == rhs.creation_time() && | |
| 38 lhs.activation_time() == rhs.activation_time() && | |
| 39 lhs.attempt_count() == rhs.attempt_count() && | |
| 40 lhs.last_attempt_time() == rhs.last_attempt_time(); | |
| 41 } | |
| 42 | |
| 43 } // namespace | |
| 44 | |
| 45 // Class that serves as a base for testing different implementations of the | |
| 46 // |RequestQueueStore|. Specific implementations extend the templatized version | |
| 47 // of this class and provide appropriate store factory. | |
| 48 class RequestQueueStoreTestBase : public testing::Test { | |
| 49 public: | |
| 50 RequestQueueStoreTestBase(); | |
| 51 | |
| 52 // Test overrides. | |
| 53 void TearDown() override; | |
| 54 | |
| 55 void PumpLoop(); | |
| 56 void ClearResults(); | |
| 57 | |
| 58 // Callback used for get requests. | |
| 59 void GetRequestsDone(bool result, | |
| 60 const std::vector<SavePageRequest>& requests); | |
| 61 // Callback used for add/update request. | |
| 62 void AddOrUpdateDone(UpdateStatus result); | |
| 63 // Callback used for remove requests. | |
| 64 void RemoveDone(bool result, int count); | |
| 65 // Callback used for reset. | |
| 66 void ResetDone(bool result); | |
| 67 | |
| 68 LastResult last_result() const { return last_result_; } | |
| 69 UpdateStatus last_update_status() const { return last_update_status_; } | |
| 70 int last_remove_count() const { return last_remove_count_; } | |
| 71 const std::vector<SavePageRequest>& last_requests() const { | |
| 72 return last_requests_; | |
| 73 } | |
| 74 | |
| 75 protected: | |
| 76 base::ScopedTempDir temp_directory_; | |
| 77 | |
| 78 private: | |
| 79 LastResult last_result_; | |
| 80 UpdateStatus last_update_status_; | |
| 81 int last_remove_count_; | |
| 82 std::vector<SavePageRequest> last_requests_; | |
| 83 | |
| 84 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | |
| 85 base::ThreadTaskRunnerHandle task_runner_handle_; | |
| 86 }; | |
| 87 | |
| 88 RequestQueueStoreTestBase::RequestQueueStoreTestBase() | |
| 89 : last_result_(LastResult::kNone), | |
| 90 last_update_status_(UpdateStatus::FAILED), | |
| 91 last_remove_count_(0), | |
| 92 task_runner_(new base::TestSimpleTaskRunner), | |
| 93 task_runner_handle_(task_runner_) { | |
| 94 EXPECT_TRUE(temp_directory_.CreateUniqueTempDir()); | |
| 95 } | |
| 96 | |
| 97 void RequestQueueStoreTestBase::TearDown() { | |
| 98 // Wait for all the pieces of the store to delete itself properly. | |
| 99 PumpLoop(); | |
| 100 } | |
| 101 | |
| 102 void RequestQueueStoreTestBase::PumpLoop() { | |
| 103 task_runner_->RunUntilIdle(); | |
| 104 } | |
| 105 | |
| 106 void RequestQueueStoreTestBase::ClearResults() { | |
| 107 last_result_ = LastResult::kNone; | |
| 108 last_update_status_ = UpdateStatus::FAILED; | |
| 109 last_remove_count_ = 0; | |
| 110 last_requests_.clear(); | |
| 111 } | |
| 112 | |
| 113 void RequestQueueStoreTestBase::GetRequestsDone( | |
| 114 bool result, | |
| 115 const std::vector<SavePageRequest>& requests) { | |
| 116 last_result_ = result ? LastResult::kTrue : LastResult::kFalse; | |
| 117 last_requests_ = requests; | |
| 118 } | |
| 119 | |
| 120 void RequestQueueStoreTestBase::AddOrUpdateDone(UpdateStatus status) { | |
| 121 last_update_status_ = status; | |
| 122 } | |
| 123 | |
| 124 void RequestQueueStoreTestBase::RemoveDone(bool result, int count) { | |
| 125 last_result_ = result ? LastResult::kTrue : LastResult::kFalse; | |
| 126 last_remove_count_ = count; | |
| 127 } | |
| 128 | |
| 129 void RequestQueueStoreTestBase::ResetDone(bool result) { | |
| 130 last_result_ = result ? LastResult::kTrue : LastResult::kFalse; | |
| 131 } | |
| 132 | |
| 133 // Defines interface for the store factory. | |
| 134 class RequestQueueStoreFactory { | |
| 135 public: | |
| 136 virtual RequestQueueStore* BuildStore(const base::FilePath& path) = 0; | |
| 137 }; | |
| 138 | |
| 139 // Implements a store factory for in memory store. | |
| 140 class RequestQueueInMemoryStoreFactory : public RequestQueueStoreFactory { | |
| 141 public: | |
| 142 RequestQueueStore* BuildStore(const base::FilePath& path) override { | |
| 143 RequestQueueStore* store = new RequestQueueInMemoryStore(); | |
| 144 return store; | |
| 145 } | |
| 146 }; | |
| 147 | |
| 148 // Implements a store factory for SQLite based implementation of the store. | |
| 149 class RequestQueueStoreSQLFactory : public RequestQueueStoreFactory { | |
| 150 public: | |
| 151 RequestQueueStore* BuildStore(const base::FilePath& path) override { | |
| 152 RequestQueueStore* store = | |
| 153 new RequestQueueStoreSQL(base::ThreadTaskRunnerHandle::Get(), path); | |
| 154 return store; | |
| 155 } | |
| 156 }; | |
| 157 | |
| 158 // Defines a store test fixture templatized by the store factory. | |
| 159 template <typename T> | |
| 160 class RequestQueueStoreTest : public RequestQueueStoreTestBase { | |
| 161 public: | |
| 162 std::unique_ptr<RequestQueueStore> BuildStore(); | |
| 163 | |
| 164 protected: | |
| 165 T factory_; | |
| 166 }; | |
| 167 | |
| 168 template <typename T> | |
| 169 std::unique_ptr<RequestQueueStore> RequestQueueStoreTest<T>::BuildStore() { | |
| 170 std::unique_ptr<RequestQueueStore> store( | |
| 171 factory_.BuildStore(temp_directory_.path())); | |
| 172 return store; | |
| 173 } | |
| 174 | |
| 175 // |StoreTypes| lists all factories, based on which the tests will be created. | |
| 176 typedef testing::Types<RequestQueueInMemoryStoreFactory, | |
| 177 RequestQueueStoreSQLFactory> | |
| 178 StoreTypes; | |
| 179 | |
| 180 // This portion causes test fixtures to be defined. | |
| 181 // Notice that in the store we are using "this->" to refer to the methods | |
| 182 // defined on the |RequestQuieueStoreBaseTest| class. That's by design. | |
| 183 TYPED_TEST_CASE(RequestQueueStoreTest, StoreTypes); | |
|
Pete Williamson
2016/06/15 23:37:05
Nifty! I like seeing the code only once for both
fgorski
2016/06/16 16:41:08
Acknowledged.
| |
| 184 | |
| 185 TYPED_TEST(RequestQueueStoreTest, GetRequestsEmpty) { | |
| 186 std::unique_ptr<RequestQueueStore> store(this->BuildStore()); | |
| 187 store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone, | |
| 188 base::Unretained(this))); | |
| 189 ASSERT_EQ(LastResult::kNone, this->last_result()); | |
| 190 this->PumpLoop(); | |
| 191 ASSERT_EQ(LastResult::kTrue, this->last_result()); | |
| 192 ASSERT_TRUE(this->last_requests().empty()); | |
| 193 } | |
| 194 | |
| 195 TYPED_TEST(RequestQueueStoreTest, AddRequest) { | |
| 196 std::unique_ptr<RequestQueueStore> store(this->BuildStore()); | |
| 197 base::Time creation_time = base::Time::Now(); | |
| 198 SavePageRequest request(kRequestId, kUrl, kClientId, creation_time); | |
| 199 | |
| 200 store->AddOrUpdateRequest( | |
| 201 request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, | |
| 202 base::Unretained(this))); | |
| 203 ASSERT_EQ(UpdateStatus::FAILED, this->last_update_status()); | |
|
Pete Williamson
2016/06/15 23:37:05
Nit - I'm not sure this assert (and others like it
fgorski
2016/06/16 16:41:08
Because we use the UpdateStatus enum verbatim, we
| |
| 204 this->PumpLoop(); | |
| 205 ASSERT_EQ(UpdateStatus::ADDED, this->last_update_status()); | |
| 206 | |
| 207 // Verifying get reqeust results after a request was added. | |
| 208 this->ClearResults(); | |
| 209 store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone, | |
| 210 base::Unretained(this))); | |
| 211 ASSERT_EQ(LastResult::kNone, this->last_result()); | |
| 212 this->PumpLoop(); | |
| 213 ASSERT_EQ(LastResult::kTrue, this->last_result()); | |
| 214 ASSERT_EQ(1ul, this->last_requests().size()); | |
| 215 ASSERT_TRUE(request == this->last_requests()[0]); | |
| 216 } | |
| 217 | |
| 218 TYPED_TEST(RequestQueueStoreTest, UpdateRequest) { | |
| 219 std::unique_ptr<RequestQueueStore> store(this->BuildStore()); | |
| 220 base::Time creation_time = base::Time::Now(); | |
| 221 SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); | |
| 222 store->AddOrUpdateRequest( | |
| 223 original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, | |
| 224 base::Unretained(this))); | |
| 225 this->PumpLoop(); | |
| 226 this->ClearResults(); | |
| 227 | |
| 228 base::Time new_creation_time = | |
| 229 creation_time + base::TimeDelta::FromMinutes(1); | |
| 230 base::Time activation_time = creation_time + base::TimeDelta::FromHours(6); | |
| 231 SavePageRequest updated_request(kRequestId, kUrl, kClientId, | |
| 232 new_creation_time, activation_time); | |
| 233 store->AddOrUpdateRequest( | |
| 234 updated_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, | |
| 235 base::Unretained(this))); | |
| 236 ASSERT_EQ(UpdateStatus::FAILED, this->last_update_status()); | |
| 237 this->PumpLoop(); | |
| 238 ASSERT_EQ(UpdateStatus::UPDATED, this->last_update_status()); | |
| 239 | |
| 240 // Verifying get reqeust results after a request was updated. | |
| 241 this->ClearResults(); | |
| 242 store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone, | |
| 243 base::Unretained(this))); | |
| 244 ASSERT_EQ(LastResult::kNone, this->last_result()); | |
| 245 this->PumpLoop(); | |
| 246 ASSERT_EQ(LastResult::kTrue, this->last_result()); | |
| 247 ASSERT_EQ(1ul, this->last_requests().size()); | |
| 248 ASSERT_TRUE(updated_request == this->last_requests()[0]); | |
| 249 } | |
| 250 | |
| 251 TYPED_TEST(RequestQueueStoreTest, RemoveRequest) { | |
| 252 std::unique_ptr<RequestQueueStore> store(this->BuildStore()); | |
| 253 base::Time creation_time = base::Time::Now(); | |
| 254 SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); | |
| 255 store->AddOrUpdateRequest( | |
| 256 original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, | |
| 257 base::Unretained(this))); | |
| 258 this->PumpLoop(); | |
| 259 this->ClearResults(); | |
| 260 | |
| 261 std::vector<int64_t> request_ids{kRequestId}; | |
| 262 store->RemoveRequests(request_ids, | |
| 263 base::Bind(&RequestQueueStoreTestBase::RemoveDone, | |
| 264 base::Unretained(this))); | |
| 265 ASSERT_EQ(LastResult::kNone, this->last_result()); | |
| 266 ASSERT_EQ(0, this->last_remove_count()); | |
| 267 this->PumpLoop(); | |
| 268 ASSERT_EQ(LastResult::kTrue, this->last_result()); | |
| 269 ASSERT_EQ(1, this->last_remove_count()); | |
| 270 ASSERT_EQ(0ul, this->last_requests().size()); | |
| 271 this->ClearResults(); | |
| 272 | |
|
Pete Williamson
2016/06/15 23:37:05
We could also do a Get and make sure the request i
fgorski
2016/06/16 16:41:08
Good point. Done
| |
| 273 // Removing a request that is missing fails. | |
| 274 store->RemoveRequests(request_ids, | |
| 275 base::Bind(&RequestQueueStoreTestBase::RemoveDone, | |
| 276 base::Unretained(this))); | |
| 277 ASSERT_EQ(LastResult::kNone, this->last_result()); | |
| 278 ASSERT_EQ(0, this->last_remove_count()); | |
| 279 this->PumpLoop(); | |
| 280 ASSERT_EQ(LastResult::kTrue, this->last_result()); | |
| 281 ASSERT_EQ(0, this->last_remove_count()); | |
| 282 } | |
| 283 | |
| 284 TYPED_TEST(RequestQueueStoreTest, ResetStore) { | |
| 285 std::unique_ptr<RequestQueueStore> store(this->BuildStore()); | |
| 286 base::Time creation_time = base::Time::Now(); | |
| 287 SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time); | |
| 288 store->AddOrUpdateRequest( | |
| 289 original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone, | |
| 290 base::Unretained(this))); | |
| 291 this->PumpLoop(); | |
| 292 this->ClearResults(); | |
| 293 | |
| 294 store->Reset(base::Bind(&RequestQueueStoreTestBase::ResetDone, | |
| 295 base::Unretained(this))); | |
| 296 ASSERT_EQ(LastResult::kNone, this->last_result()); | |
| 297 this->PumpLoop(); | |
| 298 ASSERT_EQ(LastResult::kTrue, this->last_result()); | |
| 299 ASSERT_EQ(0ul, this->last_requests().size()); | |
|
Pete Williamson
2016/06/15 23:37:05
Should we do a get here to verify that the store a
fgorski
2016/06/16 16:41:08
Done. I actually update the reset/recovery functio
| |
| 300 } | |
| 301 | |
| 302 } // offline_pages | |
| OLD | NEW |