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.
5 #include "components/offline_pages/offline_page_model.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "components/offline_pages/offline_page_item.h"
18 #include "components/offline_pages/offline_page_metadata_store.h"
19 #include "testing/gtest/include/gtest/gtest.h"
22 using SavePageResult
= offline_pages::OfflinePageModel::SavePageResult
;
23 using LoadResult
= offline_pages::OfflinePageModel::LoadResult
;
24 using DeletePageResult
= offline_pages::OfflinePageModel::DeletePageResult
;
26 namespace offline_pages
{
29 const GURL
kTestUrl("http://example.com");
30 const base::string16 kTestPageTitle
= base::ASCIIToUTF16("Test Page Title");
31 const GURL
kTestUrl2("http://other.page.com");
32 const base::string16 kTestPageTitle2
= base::ASCIIToUTF16("Other page title");
33 const int64 kTestFileSize
= 876543LL;
35 class OfflinePageTestStore
: public OfflinePageMetadataStore
{
37 enum class TestScenario
{
44 explicit OfflinePageTestStore(
45 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
);
46 ~OfflinePageTestStore() override
;
48 // OfflinePageMetadataStore overrides:
49 void Load(const LoadCallback
& callback
) override
;
50 void AddOfflinePage(const OfflinePageItem
& offline_page
,
51 const UpdateCallback
& callback
) override
;
52 void RemoveOfflinePage(const GURL
& page_url
,
53 const UpdateCallback
& callback
) override
;
54 const OfflinePageItem
& last_saved_page() const { return last_saved_page_
; }
56 void set_test_scenario(TestScenario scenario
) { scenario_
= scenario
; };
58 const std::vector
<OfflinePageItem
>& offline_pages() const {
59 return offline_pages_
;
63 OfflinePageItem last_saved_page_
;
64 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
65 TestScenario scenario_
;
67 std::vector
<OfflinePageItem
> offline_pages_
;
69 DISALLOW_COPY_AND_ASSIGN(OfflinePageTestStore
);
72 OfflinePageTestStore::OfflinePageTestStore(
73 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
)
74 : task_runner_(task_runner
),
75 scenario_(TestScenario::SUCCESSFUL
) {
78 OfflinePageTestStore::~OfflinePageTestStore() {
81 void OfflinePageTestStore::Load(const LoadCallback
& callback
) {
82 if (scenario_
!= TestScenario::LOAD_FAILED
) {
83 task_runner_
->PostTask(
84 FROM_HERE
, base::Bind(callback
, true, offline_pages_
));
86 task_runner_
->PostTask(
87 FROM_HERE
, base::Bind(callback
, false, std::vector
<OfflinePageItem
>()));
91 void OfflinePageTestStore::AddOfflinePage(const OfflinePageItem
& offline_page
,
92 const UpdateCallback
& callback
) {
93 last_saved_page_
= offline_page
;
94 bool result
= scenario_
!= TestScenario::WRITE_FAILED
;
96 offline_pages_
.push_back(offline_page
);
98 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, result
));
101 void OfflinePageTestStore::RemoveOfflinePage(const GURL
& page_url
,
102 const UpdateCallback
& callback
) {
104 if (scenario_
!= TestScenario::REMOVE_FAILED
) {
105 for (auto iter
= offline_pages_
.begin();
106 iter
!= offline_pages_
.end(); ++iter
) {
107 if (iter
->url
== page_url
) {
108 offline_pages_
.erase(iter
);
115 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, result
));
120 class OfflinePageModelTest
;
122 class OfflinePageTestArchiver
: public OfflinePageArchiver
{
124 OfflinePageTestArchiver(
125 OfflinePageModelTest
* test
,
127 const base::string16
& title
,
128 const base::FilePath
& archiver_dir
,
129 ArchiverResult result
,
130 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
);
131 ~OfflinePageTestArchiver() override
;
133 // OfflinePageArchiver implementation:
134 void CreateArchive(const CreateArchiveCallback
& callback
) override
;
136 void CompleteCreateArchive();
138 void set_delayed(bool delayed
) { delayed_
= delayed
; }
140 bool create_archive_called() const { return create_archive_called_
; }
143 OfflinePageModelTest
* test_
; // Outlive OfflinePageTestArchiver.
145 base::string16 title_
;
146 base::FilePath archiver_dir_
;
147 ArchiverResult result_
;
148 bool create_archive_called_
;
150 CreateArchiveCallback callback_
;
151 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
152 DISALLOW_COPY_AND_ASSIGN(OfflinePageTestArchiver
);
155 class OfflinePageModelTest
156 : public testing::Test
,
157 public base::SupportsWeakPtr
<OfflinePageModelTest
> {
159 OfflinePageModelTest();
160 ~OfflinePageModelTest() override
;
162 void SetUp() override
;
164 // OfflinePageModel callbacks.
165 void OnSavePageDone(SavePageResult result
);
166 void OnLoadAllPagesDone(LoadResult result
,
167 const std::vector
<OfflinePageItem
>& offline_pages
);
168 void OnDeletePageDone(DeletePageResult result
);
170 scoped_ptr
<OfflinePageTestArchiver
> BuildArchiver(
172 const base::string16
& title
,
173 OfflinePageArchiver::ArchiverResult result
);
174 scoped_ptr
<OfflinePageMetadataStore
> BuildStore();
175 scoped_ptr
<OfflinePageModel
> BuildModel();
181 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner() {
182 return message_loop_
.task_runner();
185 OfflinePageModel
* model() { return model_
.get(); }
187 OfflinePageTestStore
* GetStore();
189 SavePageResult
last_save_result() const {
190 return last_save_result_
;
193 LoadResult
last_load_result() const {
194 return last_load_result_
;
197 DeletePageResult
last_delete_result() const {
198 return last_delete_result_
;
201 const std::vector
<OfflinePageItem
>& last_loaded_pages() const {
202 return last_loaded_pages_
;
205 const base::FilePath
& last_archiver_path() { return last_archiver_path_
; }
206 void set_last_archiver_path(const base::FilePath
& last_archiver_path
) {
207 last_archiver_path_
= last_archiver_path
;
211 base::MessageLoop message_loop_
;
212 scoped_ptr
<base::RunLoop
> run_loop_
;
213 base::ScopedTempDir temp_dir_
;
215 scoped_ptr
<OfflinePageModel
> model_
;
216 SavePageResult last_save_result_
;
217 LoadResult last_load_result_
;
218 DeletePageResult last_delete_result_
;
219 std::vector
<OfflinePageItem
> last_loaded_pages_
;
220 base::FilePath last_archiver_path_
;
223 OfflinePageTestArchiver::OfflinePageTestArchiver(
224 OfflinePageModelTest
* test
,
226 const base::string16
& title
,
227 const base::FilePath
& archiver_dir
,
228 ArchiverResult result
,
229 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
)
233 archiver_dir_(archiver_dir
),
235 create_archive_called_(false),
237 task_runner_(task_runner
) {
240 OfflinePageTestArchiver::~OfflinePageTestArchiver() {
241 EXPECT_TRUE(create_archive_called_
);
244 void OfflinePageTestArchiver::CreateArchive(
245 const CreateArchiveCallback
& callback
) {
246 create_archive_called_
= true;
247 callback_
= callback
;
249 CompleteCreateArchive();
252 void OfflinePageTestArchiver::CompleteCreateArchive() {
253 DCHECK(!callback_
.is_null());
254 base::FilePath archiver_path
;
255 ASSERT_TRUE(base::CreateTemporaryFileInDir(archiver_dir_
, &archiver_path
));
256 test_
->set_last_archiver_path(archiver_path
);
257 task_runner_
->PostTask(
258 FROM_HERE
, base::Bind(callback_
, this, result_
, url_
, title_
,
263 OfflinePageModelTest::OfflinePageModelTest()
264 : last_save_result_(SavePageResult::CANCELLED
),
265 last_load_result_(LoadResult::CANCELLED
),
266 last_delete_result_(DeletePageResult::CANCELLED
) {
269 OfflinePageModelTest::~OfflinePageModelTest() {
272 void OfflinePageModelTest::SetUp() {
273 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
274 model_
= BuildModel().Pass();
277 void OfflinePageModelTest::OnSavePageDone(
278 OfflinePageModel::SavePageResult result
) {
280 last_save_result_
= result
;
283 void OfflinePageModelTest::OnLoadAllPagesDone(
285 const std::vector
<OfflinePageItem
>& offline_pages
) {
287 last_load_result_
= result
;
288 last_loaded_pages_
= offline_pages
;
291 void OfflinePageModelTest::OnDeletePageDone(DeletePageResult result
) {
293 last_delete_result_
= result
;
296 scoped_ptr
<OfflinePageTestArchiver
> OfflinePageModelTest::BuildArchiver(
297 const GURL
& url
, const base::string16
& title
,
298 OfflinePageArchiver::ArchiverResult result
) {
299 return scoped_ptr
<OfflinePageTestArchiver
>(new OfflinePageTestArchiver(
300 this, url
, title
, temp_dir_
.path(), result
, task_runner()));
303 scoped_ptr
<OfflinePageMetadataStore
> OfflinePageModelTest::BuildStore() {
304 return scoped_ptr
<OfflinePageMetadataStore
>(
305 new OfflinePageTestStore(task_runner()));
308 scoped_ptr
<OfflinePageModel
> OfflinePageModelTest::BuildModel() {
309 return scoped_ptr
<OfflinePageModel
>(
310 new OfflinePageModel(BuildStore().Pass(), task_runner()));
313 void OfflinePageModelTest::PumpLoop() {
314 run_loop_
.reset(new base::RunLoop());
318 void OfflinePageModelTest::ResetResults() {
319 last_save_result_
= SavePageResult::CANCELLED
;
320 last_load_result_
= LoadResult::CANCELLED
;
321 last_delete_result_
= DeletePageResult::CANCELLED
;
322 last_loaded_pages_
.clear();
323 last_archiver_path_
.clear();
326 OfflinePageTestStore
* OfflinePageModelTest::GetStore() {
327 return static_cast<OfflinePageTestStore
*>(model()->GetStoreForTesting());
330 TEST_F(OfflinePageModelTest
, SavePageSuccessful
) {
331 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
332 kTestUrl
, kTestPageTitle
,
333 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
334 model()->SavePage(kTestUrl
, archiver
.Pass(),
335 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
339 OfflinePageTestStore
* store
= GetStore();
340 EXPECT_EQ(kTestUrl
, store
->last_saved_page().url
);
341 EXPECT_EQ(kTestPageTitle
, store
->last_saved_page().title
);
342 // Save last_archiver_path since it will be referred to later.
343 base::FilePath archiver_path
= last_archiver_path();
344 EXPECT_EQ(archiver_path
, store
->last_saved_page().file_path
);
345 EXPECT_EQ(kTestFileSize
, store
->last_saved_page().file_size
);
346 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
350 model()->LoadAllPages(base::Bind(&OfflinePageModelTest::OnLoadAllPagesDone
,
353 EXPECT_EQ(LoadResult::SUCCESS
, last_load_result());
354 EXPECT_EQ(1UL, last_loaded_pages().size());
355 EXPECT_EQ(kTestUrl
, last_loaded_pages()[0].url
);
356 EXPECT_EQ(kTestPageTitle
, last_loaded_pages()[0].title
);
357 EXPECT_EQ(archiver_path
, last_loaded_pages()[0].file_path
);
358 EXPECT_EQ(kTestFileSize
, last_loaded_pages()[0].file_size
);
361 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverCancelled
) {
362 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
363 kTestUrl
, kTestPageTitle
,
364 OfflinePageArchiver::ArchiverResult::ERROR_CANCELED
).Pass());
365 model()->SavePage(kTestUrl
, archiver
.Pass(),
366 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
369 EXPECT_EQ(SavePageResult::CANCELLED
, last_save_result());
372 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverDeviceFull
) {
373 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
374 kTestUrl
, kTestPageTitle
,
375 OfflinePageArchiver::ArchiverResult::ERROR_DEVICE_FULL
).Pass());
376 model()->SavePage(kTestUrl
, archiver
.Pass(),
377 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
380 EXPECT_EQ(SavePageResult::DEVICE_FULL
, last_save_result());
383 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverContentUnavailable
) {
384 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
385 kTestUrl
, kTestPageTitle
,
386 OfflinePageArchiver::ArchiverResult::ERROR_CONTENT_UNAVAILABLE
).Pass());
387 model()->SavePage(kTestUrl
, archiver
.Pass(),
388 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
391 EXPECT_EQ(SavePageResult::CONTENT_UNAVAILABLE
, last_save_result());
394 TEST_F(OfflinePageModelTest
, SavePageOfflineCreationFailed
) {
395 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
396 kTestUrl
, kTestPageTitle
,
397 OfflinePageArchiver::ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED
).
399 model()->SavePage(kTestUrl
, archiver
.Pass(),
400 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
403 EXPECT_EQ(SavePageResult::ARCHIVE_CREATION_FAILED
, last_save_result());
406 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverReturnedWrongUrl
) {
407 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
408 GURL("http://other.random.url.com"), kTestPageTitle
,
409 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
410 model()->SavePage(kTestUrl
, archiver
.Pass(),
411 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
414 EXPECT_EQ(SavePageResult::ARCHIVE_CREATION_FAILED
, last_save_result());
417 TEST_F(OfflinePageModelTest
, SavePageOfflineCreationStoreWriteFailure
) {
418 GetStore()->set_test_scenario(
419 OfflinePageTestStore::TestScenario::WRITE_FAILED
);
420 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
421 kTestUrl
, kTestPageTitle
,
422 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
423 model()->SavePage(kTestUrl
, archiver
.Pass(),
424 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
427 EXPECT_EQ(SavePageResult::STORE_FAILURE
, last_save_result());
430 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverTwoPages
) {
431 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
432 kTestUrl
, kTestPageTitle
,
433 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
434 // archiver_ptr will be valid until after first PumpLoop() call after
435 // CompleteCreateArchive() is called.
436 OfflinePageTestArchiver
* archiver_ptr
= archiver
.get();
437 archiver_ptr
->set_delayed(true);
438 model()->SavePage(kTestUrl
, archiver
.Pass(),
439 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
441 EXPECT_TRUE(archiver_ptr
->create_archive_called());
443 // Request to save another page.
444 scoped_ptr
<OfflinePageTestArchiver
> archiver2(BuildArchiver(
445 kTestUrl2
, kTestPageTitle2
,
446 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
447 model()->SavePage(kTestUrl2
, archiver2
.Pass(),
448 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
452 OfflinePageTestStore
* store
= GetStore();
454 EXPECT_EQ(kTestUrl2
, store
->last_saved_page().url
);
455 EXPECT_EQ(kTestPageTitle2
, store
->last_saved_page().title
);
456 base::FilePath archiver_path2
= last_archiver_path();
457 EXPECT_EQ(archiver_path2
, store
->last_saved_page().file_path
);
458 EXPECT_EQ(kTestFileSize
, store
->last_saved_page().file_size
);
459 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
463 archiver_ptr
->CompleteCreateArchive();
464 // After this pump loop archiver_ptr is invalid.
467 EXPECT_EQ(kTestUrl
, store
->last_saved_page().url
);
468 EXPECT_EQ(kTestPageTitle
, store
->last_saved_page().title
);
469 base::FilePath archiver_path
= last_archiver_path();
470 EXPECT_EQ(archiver_path
, store
->last_saved_page().file_path
);
471 EXPECT_EQ(kTestFileSize
, store
->last_saved_page().file_size
);
472 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
476 model()->LoadAllPages(base::Bind(&OfflinePageModelTest::OnLoadAllPagesDone
,
479 EXPECT_EQ(LoadResult::SUCCESS
, last_load_result());
480 EXPECT_EQ(2UL, last_loaded_pages().size());
481 EXPECT_EQ(kTestUrl2
, last_loaded_pages()[0].url
);
482 EXPECT_EQ(kTestPageTitle2
, last_loaded_pages()[0].title
);
483 EXPECT_EQ(archiver_path2
, last_loaded_pages()[0].file_path
);
484 EXPECT_EQ(kTestFileSize
, last_loaded_pages()[0].file_size
);
485 EXPECT_EQ(kTestUrl
, last_loaded_pages()[1].url
);
486 EXPECT_EQ(kTestPageTitle
, last_loaded_pages()[1].title
);
487 EXPECT_EQ(archiver_path
, last_loaded_pages()[1].file_path
);
488 EXPECT_EQ(kTestFileSize
, last_loaded_pages()[1].file_size
);
491 TEST_F(OfflinePageModelTest
, LoadAllPagesStoreEmpty
) {
492 model()->LoadAllPages(base::Bind(&OfflinePageModelTest::OnLoadAllPagesDone
,
495 EXPECT_EQ(LoadResult::SUCCESS
, last_load_result());
496 EXPECT_EQ(0UL, last_loaded_pages().size());
499 TEST_F(OfflinePageModelTest
, LoadAllPagesStoreFailure
) {
500 GetStore()->set_test_scenario(
501 OfflinePageTestStore::TestScenario::LOAD_FAILED
);
502 model()->LoadAllPages(base::Bind(&OfflinePageModelTest::OnLoadAllPagesDone
,
505 EXPECT_EQ(LoadResult::STORE_FAILURE
, last_load_result());
506 EXPECT_EQ(0UL, last_loaded_pages().size());
509 TEST_F(OfflinePageModelTest
, DeletePageSuccessful
) {
510 OfflinePageTestStore
* store
= GetStore();
513 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
514 kTestUrl
, kTestPageTitle
,
515 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
516 model()->SavePage(kTestUrl
, archiver
.Pass(),
517 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
521 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
522 EXPECT_EQ(1u, store
->offline_pages().size());
526 // Save another page.
527 scoped_ptr
<OfflinePageTestArchiver
> archiver2(BuildArchiver(
528 kTestUrl2
, kTestPageTitle2
,
529 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
530 model()->SavePage(kTestUrl2
, archiver2
.Pass(),
531 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
535 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
536 EXPECT_EQ(2u, store
->offline_pages().size());
541 model()->DeletePage(kTestUrl
,
542 base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
547 EXPECT_EQ(DeletePageResult::SUCCESS
, last_delete_result());
548 ASSERT_EQ(1u, store
->offline_pages().size());
549 EXPECT_EQ(kTestUrl2
, store
->offline_pages()[0].url
);
551 // Delete another page.
552 model()->DeletePage(kTestUrl2
,
553 base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
560 EXPECT_EQ(DeletePageResult::SUCCESS
, last_delete_result());
561 EXPECT_EQ(0u, store
->offline_pages().size());
564 TEST_F(OfflinePageModelTest
, DeletePageStoreFailureOnLoad
) {
565 GetStore()->set_test_scenario(
566 OfflinePageTestStore::TestScenario::LOAD_FAILED
);
567 model()->DeletePage(kTestUrl
,
568 base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
571 EXPECT_EQ(DeletePageResult::STORE_FAILURE
, last_delete_result());
574 TEST_F(OfflinePageModelTest
, DeletePageNotFound
) {
575 model()->DeletePage(kTestUrl
,
576 base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
579 EXPECT_EQ(DeletePageResult::NOT_FOUND
, last_delete_result());
582 TEST_F(OfflinePageModelTest
, DeletePageStoreFailureOnRemove
) {
584 scoped_ptr
<OfflinePageTestArchiver
> archiver(BuildArchiver(
585 kTestUrl
, kTestPageTitle
,
586 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
).Pass());
587 model()->SavePage(kTestUrl
, archiver
.Pass(),
588 base::Bind(&OfflinePageModelTest::OnSavePageDone
,
594 // Try to delete this page.
595 GetStore()->set_test_scenario(
596 OfflinePageTestStore::TestScenario::REMOVE_FAILED
);
597 model()->DeletePage(kTestUrl
,
598 base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
601 EXPECT_EQ(DeletePageResult::STORE_FAILURE
, last_delete_result());
604 } // namespace offline_pages