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 ASSERT_FALSE( | |
225 connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "original_url")); | |
226 } | |
227 | |
228 class OfflinePageMetadataStoreFactory { | |
229 public: | |
230 OfflinePageMetadataStore* BuildStore(const base::FilePath& file_path) { | |
231 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
232 base::ThreadTaskRunnerHandle::Get(), file_path); | |
233 return store; | |
234 } | |
235 | |
236 OfflinePageMetadataStore* BuildStoreM52(const base::FilePath& file_path) { | |
237 BuildTestStoreWithSchemaFromM52(file_path); | |
238 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
239 base::ThreadTaskRunnerHandle::Get(), file_path); | |
240 return store; | |
241 } | |
242 | |
243 OfflinePageMetadataStore* BuildStoreM53(const base::FilePath& file_path) { | |
244 BuildTestStoreWithSchemaFromM53(file_path); | |
245 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
246 base::ThreadTaskRunnerHandle::Get(), file_path); | |
247 return store; | |
248 } | |
249 | |
250 OfflinePageMetadataStore* BuildStoreM54(const base::FilePath& file_path) { | |
251 BuildTestStoreWithSchemaFromM54(file_path); | |
252 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
253 base::ThreadTaskRunnerHandle::Get(), file_path); | |
254 return store; | |
255 } | |
256 | |
257 OfflinePageMetadataStore* BuildStoreM55(const base::FilePath& file_path) { | |
258 BuildTestStoreWithSchemaFromM55(file_path); | |
259 OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL( | |
260 base::ThreadTaskRunnerHandle::Get(), file_path); | |
261 return store; | |
262 } | |
263 }; | |
264 | |
265 enum CalledCallback { NONE, LOAD, ADD, UPDATE, REMOVE, RESET }; | |
266 enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE }; | |
267 | |
268 class OfflinePageMetadataStoreTest : public testing::Test { | |
269 public: | |
270 OfflinePageMetadataStoreTest(); | |
271 ~OfflinePageMetadataStoreTest() override; | |
272 | |
273 void TearDown() override { | |
274 // Wait for all the pieces of the store to delete itself properly. | |
275 PumpLoop(); | |
276 } | |
277 | |
278 std::unique_ptr<OfflinePageMetadataStore> BuildStore(); | |
279 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM52(); | |
280 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM53(); | |
281 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM54(); | |
282 std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM55(); | |
283 | |
284 void PumpLoop(); | |
285 | |
286 void InitializeCallback(bool success); | |
287 void GetOfflinePagesCallback( | |
288 const std::vector<OfflinePageItem>& offline_pages); | |
289 void AddCallback(ItemActionStatus status); | |
290 void UpdateCallback(CalledCallback called_callback, | |
291 std::unique_ptr<OfflinePagesUpdateResult> result); | |
292 void ResetCallback(bool success); | |
293 | |
294 void ClearResults(); | |
295 | |
296 OfflinePageItem CheckThatStoreHasOneItem(); | |
297 void CheckThatOfflinePageCanBeSaved( | |
298 std::unique_ptr<OfflinePageMetadataStore> store); | |
299 | |
300 OfflinePagesUpdateResult* last_update_result() { | |
301 return last_update_result_.get(); | |
302 } | |
303 | |
304 protected: | |
305 CalledCallback last_called_callback_; | |
306 Status last_status_; | |
307 std::unique_ptr<OfflinePagesUpdateResult> last_update_result_; | |
308 std::vector<OfflinePageItem> offline_pages_; | |
309 OfflinePageMetadataStoreFactory factory_; | |
310 | |
311 base::ScopedTempDir temp_directory_; | |
312 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | |
313 base::ThreadTaskRunnerHandle task_runner_handle_; | |
314 }; | |
315 | |
316 OfflinePageMetadataStoreTest::OfflinePageMetadataStoreTest() | |
317 : last_called_callback_(NONE), | |
318 last_status_(STATUS_NONE), | |
319 task_runner_(new base::TestSimpleTaskRunner), | |
320 task_runner_handle_(task_runner_) { | |
321 EXPECT_TRUE(temp_directory_.CreateUniqueTempDir()); | |
322 } | |
323 | |
324 OfflinePageMetadataStoreTest::~OfflinePageMetadataStoreTest() {} | |
325 | |
326 void OfflinePageMetadataStoreTest::PumpLoop() { | |
327 task_runner_->RunUntilIdle(); | |
328 } | |
329 | |
330 void OfflinePageMetadataStoreTest::InitializeCallback(bool success) { | |
331 last_status_ = success ? STATUS_TRUE : STATUS_FALSE; | |
332 } | |
333 | |
334 void OfflinePageMetadataStoreTest::GetOfflinePagesCallback( | |
335 const std::vector<OfflinePageItem>& offline_pages) { | |
336 last_called_callback_ = LOAD; | |
337 offline_pages_.swap(const_cast<std::vector<OfflinePageItem>&>(offline_pages)); | |
338 } | |
339 | |
340 void OfflinePageMetadataStoreTest::AddCallback(ItemActionStatus status) { | |
341 last_called_callback_ = ADD; | |
342 // TODO(fgorski): Add specific add status. | |
343 // last_item_status_ = status; | |
344 last_status_ = | |
345 status == ItemActionStatus::SUCCESS ? STATUS_TRUE : STATUS_FALSE; | |
346 } | |
347 | |
348 void OfflinePageMetadataStoreTest::UpdateCallback( | |
349 CalledCallback called_callback, | |
350 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
351 last_called_callback_ = called_callback; | |
352 last_status_ = result->updated_items.size() > 0 ? STATUS_TRUE : STATUS_FALSE; | |
353 last_update_result_ = std::move(result); | |
354 } | |
355 | |
356 void OfflinePageMetadataStoreTest::ResetCallback(bool success) { | |
357 last_called_callback_ = RESET; | |
358 last_status_ = success ? STATUS_TRUE : STATUS_FALSE; | |
359 } | |
360 | |
361 void OfflinePageMetadataStoreTest::ClearResults() { | |
362 last_called_callback_ = NONE; | |
363 last_status_ = STATUS_NONE; | |
364 offline_pages_.clear(); | |
365 last_update_result_.reset(nullptr); | |
366 } | |
367 | |
368 OfflinePageItem OfflinePageMetadataStoreTest::CheckThatStoreHasOneItem() { | |
369 EXPECT_EQ(LOAD, last_called_callback_); | |
370 EXPECT_EQ(STATUS_TRUE, last_status_); | |
371 EXPECT_EQ(1U, offline_pages_.size()); | |
372 | |
373 return offline_pages_[0]; | |
374 } | |
375 | |
376 void OfflinePageMetadataStoreTest::CheckThatOfflinePageCanBeSaved( | |
377 std::unique_ptr<OfflinePageMetadataStore> store) { | |
378 size_t store_size = offline_pages_.size(); | |
379 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
380 base::FilePath(kFilePath), kFileSize); | |
381 offline_page.title = base::UTF8ToUTF16("a title"); | |
382 base::Time expiration_time = base::Time::Now(); | |
383 offline_page.expiration_time = expiration_time; | |
384 offline_page.original_url = GURL(kOriginalTestURL); | |
385 | |
386 store->AddOfflinePage(offline_page, | |
387 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
388 base::Unretained(this))); | |
389 PumpLoop(); | |
390 EXPECT_EQ(ADD, last_called_callback_); | |
391 EXPECT_EQ(STATUS_TRUE, last_status_); | |
392 ClearResults(); | |
393 | |
394 // Close the store first to ensure file lock is removed. | |
395 store.reset(); | |
396 store = BuildStore(); | |
397 PumpLoop(); | |
398 | |
399 EXPECT_EQ(LOAD, last_called_callback_); | |
400 EXPECT_EQ(STATUS_TRUE, last_status_); | |
401 ASSERT_EQ(store_size + 1, offline_pages_.size()); | |
402 if (store_size > 0 && | |
403 offline_pages_[0].offline_id != offline_page.offline_id) { | |
404 std::swap(offline_pages_[0], offline_pages_[1]); | |
405 } | |
406 EXPECT_EQ(offline_page, offline_pages_[0]); | |
407 } | |
408 | |
409 std::unique_ptr<OfflinePageMetadataStore> | |
410 OfflinePageMetadataStoreTest::BuildStore() { | |
411 std::unique_ptr<OfflinePageMetadataStore> store( | |
412 factory_.BuildStore(temp_directory_.GetPath())); | |
413 PumpLoop(); | |
414 store->Initialize( | |
415 base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback, | |
416 base::Unretained(this))); | |
417 PumpLoop(); | |
418 store->GetOfflinePages( | |
419 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
420 base::Unretained(this))); | |
421 PumpLoop(); | |
422 return store; | |
423 } | |
424 | |
425 std::unique_ptr<OfflinePageMetadataStore> | |
426 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM52() { | |
427 std::unique_ptr<OfflinePageMetadataStore> store( | |
428 factory_.BuildStoreM52(temp_directory_.GetPath())); | |
429 PumpLoop(); | |
430 store->Initialize( | |
431 base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback, | |
432 base::Unretained(this))); | |
433 PumpLoop(); | |
434 store->GetOfflinePages( | |
435 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
436 base::Unretained(this))); | |
437 PumpLoop(); | |
438 return store; | |
439 } | |
440 | |
441 std::unique_ptr<OfflinePageMetadataStore> | |
442 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM53() { | |
443 std::unique_ptr<OfflinePageMetadataStore> store( | |
444 factory_.BuildStoreM53(temp_directory_.GetPath())); | |
445 PumpLoop(); | |
446 store->Initialize( | |
447 base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback, | |
448 base::Unretained(this))); | |
449 PumpLoop(); | |
450 store->GetOfflinePages( | |
451 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
452 base::Unretained(this))); | |
453 PumpLoop(); | |
454 return store; | |
455 } | |
456 | |
457 std::unique_ptr<OfflinePageMetadataStore> | |
458 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM54() { | |
459 std::unique_ptr<OfflinePageMetadataStore> store( | |
460 factory_.BuildStoreM53(temp_directory_.GetPath())); | |
461 PumpLoop(); | |
462 store->Initialize( | |
463 base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback, | |
464 base::Unretained(this))); | |
465 PumpLoop(); | |
466 store->GetOfflinePages( | |
467 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
468 base::Unretained(this))); | |
469 PumpLoop(); | |
470 return store; | |
471 } | |
472 | |
473 std::unique_ptr<OfflinePageMetadataStore> | |
474 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM55() { | |
475 std::unique_ptr<OfflinePageMetadataStore> store( | |
476 factory_.BuildStoreM55(temp_directory_.GetPath())); | |
477 PumpLoop(); | |
478 store->Initialize( | |
479 base::Bind(&OfflinePageMetadataStoreTest::InitializeCallback, | |
480 base::Unretained(this))); | |
481 PumpLoop(); | |
482 store->GetOfflinePages( | |
483 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
484 base::Unretained(this))); | |
485 PumpLoop(); | |
486 return store; | |
487 } | |
488 | |
489 // Loads empty store and makes sure that there are no offline pages stored in | |
490 // it. | |
491 TEST_F(OfflinePageMetadataStoreTest, LoadEmptyStore) { | |
492 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
493 EXPECT_EQ(LOAD, last_called_callback_); | |
494 EXPECT_EQ(STATUS_TRUE, last_status_); | |
495 EXPECT_EQ(0U, offline_pages_.size()); | |
496 } | |
497 | |
498 TEST_F(OfflinePageMetadataStoreTest, GetOfflinePagesFromInvalidStore) { | |
499 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
500 OfflinePageMetadataStoreSQL* sql_store = | |
501 static_cast<OfflinePageMetadataStoreSQL*>(store.get()); | |
502 | |
503 sql_store->SetStateForTesting(StoreState::NOT_LOADED, false); | |
504 store->GetOfflinePages( | |
505 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
506 base::Unretained(this))); | |
507 PumpLoop(); | |
508 EXPECT_EQ(LOAD, last_called_callback_); | |
509 EXPECT_EQ(0UL, offline_pages_.size()); | |
510 EXPECT_EQ(StoreState::NOT_LOADED, store->state()); | |
511 | |
512 ClearResults(); | |
513 sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false); | |
514 store->GetOfflinePages( | |
515 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
516 base::Unretained(this))); | |
517 PumpLoop(); | |
518 EXPECT_EQ(LOAD, last_called_callback_); | |
519 EXPECT_EQ(0UL, offline_pages_.size()); | |
520 EXPECT_EQ(StoreState::FAILED_LOADING, store->state()); | |
521 | |
522 ClearResults(); | |
523 sql_store->SetStateForTesting(StoreState::FAILED_RESET, false); | |
524 store->GetOfflinePages( | |
525 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
526 base::Unretained(this))); | |
527 PumpLoop(); | |
528 EXPECT_EQ(LOAD, last_called_callback_); | |
529 EXPECT_EQ(0UL, offline_pages_.size()); | |
530 EXPECT_EQ(StoreState::FAILED_RESET, store->state()); | |
531 | |
532 ClearResults(); | |
533 sql_store->SetStateForTesting(StoreState::LOADED, true); | |
534 store->GetOfflinePages( | |
535 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
536 base::Unretained(this))); | |
537 PumpLoop(); | |
538 EXPECT_EQ(LOAD, last_called_callback_); | |
539 EXPECT_EQ(0UL, offline_pages_.size()); | |
540 | |
541 ClearResults(); | |
542 sql_store->SetStateForTesting(StoreState::NOT_LOADED, true); | |
543 store->GetOfflinePages( | |
544 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
545 base::Unretained(this))); | |
546 PumpLoop(); | |
547 EXPECT_EQ(LOAD, last_called_callback_); | |
548 EXPECT_EQ(0UL, offline_pages_.size()); | |
549 | |
550 ClearResults(); | |
551 sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false); | |
552 store->GetOfflinePages( | |
553 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
554 base::Unretained(this))); | |
555 PumpLoop(); | |
556 EXPECT_EQ(LOAD, last_called_callback_); | |
557 EXPECT_EQ(0UL, offline_pages_.size()); | |
558 | |
559 ClearResults(); | |
560 sql_store->SetStateForTesting(StoreState::FAILED_RESET, false); | |
561 store->GetOfflinePages( | |
562 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
563 base::Unretained(this))); | |
564 PumpLoop(); | |
565 EXPECT_EQ(LOAD, last_called_callback_); | |
566 EXPECT_EQ(0UL, offline_pages_.size()); | |
567 } | |
568 | |
569 // Loads a store which has an outdated schema. | |
570 // This test case would crash if it's not handling correctly when we're loading | |
571 // old version stores. | |
572 // TODO(romax): Move this to sql_unittest. | |
573 TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) { | |
574 std::unique_ptr<OfflinePageMetadataStore> store( | |
575 BuildStoreWithSchemaFromM52()); | |
576 | |
577 CheckThatStoreHasOneItem(); | |
578 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
579 } | |
580 | |
581 // Loads a store which has an outdated schema. | |
582 // This test case would crash if it's not handling correctly when we're loading | |
583 // old version stores. | |
584 // TODO(romax): Move this to sql_unittest. | |
585 TEST_F(OfflinePageMetadataStoreTest, LoadVersion53Store) { | |
586 std::unique_ptr<OfflinePageMetadataStore> store( | |
587 BuildStoreWithSchemaFromM53()); | |
588 | |
589 OfflinePageItem item = CheckThatStoreHasOneItem(); | |
590 // We should have a valid expiration time after upgrade. | |
591 EXPECT_NE(base::Time::FromInternalValue(0), | |
592 offline_pages_[0].expiration_time); | |
593 | |
594 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
595 } | |
596 | |
597 // Loads a string with schema from M54. | |
598 // Because for now we only reduce the number of fields it just makes sure there | |
599 // are no crashes in the process. | |
600 // TODO(romax): Move this to sql_unittest. | |
601 TEST_F(OfflinePageMetadataStoreTest, LoadVersion54Store) { | |
602 std::unique_ptr<OfflinePageMetadataStore> store( | |
603 BuildStoreWithSchemaFromM54()); | |
604 | |
605 OfflinePageItem item = CheckThatStoreHasOneItem(); | |
606 | |
607 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
608 } | |
609 | |
610 // Loads a string with schema from M55. | |
611 // Because for now we only reduce the number of fields it just makes sure there | |
612 // are no crashes in the process. | |
613 // TODO(romax): Move this to sql_unittest. | |
614 TEST_F(OfflinePageMetadataStoreTest, LoadVersion55Store) { | |
615 std::unique_ptr<OfflinePageMetadataStore> store( | |
616 BuildStoreWithSchemaFromM55()); | |
617 | |
618 OfflinePageItem item = CheckThatStoreHasOneItem(); | |
619 | |
620 CheckThatOfflinePageCanBeSaved(std::move(store)); | |
621 } | |
622 | |
623 // Adds metadata of an offline page into a store and then opens the store | |
624 // again to make sure that stored metadata survives store restarts. | |
625 TEST_F(OfflinePageMetadataStoreTest, AddOfflinePage) { | |
626 CheckThatOfflinePageCanBeSaved(BuildStore()); | |
627 } | |
628 | |
629 TEST_F(OfflinePageMetadataStoreTest, AddSameOfflinePageTwice) { | |
630 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
631 | |
632 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
633 base::FilePath(kFilePath), kFileSize); | |
634 offline_page.title = base::UTF8ToUTF16("a title"); | |
635 base::Time expiration_time = base::Time::Now(); | |
636 offline_page.expiration_time = expiration_time; | |
637 | |
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 ClearResults(); | |
645 | |
646 store->AddOfflinePage(offline_page, | |
647 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
648 base::Unretained(this))); | |
649 PumpLoop(); | |
650 EXPECT_EQ(ADD, last_called_callback_); | |
651 EXPECT_EQ(STATUS_FALSE, last_status_); | |
652 } | |
653 | |
654 // Tests removing offline page metadata from the store, for which it first adds | |
655 // metadata of an offline page. | |
656 TEST_F(OfflinePageMetadataStoreTest, RemoveOfflinePage) { | |
657 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
658 | |
659 // Add an offline page. | |
660 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
661 base::FilePath(kFilePath), kFileSize); | |
662 store->AddOfflinePage(offline_page, | |
663 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
664 base::Unretained(this))); | |
665 PumpLoop(); | |
666 EXPECT_EQ(ADD, last_called_callback_); | |
667 EXPECT_EQ(STATUS_TRUE, last_status_); | |
668 | |
669 ClearResults(); | |
670 | |
671 // Get all pages from the store. | |
672 store->GetOfflinePages( | |
673 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
674 base::Unretained(this))); | |
675 PumpLoop(); | |
676 EXPECT_EQ(LOAD, last_called_callback_); | |
677 EXPECT_EQ(1U, offline_pages_.size()); | |
678 | |
679 // Remove the offline page. | |
680 std::vector<int64_t> ids_to_remove; | |
681 ids_to_remove.push_back(offline_page.offline_id); | |
682 store->RemoveOfflinePages( | |
683 ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback, | |
684 base::Unretained(this), REMOVE)); | |
685 PumpLoop(); | |
686 EXPECT_EQ(REMOVE, last_called_callback_); | |
687 EXPECT_EQ(STATUS_TRUE, last_status_); | |
688 ASSERT_TRUE(last_update_result() != nullptr); | |
689 EXPECT_EQ(1UL, last_update_result()->item_statuses.size()); | |
690 EXPECT_EQ(ItemActionStatus::SUCCESS, | |
691 last_update_result()->item_statuses.begin()->second); | |
692 EXPECT_EQ(1UL, last_update_result()->updated_items.size()); | |
693 EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin())); | |
694 | |
695 ClearResults(); | |
696 | |
697 // Get all pages from the store. | |
698 store->GetOfflinePages( | |
699 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
700 base::Unretained(this))); | |
701 PumpLoop(); | |
702 EXPECT_EQ(LOAD, last_called_callback_); | |
703 EXPECT_EQ(0U, offline_pages_.size()); | |
704 | |
705 ClearResults(); | |
706 | |
707 // Close and reload the store. | |
708 store.reset(); | |
709 store = BuildStore(); | |
710 EXPECT_EQ(LOAD, last_called_callback_); | |
711 EXPECT_EQ(STATUS_TRUE, last_status_); | |
712 EXPECT_EQ(0U, offline_pages_.size()); | |
713 } | |
714 | |
715 // Adds metadata of multiple offline pages into a store and removes some. | |
716 TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) { | |
717 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
718 | |
719 // Add an offline page. | |
720 OfflinePageItem offline_page_1(GURL(kTestURL), 12345LL, kTestClientId1, | |
721 base::FilePath(kFilePath), kFileSize); | |
722 store->AddOfflinePage(offline_page_1, | |
723 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
724 base::Unretained(this))); | |
725 PumpLoop(); | |
726 EXPECT_EQ(ADD, last_called_callback_); | |
727 EXPECT_EQ(STATUS_TRUE, last_status_); | |
728 | |
729 ClearResults(); | |
730 | |
731 // Add anther offline page. | |
732 base::FilePath file_path_2 = | |
733 base::FilePath(FILE_PATH_LITERAL("//other.page.com.mhtml")); | |
734 OfflinePageItem offline_page_2(GURL("https://other.page.com"), 5678LL, | |
735 kTestClientId2, file_path_2, 12345, | |
736 base::Time::Now()); | |
737 offline_page_2.expiration_time = base::Time::Now(); | |
738 offline_page_2.original_url = GURL("https://example.com/bar"); | |
739 store->AddOfflinePage(offline_page_2, | |
740 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
741 base::Unretained(this))); | |
742 PumpLoop(); | |
743 EXPECT_EQ(ADD, last_called_callback_); | |
744 EXPECT_EQ(STATUS_TRUE, last_status_); | |
745 | |
746 ClearResults(); | |
747 | |
748 // Get all pages from the store. | |
749 store->GetOfflinePages( | |
750 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
751 base::Unretained(this))); | |
752 PumpLoop(); | |
753 | |
754 EXPECT_EQ(LOAD, last_called_callback_); | |
755 EXPECT_EQ(2U, offline_pages_.size()); | |
756 | |
757 // Remove the offline page. | |
758 std::vector<int64_t> ids_to_remove; | |
759 ids_to_remove.push_back(offline_page_1.offline_id); | |
760 store->RemoveOfflinePages( | |
761 ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback, | |
762 base::Unretained(this), REMOVE)); | |
763 PumpLoop(); | |
764 EXPECT_EQ(REMOVE, last_called_callback_); | |
765 EXPECT_EQ(STATUS_TRUE, last_status_); | |
766 ASSERT_TRUE(last_update_result() != nullptr); | |
767 EXPECT_EQ(1UL, last_update_result()->item_statuses.size()); | |
768 EXPECT_EQ(ItemActionStatus::SUCCESS, | |
769 last_update_result()->item_statuses.begin()->second); | |
770 EXPECT_EQ(1UL, last_update_result()->updated_items.size()); | |
771 EXPECT_EQ(offline_page_1, *(last_update_result()->updated_items.begin())); | |
772 | |
773 ClearResults(); | |
774 | |
775 // Close and reload the store. | |
776 store.reset(); | |
777 store = BuildStore(); | |
778 store->GetOfflinePages( | |
779 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
780 base::Unretained(this))); | |
781 PumpLoop(); | |
782 | |
783 EXPECT_EQ(LOAD, last_called_callback_); | |
784 EXPECT_EQ(STATUS_TRUE, last_status_); | |
785 ASSERT_EQ(1U, offline_pages_.size()); | |
786 EXPECT_EQ(offline_page_2.url, offline_pages_[0].url); | |
787 EXPECT_EQ(offline_page_2.offline_id, offline_pages_[0].offline_id); | |
788 EXPECT_EQ(offline_page_2.file_path, offline_pages_[0].file_path); | |
789 EXPECT_EQ(offline_page_2.file_size, offline_pages_[0].file_size); | |
790 EXPECT_EQ(offline_page_2.creation_time, offline_pages_[0].creation_time); | |
791 EXPECT_EQ(offline_page_2.last_access_time, | |
792 offline_pages_[0].last_access_time); | |
793 EXPECT_EQ(offline_page_2.expiration_time, offline_pages_[0].expiration_time); | |
794 EXPECT_EQ(offline_page_2.access_count, offline_pages_[0].access_count); | |
795 EXPECT_EQ(offline_page_2.client_id, offline_pages_[0].client_id); | |
796 } | |
797 | |
798 // Tests updating offline page metadata from the store. | |
799 TEST_F(OfflinePageMetadataStoreTest, UpdateOfflinePage) { | |
800 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
801 | |
802 // First, adds a fresh page. | |
803 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
804 base::FilePath(kFilePath), kFileSize); | |
805 store->AddOfflinePage(offline_page, | |
806 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
807 base::Unretained(this))); | |
808 PumpLoop(); | |
809 EXPECT_EQ(ADD, last_called_callback_); | |
810 EXPECT_EQ(STATUS_TRUE, last_status_); | |
811 | |
812 ClearResults(); | |
813 store->GetOfflinePages( | |
814 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
815 base::Unretained(this))); | |
816 PumpLoop(); | |
817 | |
818 EXPECT_EQ(LOAD, last_called_callback_); | |
819 ASSERT_EQ(1U, offline_pages_.size()); | |
820 EXPECT_EQ(offline_page, offline_pages_[0]); | |
821 | |
822 // Then update some data. | |
823 offline_page.file_size = kFileSize + 1; | |
824 offline_page.access_count++; | |
825 offline_page.expiration_time = base::Time::Now(); | |
826 offline_page.original_url = GURL("https://example.com/bar"); | |
827 std::vector<OfflinePageItem> items_to_update; | |
828 items_to_update.push_back(offline_page); | |
829 store->UpdateOfflinePages( | |
830 items_to_update, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback, | |
831 base::Unretained(this), UPDATE)); | |
832 PumpLoop(); | |
833 EXPECT_EQ(UPDATE, last_called_callback_); | |
834 EXPECT_EQ(STATUS_TRUE, last_status_); | |
835 ASSERT_TRUE(last_update_result() != nullptr); | |
836 EXPECT_EQ(1UL, last_update_result()->item_statuses.size()); | |
837 EXPECT_EQ(ItemActionStatus::SUCCESS, | |
838 last_update_result()->item_statuses.begin()->second); | |
839 EXPECT_EQ(1UL, last_update_result()->updated_items.size()); | |
840 EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin())); | |
841 | |
842 ClearResults(); | |
843 store->GetOfflinePages( | |
844 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
845 base::Unretained(this))); | |
846 PumpLoop(); | |
847 | |
848 EXPECT_EQ(LOAD, last_called_callback_); | |
849 ASSERT_EQ(1U, offline_pages_.size()); | |
850 EXPECT_EQ(offline_page, offline_pages_[0]); | |
851 } | |
852 | |
853 TEST_F(OfflinePageMetadataStoreTest, ClearAllOfflinePages) { | |
854 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
855 | |
856 // Add 2 offline pages. | |
857 OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1, | |
858 base::FilePath(kFilePath), kFileSize); | |
859 store->AddOfflinePage(offline_page, | |
860 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
861 base::Unretained(this))); | |
862 PumpLoop(); | |
863 EXPECT_EQ(ADD, last_called_callback_); | |
864 EXPECT_EQ(STATUS_TRUE, last_status_); | |
865 | |
866 ClearResults(); | |
867 | |
868 OfflinePageItem offline_page2(GURL("http://test.com"), 5678LL, kTestClientId2, | |
869 base::FilePath(kFilePath), kFileSize); | |
870 store->AddOfflinePage(offline_page2, | |
871 base::Bind(&OfflinePageMetadataStoreTest::AddCallback, | |
872 base::Unretained(this))); | |
873 PumpLoop(); | |
874 EXPECT_EQ(ADD, last_called_callback_); | |
875 EXPECT_EQ(STATUS_TRUE, last_status_); | |
876 | |
877 ClearResults(); | |
878 | |
879 // Get all pages from the store. | |
880 store->GetOfflinePages( | |
881 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
882 base::Unretained(this))); | |
883 PumpLoop(); | |
884 | |
885 EXPECT_EQ(LOAD, last_called_callback_); | |
886 EXPECT_EQ(2U, offline_pages_.size()); | |
887 | |
888 // Clear all records from the store. | |
889 store->Reset(base::Bind(&OfflinePageMetadataStoreTest::ResetCallback, | |
890 base::Unretained(this))); | |
891 PumpLoop(); | |
892 EXPECT_EQ(RESET, last_called_callback_); | |
893 EXPECT_EQ(STATUS_TRUE, last_status_); | |
894 | |
895 ClearResults(); | |
896 | |
897 // Get all pages from the store. | |
898 store->GetOfflinePages( | |
899 base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback, | |
900 base::Unretained(this))); | |
901 PumpLoop(); | |
902 | |
903 EXPECT_EQ(LOAD, last_called_callback_); | |
904 ASSERT_EQ(0U, offline_pages_.size()); | |
905 } | |
906 | |
907 TEST_F(OfflinePageMetadataStoreTest, ResetStore) { | |
908 std::unique_ptr<OfflinePageMetadataStore> store(BuildStore()); | |
909 | |
910 store->Reset(base::Bind(&OfflinePageMetadataStoreTest::ResetCallback, | |
911 base::Unretained(this))); | |
912 PumpLoop(); | |
913 EXPECT_EQ(STATUS_TRUE, last_status_); | |
914 } | |
915 | |
916 } // namespace | |
917 } // namespace offline_pages | |
OLD | NEW |