OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/offline_page_metadata_store.h" | |
6 | |
7 #include <stdint.h> | |
8 | |
9 #include <memory> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/files/file_path.h" | |
13 #include "base/files/scoped_temp_dir.h" | |
14 #include "base/strings/string_number_conversions.h" | |
15 #include "base/strings/utf_string_conversions.h" | |
16 #include "base/test/test_simple_task_runner.h" | |
17 #include "base/threading/thread_task_runner_handle.h" | |
18 #include "components/offline_pages/offline_page_item.h" | |
19 #include "components/offline_pages/offline_page_metadata_store_sql.h" | |
20 #include "components/offline_pages/offline_page_model.h" | |
21 #include "sql/connection.h" | |
22 #include "sql/statement.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 namespace offline_pages { | |
26 | |
27 namespace { | |
28 | |
29 #define OFFLINE_PAGES_TABLE_V1 "offlinepages_v1" | |
30 | |
31 const char kTestClientNamespace[] = "CLIENT_NAMESPACE"; | |
32 const char kTestURL[] = "https://example.com"; | |
33 const char kOriginalTestURL[] = "https://example.com/foo"; | |
34 const ClientId kTestClientId1(kTestClientNamespace, "1234"); | |
35 const ClientId kTestClientId2(kTestClientNamespace, "5678"); | |
36 const base::FilePath::CharType kFilePath[] = | |
37 FILE_PATH_LITERAL("/offline_pages/example_com.mhtml"); | |
38 int64_t kFileSize = 234567LL; | |
39 int64_t kOfflineId = 12345LL; | |
40 | |
41 // Build a store with outdated schema to simulate the upgrading process. | |
42 // TODO(romax): move it to sql_unittests. | |
43 void BuildTestStoreWithSchemaFromM52(const base::FilePath& file) { | |
44 sql::Connection connection; | |
45 ASSERT_TRUE( | |
46 connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db")))); | |
47 ASSERT_TRUE(connection.is_open()); | |
48 ASSERT_TRUE(connection.BeginTransaction()); | |
49 ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1 | |
50 "(offline_id INTEGER PRIMARY KEY NOT NULL, " | |
51 "creation_time INTEGER NOT NULL, " | |
52 "file_size INTEGER NOT NULL, " | |
53 "version INTEGER NOT NULL, " | |
54 "last_access_time INTEGER NOT NULL, " | |
55 "access_count INTEGER NOT NULL, " | |
56 "status INTEGER NOT NULL DEFAULT 0, " | |
57 "user_initiated INTEGER, " | |
58 "client_namespace VARCHAR NOT NULL, " | |
59 "client_id VARCHAR NOT NULL, " | |
60 "online_url VARCHAR NOT NULL, " | |
61 "offline_url VARCHAR NOT NULL DEFAULT '', " | |
62 "file_path VARCHAR NOT NULL " | |
63 ")")); | |
64 ASSERT_TRUE(connection.CommitTransaction()); | |
65 sql::Statement statement(connection.GetUniqueStatement( | |
66 "INSERT INTO " OFFLINE_PAGES_TABLE_V1 | |
67 "(offline_id, creation_time, file_size, version, " | |
68 "last_access_time, access_count, client_namespace, " | |
69 "client_id, online_url, file_path) " | |
70 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | |
71 statement.BindInt64(0, kOfflineId); | |
72 statement.BindInt(1, 0); | |
73 statement.BindInt64(2, kFileSize); | |
74 statement.BindInt(3, 0); | |
75 statement.BindInt(4, 0); | |
76 statement.BindInt(5, 1); | |
77 statement.BindCString(6, kTestClientNamespace); | |
78 statement.BindString(7, kTestClientId2.id); | |
79 statement.BindCString(8, kTestURL); | |
80 statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII()); | |
81 ASSERT_TRUE(statement.Run()); | |
82 ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1)); | |
83 ASSERT_FALSE( | |
84 connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "expiration_time")); | |
85 } | |
86 | |
87 void BuildTestStoreWithSchemaFromM53(const base::FilePath& file) { | |
88 sql::Connection connection; | |
89 ASSERT_TRUE( | |
90 connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db")))); | |
91 ASSERT_TRUE(connection.is_open()); | |
92 ASSERT_TRUE(connection.BeginTransaction()); | |
93 ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1 | |
94 "(offline_id INTEGER PRIMARY KEY NOT NULL, " | |
95 "creation_time INTEGER NOT NULL, " | |
96 "file_size INTEGER NOT NULL, " | |
97 "version INTEGER NOT NULL, " | |
98 "last_access_time INTEGER NOT NULL, " | |
99 "access_count INTEGER NOT NULL, " | |
100 "status INTEGER NOT NULL DEFAULT 0, " | |
101 "user_initiated INTEGER, " | |
102 "expiration_time INTEGER NOT NULL DEFAULT 0, " | |
103 "client_namespace VARCHAR NOT NULL, " | |
104 "client_id VARCHAR NOT NULL, " | |
105 "online_url VARCHAR NOT NULL, " | |
106 "offline_url VARCHAR NOT NULL DEFAULT '', " | |
107 "file_path VARCHAR NOT NULL " | |
108 ")")); | |
109 ASSERT_TRUE(connection.CommitTransaction()); | |
110 sql::Statement statement(connection.GetUniqueStatement( | |
111 "INSERT INTO " OFFLINE_PAGES_TABLE_V1 | |
112 "(offline_id, creation_time, file_size, version, " | |
113 "last_access_time, access_count, client_namespace, " | |
114 "client_id, online_url, file_path, expiration_time) " | |
115 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | |
116 statement.BindInt64(0, kOfflineId); | |
117 statement.BindInt(1, 0); | |
118 statement.BindInt64(2, kFileSize); | |
119 statement.BindInt(3, 0); | |
120 statement.BindInt(4, 0); | |
121 statement.BindInt(5, 1); | |
122 statement.BindCString(6, kTestClientNamespace); | |
123 statement.BindString(7, kTestClientId2.id); | |
124 statement.BindCString(8, kTestURL); | |
125 statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII()); | |
126 statement.BindInt64(10, base::Time::Now().ToInternalValue()); | |
127 ASSERT_TRUE(statement.Run()); | |
128 ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1)); | |
129 ASSERT_FALSE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "title")); | |
130 } | |
131 | |
132 void BuildTestStoreWithSchemaFromM54(const base::FilePath& file) { | |
133 sql::Connection connection; | |
134 ASSERT_TRUE( | |
135 connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db")))); | |
136 ASSERT_TRUE(connection.is_open()); | |
137 ASSERT_TRUE(connection.BeginTransaction()); | |
138 ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1 | |
139 "(offline_id INTEGER PRIMARY KEY NOT NULL, " | |
140 "creation_time INTEGER NOT NULL, " | |
141 "file_size INTEGER NOT NULL, " | |
142 "version INTEGER NOT NULL, " | |
143 "last_access_time INTEGER NOT NULL, " | |
144 "access_count INTEGER NOT NULL, " | |
145 "status INTEGER NOT NULL DEFAULT 0, " | |
146 "user_initiated INTEGER, " | |
147 "expiration_time INTEGER NOT NULL DEFAULT 0, " | |
148 "client_namespace VARCHAR NOT NULL, " | |
149 "client_id VARCHAR NOT NULL, " | |
150 "online_url VARCHAR NOT NULL, " | |
151 "offline_url VARCHAR NOT NULL DEFAULT '', " | |
152 "file_path VARCHAR NOT NULL " | |
153 "title VARCHAR NOT NULL DEFAULT ''" | |
154 ")")); | |
155 ASSERT_TRUE(connection.CommitTransaction()); | |
156 sql::Statement statement(connection.GetUniqueStatement( | |
157 "INSERT INTO " OFFLINE_PAGES_TABLE_V1 | |
158 "(offline_id, creation_time, file_size, version, " | |
159 "last_access_time, access_count, client_namespace, " | |
160 "client_id, online_url, file_path, expiration_time, title) " | |
161 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | |
162 statement.BindInt64(0, kOfflineId); | |
163 statement.BindInt(1, 0); | |
164 statement.BindInt64(2, kFileSize); | |
165 statement.BindInt(3, 0); | |
166 statement.BindInt(4, 0); | |
167 statement.BindInt(5, 1); | |
168 statement.BindCString(6, kTestClientNamespace); | |
169 statement.BindString(7, kTestClientId2.id); | |
170 statement.BindCString(8, kTestURL); | |
171 statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII()); | |
172 statement.BindInt64(10, base::Time::Now().ToInternalValue()); | |
173 statement.BindString16(11, base::UTF8ToUTF16("Test title")); | |
174 ASSERT_TRUE(statement.Run()); | |
175 ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1)); | |
176 ASSERT_TRUE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "version")); | |
177 ASSERT_TRUE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "status")); | |
178 ASSERT_TRUE( | |
179 connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "user_initiated")); | |
180 ASSERT_TRUE( | |
181 connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "offline_url")); | |
182 } | |
183 | |
184 void BuildTestStoreWithSchemaFromM55(const base::FilePath& file) { | |
185 sql::Connection connection; | |
186 ASSERT_TRUE( | |
187 connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db")))); | |
188 ASSERT_TRUE(connection.is_open()); | |
189 ASSERT_TRUE(connection.BeginTransaction()); | |
190 ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1 | |
191 "(offline_id INTEGER PRIMARY KEY NOT NULL, " | |
192 "creation_time INTEGER NOT NULL, " | |
193 "file_size INTEGER NOT NULL, " | |
194 "last_access_time INTEGER NOT NULL, " | |
195 "access_count INTEGER NOT NULL, " | |
196 "expiration_time INTEGER NOT NULL DEFAULT 0, " | |
197 "client_namespace VARCHAR NOT NULL, " | |
198 "client_id VARCHAR NOT NULL, " | |
199 "online_url VARCHAR NOT NULL, " | |
200 "file_path VARCHAR NOT NULL, " | |
201 "title VARCHAR NOT NULL DEFAULT ''" | |
202 ")")); | |
203 ASSERT_TRUE(connection.CommitTransaction()); | |
204 sql::Statement statement(connection.GetUniqueStatement( | |
205 "INSERT INTO " OFFLINE_PAGES_TABLE_V1 | |
206 "(offline_id, creation_time, file_size, " | |
207 "last_access_time, access_count, client_namespace, " | |
208 "client_id, online_url, file_path, expiration_time, title) " | |
209 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | |
210 statement.BindInt64(0, kOfflineId); | |
211 statement.BindInt(1, 0); | |
212 statement.BindInt64(2, kFileSize); | |
213 statement.BindInt(3, 0); | |
214 statement.BindInt(4, 1); | |
215 statement.BindCString(5, kTestClientNamespace); | |
216 statement.BindString(6, kTestClientId2.id); | |
217 statement.BindCString(7, kTestURL); | |
218 statement.BindString(8, base::FilePath(kFilePath).MaybeAsASCII()); | |
219 statement.BindInt64(9, base::Time::Now().ToInternalValue()); | |
220 statement.BindString16(10, base::UTF8ToUTF16("Test title")); | |
221 ASSERT_TRUE(statement.Run()); | |
222 ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1)); | |
223 ASSERT_TRUE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "title")); | |
224 } | |
225 | |
226 class OfflinePageMetadataStoreFactory { | |
227 public: | |
228 OfflinePageMetadataStore* BuildStore(const base::FilePath& file_path) { | |
229 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
230 base::ThreadTaskRunnerHandle::Get(), file_path); | |
231 return store; | |
232 } | |
233 | |
234 OfflinePageMetadataStore* BuildStoreM52(const base::FilePath& file_path) { | |
235 BuildTestStoreWithSchemaFromM52(file_path); | |
236 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
237 base::ThreadTaskRunnerHandle::Get(), file_path); | |
238 return store; | |
239 } | |
240 | |
241 OfflinePageMetadataStore* BuildStoreM53(const base::FilePath& file_path) { | |
242 BuildTestStoreWithSchemaFromM53(file_path); | |
243 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
244 base::ThreadTaskRunnerHandle::Get(), file_path); | |
245 return store; | |
246 } | |
247 | |
248 OfflinePageMetadataStore* BuildStoreM54(const base::FilePath& file_path) { | |
249 BuildTestStoreWithSchemaFromM54(file_path); | |
250 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
251 base::ThreadTaskRunnerHandle::Get(), file_path); | |
252 return store; | |
253 } | |
254 | |
255 OfflinePageMetadataStore* BuildStoreM55(const base::FilePath& file_path) { | |
256 BuildTestStoreWithSchemaFromM55(file_path); | |
257 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
258 base::ThreadTaskRunnerHandle::Get(), file_path); | |
259 return store; | |
260 } | |
261 }; | |
262 | |
263 enum CalledCallback { NONE, LOAD, ADD, UPDATE, REMOVE, RESET }; | |
264 enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE }; | |
265 | |
266 class OfflinePageMetadataStoreTest : public testing::Test { | |
267 public: | |
268 OfflinePageMetadataStoreTest(); | |
269 ~OfflinePageMetadataStoreTest() override; | |
270 | |
271 void TearDown() override { | |
272 // Wait for all the pieces of the store to delete itself properly. | |
273 PumpLoop(); | |
274 } | |
275 | |
276 std::unique_ptr<OfflinePageMetadataStore> BuildStore(); | |
277 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM52(); | |
278 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM53(); | |
279 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM54(); | |
280 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM55(); | |
281 | |
282 void PumpLoop(); | |
283 | |
284 void GetOfflinePagesCallback( | |
285 OfflinePageMetadataStore::LoadStatus load_status, | |
286 const std::vector<OfflinePageItem>& offline_pages); | |
287 void AddCallback(ItemActionStatus status); | |
288 void UpdateCallback(CalledCallback called_callback, | |
289 std::unique_ptr<OfflinePagesUpdateResult> result); | |
290 void ResetCallback(bool status); | |
291 | |
292 void ClearResults(); | |
293 | |
294 OfflinePageItem CheckThatStoreHasOneItem(); | |
295 void CheckThatOfflinePageCanBeSaved( | |
296 std::unique_ptr<OfflinePageMetadataStore> store); | |
297 | |
298 OfflinePagesUpdateResult* last_update_result() { | |
299 return last_update_result_.get(); | |
300 } | |
301 | |
302 protected: | |
303 CalledCallback last_called_callback_; | |
304 Status last_status_; | |
305 std::unique_ptr<OfflinePagesUpdateResult> last_update_result_; | |
306 std::vector<OfflinePageItem> offline_pages_; | |
307 OfflinePageMetadataStoreFactory factory_; | |
308 | |
309 base::ScopedTempDir temp_directory_; | |
310 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | |
311 base::ThreadTaskRunnerHandle task_runner_handle_; | |
312 }; | |
313 | |
314 OfflinePageMetadataStoreTest::OfflinePageMetadataStoreTest() | |
315 : last_called_callback_(NONE), | |
316 last_status_(STATUS_NONE), | |
317 task_runner_(new base::TestSimpleTaskRunner), | |
318 task_runner_handle_(task_runner_) { | |
319 EXPECT_TRUE(temp_directory_.CreateUniqueTempDir()); | |
320 } | |
321 | |
322 OfflinePageMetadataStoreTest::~OfflinePageMetadataStoreTest() {} | |
323 | |
324 void OfflinePageMetadataStoreTest::PumpLoop() { | |
325 task_runner_->RunUntilIdle(); | |
326 } | |
327 | |
328 void OfflinePageMetadataStoreTest::GetOfflinePagesCallback( | |
329 OfflinePageMetadataStore::LoadStatus load_status, | |
330 const std::vector<OfflinePageItem>& offline_pages) { | |
331 last_called_callback_ = LOAD; | |
332 last_status_ = load_status == OfflinePageMetadataStore::LOAD_SUCCEEDED ? | |
333 STATUS_TRUE : STATUS_FALSE; | |
334 offline_pages_.swap(const_cast<std::vector<OfflinePageItem>&>(offline_pages)); | |
335 } | |
336 | |
337 void OfflinePageMetadataStoreTest::AddCallback(ItemActionStatus status) { | |
338 last_called_callback_ = ADD; | |
339 // TODO(fgorski): Add specific add status. | |
340 // last_item_status_ = status; | |
341 last_status_ = | |
342 status == ItemActionStatus::SUCCESS ? STATUS_TRUE : STATUS_FALSE; | |
343 } | |
344 | |
345 void OfflinePageMetadataStoreTest::UpdateCallback( | |
346 CalledCallback called_callback, | |
347 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
348 last_called_callback_ = called_callback; | |
349 last_status_ = result->updated_items.size() > 0 ? STATUS_TRUE : STATUS_FALSE; | |
350 last_update_result_ = std::move(result); | |
351 } | |
352 | |
353 void OfflinePageMetadataStoreTest::ResetCallback(bool status) { | |
354 last_called_callback_ = RESET; | |
355 last_status_ = status ? STATUS_TRUE : STATUS_FALSE; | |
356 } | |
357 | |
358 void OfflinePageMetadataStoreTest::ClearResults() { | |
359 last_called_callback_ = NONE; | |
360 last_status_ = STATUS_NONE; | |
361 offline_pages_.clear(); | |
362 last_update_result_.reset(nullptr); | |
363 } | |
364 | |
365 OfflinePageItem OfflinePageMetadataStoreTest::CheckThatStoreHasOneItem() { | |
366 EXPECT_EQ(LOAD, last_called_callback_); | |
367 EXPECT_EQ(STATUS_TRUE, last_status_); | |
368 EXPECT_EQ(1U, offline_pages_.size()); | |
369 | |
370 return offline_pages_[0]; | |
371 } | |
372 | |
373 void OfflinePageMetadataStoreTest::CheckThatOfflinePageCanBeSaved( | |
374 std::unique_ptr<OfflinePageMetadataStore> store) { | |
375 size_t store_size = offline_pages_.size(); | |
376 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
377 base::FilePath(kFilePath), kFileSize); | |
378 offline_page.title = base::UTF8ToUTF16("a title"); | |
379 base::Time expiration_time = base::Time::Now(); | |
380 offline_page.expiration_time = expiration_time; | |
381 offline_page.original_url = GURL(kOriginalTestURL); | |
382 | |
383 store->AddOfflinePage(offline_page, | |
384 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
385 base::Unretained(this))); | |
386 PumpLoop(); | |
387 EXPECT_EQ(ADD, last_called_callback_); | |
388 EXPECT_EQ(STATUS_TRUE, last_status_); | |
389 ClearResults(); | |
390 | |
391 // Close the store first to ensure file lock is removed. | |
392 store.reset(); | |
393 store = BuildStore(); | |
394 PumpLoop(); | |
395 | |
396 EXPECT_EQ(LOAD, last_called_callback_); | |
397 EXPECT_EQ(STATUS_TRUE, last_status_); | |
398 ASSERT_EQ(store_size + 1, offline_pages_.size()); | |
399 if (store_size > 0 && | |
400 offline_pages_[0].offline_id != offline_page.offline_id) { | |
401 std::swap(offline_pages_[0], offline_pages_[1]); | |
402 } | |
403 EXPECT_EQ(offline_page, offline_pages_[0]); | |
404 } | |
405 | |
406 std::unique_ptr<OfflinePageMetadataStore> | |
407 OfflinePageMetadataStoreTest::BuildStore() { | |
408 std::unique_ptr<OfflinePageMetadataStore> store( | |
409 factory_.BuildStore(temp_directory_.GetPath())); | |
410 PumpLoop(); | |
411 store->GetOfflinePages( | |
412 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
413 base::Unretained(this))); | |
414 PumpLoop(); | |
415 return store; | |
416 } | |
417 | |
418 std::unique_ptr<OfflinePageMetadataStore> | |
419 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM52() { | |
420 std::unique_ptr<OfflinePageMetadataStore> store( | |
421 factory_.BuildStoreM52(temp_directory_.GetPath())); | |
422 PumpLoop(); | |
423 store->GetOfflinePages( | |
424 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
425 base::Unretained(this))); | |
426 PumpLoop(); | |
427 return store; | |
428 } | |
429 | |
430 std::unique_ptr<OfflinePageMetadataStore> | |
431 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM53() { | |
432 std::unique_ptr<OfflinePageMetadataStore> store( | |
433 factory_.BuildStoreM53(temp_directory_.GetPath())); | |
434 PumpLoop(); | |
435 store->GetOfflinePages( | |
436 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
437 base::Unretained(this))); | |
438 PumpLoop(); | |
439 return store; | |
440 } | |
441 | |
442 std::unique_ptr<OfflinePageMetadataStore> | |
443 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM54() { | |
444 std::unique_ptr<OfflinePageMetadataStore> store( | |
445 factory_.BuildStoreM53(temp_directory_.GetPath())); | |
446 PumpLoop(); | |
447 store->GetOfflinePages( | |
448 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
449 base::Unretained(this))); | |
450 PumpLoop(); | |
451 return store; | |
452 } | |
453 | |
454 std::unique_ptr<OfflinePageMetadataStore> | |
455 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM55() { | |
456 std::unique_ptr<OfflinePageMetadataStore> store( | |
457 factory_.BuildStoreM55(temp_directory_.GetPath())); | |
458 PumpLoop(); | |
459 store->GetOfflinePages( | |
460 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
461 base::Unretained(this))); | |
462 PumpLoop(); | |
463 return store; | |
464 } | |
465 | |
466 // Loads empty store and makes sure that there are no offline pages stored in | |
467 // it. | |
468 TEST_F(OfflinePageMetadataStoreTest, LoadEmptyStore) { | |
469 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
470 EXPECT_EQ(LOAD, last_called_callback_); | |
471 EXPECT_EQ(STATUS_TRUE, last_status_); | |
472 EXPECT_EQ(0U, offline_pages_.size()); | |
473 } | |
474 | |
475 TEST_F(OfflinePageMetadataStoreTest, GetOfflinePagesFromInvalidStore) { | |
476 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
477 OfflinePageMetadataStoreSQL* sql_store = | |
478 static_cast<OfflinePageMetadataStoreSQL*>(store.get()); | |
479 | |
480 sql_store->SetStateForTesting(StoreState::NOT_LOADED, false); | |
481 store->GetOfflinePages( | |
482 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
483 base::Unretained(this))); | |
484 PumpLoop(); | |
485 EXPECT_EQ(LOAD, last_called_callback_); | |
486 EXPECT_EQ(0UL, offline_pages_.size()); | |
487 EXPECT_EQ(STATUS_FALSE, last_status_); | |
488 | |
489 sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false); | |
490 store->GetOfflinePages( | |
491 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
492 base::Unretained(this))); | |
493 PumpLoop(); | |
494 EXPECT_EQ(LOAD, last_called_callback_); | |
495 EXPECT_EQ(0UL, offline_pages_.size()); | |
496 EXPECT_EQ(STATUS_FALSE, last_status_); | |
497 | |
498 sql_store->SetStateForTesting(StoreState::FAILED_RESET, false); | |
499 store->GetOfflinePages( | |
500 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
501 base::Unretained(this))); | |
502 PumpLoop(); | |
503 EXPECT_EQ(LOAD, last_called_callback_); | |
504 EXPECT_EQ(0UL, offline_pages_.size()); | |
505 EXPECT_EQ(STATUS_FALSE, last_status_); | |
506 | |
507 sql_store->SetStateForTesting(StoreState::LOADED, true); | |
508 store->GetOfflinePages( | |
509 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
510 base::Unretained(this))); | |
511 PumpLoop(); | |
512 EXPECT_EQ(LOAD, last_called_callback_); | |
513 EXPECT_EQ(0UL, offline_pages_.size()); | |
514 EXPECT_EQ(STATUS_FALSE, last_status_); | |
515 | |
516 sql_store->SetStateForTesting(StoreState::NOT_LOADED, true); | |
517 store->GetOfflinePages( | |
518 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
519 base::Unretained(this))); | |
520 PumpLoop(); | |
521 EXPECT_EQ(LOAD, last_called_callback_); | |
522 EXPECT_EQ(0UL, offline_pages_.size()); | |
523 EXPECT_EQ(STATUS_FALSE, last_status_); | |
524 | |
525 sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false); | |
526 store->GetOfflinePages( | |
527 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
528 base::Unretained(this))); | |
529 PumpLoop(); | |
530 EXPECT_EQ(LOAD, last_called_callback_); | |
531 EXPECT_EQ(0UL, offline_pages_.size()); | |
532 EXPECT_EQ(STATUS_FALSE, last_status_); | |
533 | |
534 sql_store->SetStateForTesting(StoreState::FAILED_RESET, false); | |
535 store->GetOfflinePages( | |
536 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
537 base::Unretained(this))); | |
538 PumpLoop(); | |
539 EXPECT_EQ(LOAD, last_called_callback_); | |
540 EXPECT_EQ(0UL, offline_pages_.size()); | |
541 EXPECT_EQ(STATUS_FALSE, last_status_); | |
542 | |
543 } | |
544 | |
545 // Loads a store which has an outdated schema. | |
546 // This test case would crash if it's not handling correctly when we're loading | |
547 // old version stores. | |
548 // TODO(romax): Move this to sql_unittest. | |
549 TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) { | |
550 std::unique_ptr<OfflinePageMetadataStore> store( | |
551 BuildStoreWithSchemaFromM52()); | |
552 | |
553 CheckThatStoreHasOneItem(); | |
554 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
555 } | |
556 | |
557 // Loads a store which has an outdated schema. | |
558 // This test case would crash if it's not handling correctly when we're loading | |
559 // old version stores. | |
560 // TODO(romax): Move this to sql_unittest. | |
561 TEST_F(OfflinePageMetadataStoreTest, LoadVersion53Store) { | |
562 std::unique_ptr<OfflinePageMetadataStore> store( | |
563 BuildStoreWithSchemaFromM53()); | |
564 | |
565 OfflinePageItem item = CheckThatStoreHasOneItem(); | |
566 // We should have a valid expiration time after upgrade. | |
567 EXPECT_NE(base::Time::FromInternalValue(0), | |
568 offline_pages_[0].expiration_time); | |
569 | |
570 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
571 } | |
572 | |
573 // Loads a string with schema from M54. | |
574 // Because for now we only reduce the number of fields it just makes sure there | |
575 // are no crashes in the process. | |
576 // TODO(romax): Move this to sql_unittest. | |
577 TEST_F(OfflinePageMetadataStoreTest, LoadVersion54Store) { | |
578 std::unique_ptr<OfflinePageMetadataStore> store( | |
579 BuildStoreWithSchemaFromM54()); | |
580 | |
581 OfflinePageItem item = CheckThatStoreHasOneItem(); | |
582 | |
583 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
584 } | |
585 | |
586 // Loads a string with schema from M55. | |
587 // Because for now we only reduce the number of fields it just makes sure there | |
588 // are no crashes in the process. | |
589 // TODO(romax): Move this to sql_unittest. | |
590 TEST_F(OfflinePageMetadataStoreTest, LoadVersion55Store) { | |
591 std::unique_ptr<OfflinePageMetadataStore> store( | |
592 BuildStoreWithSchemaFromM55()); | |
593 | |
594 OfflinePageItem item = CheckThatStoreHasOneItem(); | |
595 | |
596 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
597 } | |
598 | |
599 // Adds metadata of an offline page into a store and then opens the store | |
600 // again to make sure that stored metadata survives store restarts. | |
601 TEST_F(OfflinePageMetadataStoreTest, AddOfflinePage) { | |
602 CheckThatOfflinePageCanBeSaved(BuildStore()); | |
603 } | |
604 | |
605 TEST_F(OfflinePageMetadataStoreTest, AddSameOfflinePageTwice) { | |
606 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
607 | |
608 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
609 base::FilePath(kFilePath), kFileSize); | |
610 offline_page.title = base::UTF8ToUTF16("a title"); | |
611 base::Time expiration_time = base::Time::Now(); | |
612 offline_page.expiration_time = expiration_time; | |
613 | |
614 store->AddOfflinePage(offline_page, | |
615 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
616 base::Unretained(this))); | |
617 PumpLoop(); | |
618 EXPECT_EQ(ADD, last_called_callback_); | |
619 EXPECT_EQ(STATUS_TRUE, last_status_); | |
620 ClearResults(); | |
621 | |
622 store->AddOfflinePage(offline_page, | |
623 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
624 base::Unretained(this))); | |
625 PumpLoop(); | |
626 EXPECT_EQ(ADD, last_called_callback_); | |
627 EXPECT_EQ(STATUS_FALSE, last_status_); | |
628 } | |
629 | |
630 // Tests removing offline page metadata from the store, for which it first adds | |
631 // metadata of an offline page. | |
632 TEST_F(OfflinePageMetadataStoreTest, RemoveOfflinePage) { | |
633 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
634 | |
635 // Add an offline page. | |
636 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
637 base::FilePath(kFilePath), kFileSize); | |
638 store->AddOfflinePage(offline_page, | |
639 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
640 base::Unretained(this))); | |
641 PumpLoop(); | |
642 EXPECT_EQ(ADD, last_called_callback_); | |
643 EXPECT_EQ(STATUS_TRUE, last_status_); | |
644 | |
645 ClearResults(); | |
646 | |
647 // Load the store. | |
648 store->GetOfflinePages( | |
649 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
650 base::Unretained(this))); | |
651 PumpLoop(); | |
652 EXPECT_EQ(LOAD, last_called_callback_); | |
653 EXPECT_EQ(1U, offline_pages_.size()); | |
654 | |
655 // Remove the offline page. | |
656 std::vector<int64_t> ids_to_remove; | |
657 ids_to_remove.push_back(offline_page.offline_id); | |
658 store->RemoveOfflinePages( | |
659 ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback, | |
660 base::Unretained(this), REMOVE)); | |
661 PumpLoop(); | |
662 EXPECT_EQ(REMOVE, last_called_callback_); | |
663 EXPECT_EQ(STATUS_TRUE, last_status_); | |
664 ASSERT_TRUE(last_update_result() != nullptr); | |
665 EXPECT_EQ(1UL, last_update_result()->item_statuses.size()); | |
666 EXPECT_EQ(ItemActionStatus::SUCCESS, | |
667 last_update_result()->item_statuses.begin()->second); | |
668 EXPECT_EQ(1UL, last_update_result()->updated_items.size()); | |
669 EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin())); | |
670 | |
671 ClearResults(); | |
672 | |
673 // Load the store. | |
674 store->GetOfflinePages( | |
675 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
676 base::Unretained(this))); | |
677 PumpLoop(); | |
678 EXPECT_EQ(LOAD, last_called_callback_); | |
679 EXPECT_EQ(0U, offline_pages_.size()); | |
680 | |
681 ClearResults(); | |
682 | |
683 // Close and reload the store. | |
684 store.reset(); | |
685 store = BuildStore(); | |
686 EXPECT_EQ(LOAD, last_called_callback_); | |
687 EXPECT_EQ(STATUS_TRUE, last_status_); | |
688 EXPECT_EQ(0U, offline_pages_.size()); | |
689 } | |
690 | |
691 // Adds metadata of multiple offline pages into a store and removes some. | |
692 TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) { | |
693 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
694 | |
695 // Add an offline page. | |
696 OfflinePageItem offline_page_1(GURL(kTestURL), 12345LL, kTestClientId1, | |
697 base::FilePath(kFilePath), kFileSize); | |
698 store->AddOfflinePage(offline_page_1, | |
699 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
700 base::Unretained(this))); | |
701 PumpLoop(); | |
702 EXPECT_EQ(ADD, last_called_callback_); | |
703 EXPECT_EQ(STATUS_TRUE, last_status_); | |
704 | |
705 ClearResults(); | |
706 | |
707 // Add anther offline page. | |
708 base::FilePath file_path_2 = | |
709 base::FilePath(FILE_PATH_LITERAL("//other.page.com.mhtml")); | |
710 OfflinePageItem offline_page_2(GURL("https://other.page.com"), 5678LL, | |
711 kTestClientId2, file_path_2, 12345, | |
712 base::Time::Now()); | |
713 offline_page_2.expiration_time = base::Time::Now(); | |
714 offline_page_2.original_url = GURL("https://example.com/bar"); | |
715 store->AddOfflinePage(offline_page_2, | |
716 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
717 base::Unretained(this))); | |
718 PumpLoop(); | |
719 EXPECT_EQ(ADD, last_called_callback_); | |
720 EXPECT_EQ(STATUS_TRUE, last_status_); | |
721 | |
722 ClearResults(); | |
723 | |
724 // Load the store. | |
725 store->GetOfflinePages( | |
726 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
727 base::Unretained(this))); | |
728 PumpLoop(); | |
729 | |
730 EXPECT_EQ(LOAD, last_called_callback_); | |
731 EXPECT_EQ(STATUS_TRUE, last_status_); | |
732 EXPECT_EQ(2U, offline_pages_.size()); | |
733 | |
734 // Remove the offline page. | |
735 std::vector<int64_t> ids_to_remove; | |
736 ids_to_remove.push_back(offline_page_1.offline_id); | |
737 store->RemoveOfflinePages( | |
738 ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback, | |
739 base::Unretained(this), REMOVE)); | |
740 PumpLoop(); | |
741 EXPECT_EQ(REMOVE, last_called_callback_); | |
742 EXPECT_EQ(STATUS_TRUE, last_status_); | |
743 ASSERT_TRUE(last_update_result() != nullptr); | |
744 EXPECT_EQ(1UL, last_update_result()->item_statuses.size()); | |
745 EXPECT_EQ(ItemActionStatus::SUCCESS, | |
746 last_update_result()->item_statuses.begin()->second); | |
747 EXPECT_EQ(1UL, last_update_result()->updated_items.size()); | |
748 EXPECT_EQ(offline_page_1, *(last_update_result()->updated_items.begin())); | |
749 | |
750 ClearResults(); | |
751 | |
752 // Close and reload the store. | |
753 store.reset(); | |
754 store = BuildStore(); | |
755 store->GetOfflinePages( | |
756 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
757 base::Unretained(this))); | |
758 PumpLoop(); | |
759 | |
760 EXPECT_EQ(LOAD, last_called_callback_); | |
761 EXPECT_EQ(STATUS_TRUE, last_status_); | |
762 ASSERT_EQ(1U, offline_pages_.size()); | |
763 EXPECT_EQ(offline_page_2.url, offline_pages_[0].url); | |
764 EXPECT_EQ(offline_page_2.offline_id, offline_pages_[0].offline_id); | |
765 EXPECT_EQ(offline_page_2.file_path, offline_pages_[0].file_path); | |
766 EXPECT_EQ(offline_page_2.file_size, offline_pages_[0].file_size); | |
767 EXPECT_EQ(offline_page_2.creation_time, offline_pages_[0].creation_time); | |
768 EXPECT_EQ(offline_page_2.last_access_time, | |
769 offline_pages_[0].last_access_time); | |
770 EXPECT_EQ(offline_page_2.expiration_time, offline_pages_[0].expiration_time); | |
771 EXPECT_EQ(offline_page_2.access_count, offline_pages_[0].access_count); | |
772 EXPECT_EQ(offline_page_2.client_id, offline_pages_[0].client_id); | |
773 } | |
774 | |
775 // Tests updating offline page metadata from the store. | |
776 TEST_F(OfflinePageMetadataStoreTest, UpdateOfflinePage) { | |
777 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
778 | |
779 // First, adds a fresh page. | |
780 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
781 base::FilePath(kFilePath), kFileSize); | |
782 store->AddOfflinePage(offline_page, | |
783 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
784 base::Unretained(this))); | |
785 PumpLoop(); | |
786 EXPECT_EQ(ADD, last_called_callback_); | |
787 EXPECT_EQ(STATUS_TRUE, last_status_); | |
788 | |
789 ClearResults(); | |
790 store->GetOfflinePages( | |
791 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
792 base::Unretained(this))); | |
793 PumpLoop(); | |
794 | |
795 EXPECT_EQ(LOAD, last_called_callback_); | |
796 EXPECT_EQ(STATUS_TRUE, last_status_); | |
797 ASSERT_EQ(1U, offline_pages_.size()); | |
798 EXPECT_EQ(offline_page, offline_pages_[0]); | |
799 | |
800 // Then update some data. | |
801 offline_page.file_size = kFileSize + 1; | |
802 offline_page.access_count++; | |
803 offline_page.expiration_time = base::Time::Now(); | |
804 offline_page.original_url = GURL("https://example.com/bar"); | |
805 std::vector<OfflinePageItem> items_to_update; | |
806 items_to_update.push_back(offline_page); | |
807 store->UpdateOfflinePages( | |
808 items_to_update, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback, | |
809 base::Unretained(this), UPDATE)); | |
810 PumpLoop(); | |
811 EXPECT_EQ(UPDATE, last_called_callback_); | |
812 EXPECT_EQ(STATUS_TRUE, last_status_); | |
813 ASSERT_TRUE(last_update_result() != nullptr); | |
814 EXPECT_EQ(1UL, last_update_result()->item_statuses.size()); | |
815 EXPECT_EQ(ItemActionStatus::SUCCESS, | |
816 last_update_result()->item_statuses.begin()->second); | |
817 EXPECT_EQ(1UL, last_update_result()->updated_items.size()); | |
818 EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin())); | |
819 | |
820 ClearResults(); | |
821 store->GetOfflinePages( | |
822 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
823 base::Unretained(this))); | |
824 PumpLoop(); | |
825 | |
826 EXPECT_EQ(LOAD, last_called_callback_); | |
827 EXPECT_EQ(STATUS_TRUE, last_status_); | |
828 ASSERT_EQ(1U, offline_pages_.size()); | |
829 EXPECT_EQ(offline_page, offline_pages_[0]); | |
830 } | |
831 | |
832 TEST_F(OfflinePageMetadataStoreTest, ClearAllOfflinePages) { | |
833 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
834 | |
835 // Add 2 offline pages. | |
836 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
837 base::FilePath(kFilePath), kFileSize); | |
838 store->AddOfflinePage(offline_page, | |
839 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
840 base::Unretained(this))); | |
841 PumpLoop(); | |
842 EXPECT_EQ(ADD, last_called_callback_); | |
843 EXPECT_EQ(STATUS_TRUE, last_status_); | |
844 | |
845 ClearResults(); | |
846 | |
847 OfflinePageItem offline_page2(GURL("http://test.com"), 5678LL, kTestClientId2, | |
848 base::FilePath(kFilePath), kFileSize); | |
849 store->AddOfflinePage(offline_page2, | |
850 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
851 base::Unretained(this))); | |
852 PumpLoop(); | |
853 EXPECT_EQ(ADD, last_called_callback_); | |
854 EXPECT_EQ(STATUS_TRUE, last_status_); | |
855 | |
856 ClearResults(); | |
857 | |
858 // Load the store. | |
859 store->GetOfflinePages( | |
860 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
861 base::Unretained(this))); | |
862 PumpLoop(); | |
863 | |
864 EXPECT_EQ(LOAD, last_called_callback_); | |
865 EXPECT_EQ(STATUS_TRUE, last_status_); | |
866 EXPECT_EQ(2U, offline_pages_.size()); | |
867 | |
868 // Clear all records from the store. | |
869 store->Reset(base::Bind(&OfflinePageMetadataStoreTest::ResetCallback, | |
870 base::Unretained(this))); | |
871 PumpLoop(); | |
872 EXPECT_EQ(RESET, last_called_callback_); | |
873 EXPECT_EQ(STATUS_TRUE, last_status_); | |
874 | |
875 // Load the store. | |
876 store->GetOfflinePages( | |
877 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
878 base::Unretained(this))); | |
879 PumpLoop(); | |
880 | |
881 EXPECT_EQ(LOAD, last_called_callback_); | |
882 EXPECT_EQ(STATUS_TRUE, last_status_); | |
883 ASSERT_EQ(0U, offline_pages_.size()); | |
884 } | |
885 | |
886 } // namespace | |
887 } // namespace offline_pages | |
OLD | NEW |