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 DeletePageResult
= offline_pages::OfflinePageModel::DeletePageResult
;
25 namespace offline_pages
{
28 const GURL
kTestUrl("http://example.com");
29 const int64 kTestPageBookmarkId1
= 1234LL;
30 const GURL
kTestUrl2("http://other.page.com");
31 const int64 kTestPageBookmarkId2
= 5678LL;
32 const int64 kTestFileSize
= 876543LL;
34 class OfflinePageTestStore
: public OfflinePageMetadataStore
{
36 enum class TestScenario
{
43 explicit OfflinePageTestStore(
44 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
);
45 ~OfflinePageTestStore() override
;
47 // OfflinePageMetadataStore overrides:
48 void Load(const LoadCallback
& callback
) override
;
49 void AddOfflinePage(const OfflinePageItem
& offline_page
,
50 const UpdateCallback
& callback
) override
;
51 void RemoveOfflinePage(const GURL
& page_url
,
52 const UpdateCallback
& callback
) override
;
53 const OfflinePageItem
& last_saved_page() const { return last_saved_page_
; }
55 void set_test_scenario(TestScenario scenario
) { scenario_
= scenario
; };
57 const std::vector
<OfflinePageItem
>& offline_pages() const {
58 return offline_pages_
;
62 OfflinePageItem last_saved_page_
;
63 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
64 TestScenario scenario_
;
66 std::vector
<OfflinePageItem
> offline_pages_
;
68 DISALLOW_COPY_AND_ASSIGN(OfflinePageTestStore
);
71 OfflinePageTestStore::OfflinePageTestStore(
72 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
)
73 : task_runner_(task_runner
),
74 scenario_(TestScenario::SUCCESSFUL
) {
77 OfflinePageTestStore::~OfflinePageTestStore() {
80 void OfflinePageTestStore::Load(const LoadCallback
& callback
) {
81 if (scenario_
!= TestScenario::LOAD_FAILED
) {
82 task_runner_
->PostTask(
83 FROM_HERE
, base::Bind(callback
, true, offline_pages_
));
85 task_runner_
->PostTask(
86 FROM_HERE
, base::Bind(callback
, false, std::vector
<OfflinePageItem
>()));
90 void OfflinePageTestStore::AddOfflinePage(const OfflinePageItem
& offline_page
,
91 const UpdateCallback
& callback
) {
92 last_saved_page_
= offline_page
;
93 bool result
= scenario_
!= TestScenario::WRITE_FAILED
;
95 offline_pages_
.push_back(offline_page
);
97 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, result
));
100 void OfflinePageTestStore::RemoveOfflinePage(const GURL
& page_url
,
101 const UpdateCallback
& callback
) {
103 if (scenario_
!= TestScenario::REMOVE_FAILED
) {
104 for (auto iter
= offline_pages_
.begin();
105 iter
!= offline_pages_
.end(); ++iter
) {
106 if (iter
->url
== page_url
) {
107 offline_pages_
.erase(iter
);
114 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback
, result
));
119 class OfflinePageModelTest
;
121 class OfflinePageTestArchiver
: public OfflinePageArchiver
{
123 OfflinePageTestArchiver(
124 OfflinePageModelTest
* test
,
126 const base::FilePath
& archiver_dir
,
127 ArchiverResult result
,
128 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
);
129 ~OfflinePageTestArchiver() override
;
131 // OfflinePageArchiver implementation:
132 void CreateArchive(const CreateArchiveCallback
& callback
) override
;
134 void CompleteCreateArchive();
136 void set_delayed(bool delayed
) { delayed_
= delayed
; }
138 bool create_archive_called() const { return create_archive_called_
; }
141 OfflinePageModelTest
* test_
; // Outlive OfflinePageTestArchiver.
143 base::FilePath archiver_dir_
;
144 ArchiverResult result_
;
145 bool create_archive_called_
;
147 CreateArchiveCallback callback_
;
148 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
149 DISALLOW_COPY_AND_ASSIGN(OfflinePageTestArchiver
);
152 class OfflinePageModelTest
153 : public testing::Test
,
154 public OfflinePageModel::Observer
,
155 public base::SupportsWeakPtr
<OfflinePageModelTest
> {
157 OfflinePageModelTest();
158 ~OfflinePageModelTest() override
;
160 void SetUp() override
;
161 void TearDown() override
;
163 // OfflinePageModel::Observer implementation.
164 void OfflinePageModelLoaded(OfflinePageModel
* model
) override
;
166 // OfflinePageModel callbacks.
167 void OnSavePageDone(SavePageResult result
);
168 void OnDeletePageDone(DeletePageResult result
);
170 scoped_ptr
<OfflinePageTestArchiver
> BuildArchiver(
172 OfflinePageArchiver::ArchiverResult result
);
173 scoped_ptr
<OfflinePageMetadataStore
> BuildStore();
174 scoped_ptr
<OfflinePageModel
> BuildModel();
180 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner() {
181 return message_loop_
.task_runner();
184 OfflinePageModel
* model() { return model_
.get(); }
186 OfflinePageTestStore
* GetStore();
188 SavePageResult
last_save_result() const {
189 return last_save_result_
;
192 DeletePageResult
last_delete_result() const {
193 return last_delete_result_
;
196 const base::FilePath
& last_archiver_path() { return last_archiver_path_
; }
197 void set_last_archiver_path(const base::FilePath
& last_archiver_path
) {
198 last_archiver_path_
= last_archiver_path
;
202 base::MessageLoop message_loop_
;
203 scoped_ptr
<base::RunLoop
> run_loop_
;
204 base::ScopedTempDir temp_dir_
;
206 scoped_ptr
<OfflinePageModel
> model_
;
207 SavePageResult last_save_result_
;
208 DeletePageResult last_delete_result_
;
209 base::FilePath last_archiver_path_
;
212 OfflinePageTestArchiver::OfflinePageTestArchiver(
213 OfflinePageModelTest
* test
,
215 const base::FilePath
& archiver_dir
,
216 ArchiverResult result
,
217 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
)
220 archiver_dir_(archiver_dir
),
222 create_archive_called_(false),
224 task_runner_(task_runner
) {
227 OfflinePageTestArchiver::~OfflinePageTestArchiver() {
228 EXPECT_TRUE(create_archive_called_
);
231 void OfflinePageTestArchiver::CreateArchive(
232 const CreateArchiveCallback
& callback
) {
233 create_archive_called_
= true;
234 callback_
= callback
;
236 CompleteCreateArchive();
239 void OfflinePageTestArchiver::CompleteCreateArchive() {
240 DCHECK(!callback_
.is_null());
241 base::FilePath archiver_path
;
242 ASSERT_TRUE(base::CreateTemporaryFileInDir(archiver_dir_
, &archiver_path
));
243 test_
->set_last_archiver_path(archiver_path
);
244 task_runner_
->PostTask(FROM_HERE
, base::Bind(callback_
, this, result_
, url_
,
245 archiver_path
, kTestFileSize
));
248 OfflinePageModelTest::OfflinePageModelTest()
249 : last_save_result_(SavePageResult::CANCELLED
),
250 last_delete_result_(DeletePageResult::CANCELLED
) {
253 OfflinePageModelTest::~OfflinePageModelTest() {
256 void OfflinePageModelTest::SetUp() {
257 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
258 model_
= BuildModel().Pass();
259 model_
->AddObserver(this);
263 void OfflinePageModelTest::TearDown() {
264 model_
->RemoveObserver(this);
267 void OfflinePageModelTest::OfflinePageModelLoaded(OfflinePageModel
* model
) {
268 ASSERT_EQ(model_
.get(), model
);
272 void OfflinePageModelTest::OnSavePageDone(
273 OfflinePageModel::SavePageResult result
) {
275 last_save_result_
= result
;
278 void OfflinePageModelTest::OnDeletePageDone(DeletePageResult result
) {
280 last_delete_result_
= result
;
283 scoped_ptr
<OfflinePageTestArchiver
> OfflinePageModelTest::BuildArchiver(
285 OfflinePageArchiver::ArchiverResult result
) {
286 return scoped_ptr
<OfflinePageTestArchiver
>(new OfflinePageTestArchiver(
287 this, url
, temp_dir_
.path(), result
, task_runner()));
290 scoped_ptr
<OfflinePageMetadataStore
> OfflinePageModelTest::BuildStore() {
291 return scoped_ptr
<OfflinePageMetadataStore
>(
292 new OfflinePageTestStore(task_runner()));
295 scoped_ptr
<OfflinePageModel
> OfflinePageModelTest::BuildModel() {
296 return scoped_ptr
<OfflinePageModel
>(
297 new OfflinePageModel(BuildStore().Pass(), task_runner()));
300 void OfflinePageModelTest::PumpLoop() {
301 run_loop_
.reset(new base::RunLoop());
305 void OfflinePageModelTest::ResetResults() {
306 last_save_result_
= SavePageResult::CANCELLED
;
307 last_delete_result_
= DeletePageResult::CANCELLED
;
308 last_archiver_path_
.clear();
311 OfflinePageTestStore
* OfflinePageModelTest::GetStore() {
312 return static_cast<OfflinePageTestStore
*>(model()->GetStoreForTesting());
315 TEST_F(OfflinePageModelTest
, SavePageSuccessful
) {
316 scoped_ptr
<OfflinePageTestArchiver
> archiver(
317 BuildArchiver(kTestUrl
,
318 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
321 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
322 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
325 OfflinePageTestStore
* store
= GetStore();
326 EXPECT_EQ(kTestUrl
, store
->last_saved_page().url
);
327 EXPECT_EQ(kTestPageBookmarkId1
, store
->last_saved_page().bookmark_id
);
328 // Save last_archiver_path since it will be referred to later.
329 base::FilePath archiver_path
= last_archiver_path();
330 EXPECT_EQ(archiver_path
, store
->last_saved_page().file_path
);
331 EXPECT_EQ(kTestFileSize
, store
->last_saved_page().file_size
);
332 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
336 const std::vector
<OfflinePageItem
>& offline_pages
= model()->GetAllPages();
338 EXPECT_EQ(1UL, offline_pages
.size());
339 EXPECT_EQ(kTestUrl
, offline_pages
[0].url
);
340 EXPECT_EQ(kTestPageBookmarkId1
, offline_pages
[0].bookmark_id
);
341 EXPECT_EQ(archiver_path
, offline_pages
[0].file_path
);
342 EXPECT_EQ(kTestFileSize
, offline_pages
[0].file_size
);
345 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverCancelled
) {
346 scoped_ptr
<OfflinePageTestArchiver
> archiver(
347 BuildArchiver(kTestUrl
,
348 OfflinePageArchiver::ArchiverResult::ERROR_CANCELED
)
351 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
352 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
354 EXPECT_EQ(SavePageResult::CANCELLED
, last_save_result());
357 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverDeviceFull
) {
358 scoped_ptr
<OfflinePageTestArchiver
> archiver(
359 BuildArchiver(kTestUrl
,
360 OfflinePageArchiver::ArchiverResult::ERROR_DEVICE_FULL
)
363 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
364 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
366 EXPECT_EQ(SavePageResult::DEVICE_FULL
, last_save_result());
369 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverContentUnavailable
) {
370 scoped_ptr
<OfflinePageTestArchiver
> archiver(
373 OfflinePageArchiver::ArchiverResult::ERROR_CONTENT_UNAVAILABLE
)
376 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
377 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
379 EXPECT_EQ(SavePageResult::CONTENT_UNAVAILABLE
, last_save_result());
382 TEST_F(OfflinePageModelTest
, SavePageOfflineCreationFailed
) {
383 scoped_ptr
<OfflinePageTestArchiver
> archiver(
386 OfflinePageArchiver::ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED
)
389 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
390 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
392 EXPECT_EQ(SavePageResult::ARCHIVE_CREATION_FAILED
, last_save_result());
395 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverReturnedWrongUrl
) {
396 scoped_ptr
<OfflinePageTestArchiver
> archiver(
397 BuildArchiver(GURL("http://other.random.url.com"),
398 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
401 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
402 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
404 EXPECT_EQ(SavePageResult::ARCHIVE_CREATION_FAILED
, last_save_result());
407 TEST_F(OfflinePageModelTest
, SavePageOfflineCreationStoreWriteFailure
) {
408 GetStore()->set_test_scenario(
409 OfflinePageTestStore::TestScenario::WRITE_FAILED
);
410 scoped_ptr
<OfflinePageTestArchiver
> archiver(
411 BuildArchiver(kTestUrl
,
412 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
415 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
416 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
418 EXPECT_EQ(SavePageResult::STORE_FAILURE
, last_save_result());
421 TEST_F(OfflinePageModelTest
, SavePageOfflineArchiverTwoPages
) {
422 scoped_ptr
<OfflinePageTestArchiver
> archiver(
423 BuildArchiver(kTestUrl
,
424 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
426 // archiver_ptr will be valid until after first PumpLoop() call after
427 // CompleteCreateArchive() is called.
428 OfflinePageTestArchiver
* archiver_ptr
= archiver
.get();
429 archiver_ptr
->set_delayed(true);
431 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
432 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
433 EXPECT_TRUE(archiver_ptr
->create_archive_called());
435 // Request to save another page.
436 scoped_ptr
<OfflinePageTestArchiver
> archiver2(
437 BuildArchiver(kTestUrl2
,
438 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
441 kTestUrl2
, kTestPageBookmarkId2
, archiver2
.Pass(),
442 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
445 OfflinePageTestStore
* store
= GetStore();
447 EXPECT_EQ(kTestUrl2
, store
->last_saved_page().url
);
448 EXPECT_EQ(kTestPageBookmarkId2
, store
->last_saved_page().bookmark_id
);
449 base::FilePath archiver_path2
= last_archiver_path();
450 EXPECT_EQ(archiver_path2
, store
->last_saved_page().file_path
);
451 EXPECT_EQ(kTestFileSize
, store
->last_saved_page().file_size
);
452 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
456 archiver_ptr
->CompleteCreateArchive();
457 // After this pump loop archiver_ptr is invalid.
460 EXPECT_EQ(kTestUrl
, store
->last_saved_page().url
);
461 EXPECT_EQ(kTestPageBookmarkId1
, store
->last_saved_page().bookmark_id
);
462 base::FilePath archiver_path
= last_archiver_path();
463 EXPECT_EQ(archiver_path
, store
->last_saved_page().file_path
);
464 EXPECT_EQ(kTestFileSize
, store
->last_saved_page().file_size
);
465 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
469 const std::vector
<OfflinePageItem
>& offline_pages
= model()->GetAllPages();
471 EXPECT_EQ(2UL, offline_pages
.size());
472 EXPECT_EQ(kTestUrl2
, offline_pages
[0].url
);
473 EXPECT_EQ(kTestPageBookmarkId2
, offline_pages
[0].bookmark_id
);
474 EXPECT_EQ(archiver_path2
, offline_pages
[0].file_path
);
475 EXPECT_EQ(kTestFileSize
, offline_pages
[0].file_size
);
476 EXPECT_EQ(kTestUrl
, offline_pages
[1].url
);
477 EXPECT_EQ(kTestPageBookmarkId1
, offline_pages
[1].bookmark_id
);
478 EXPECT_EQ(archiver_path
, offline_pages
[1].file_path
);
479 EXPECT_EQ(kTestFileSize
, offline_pages
[1].file_size
);
482 TEST_F(OfflinePageModelTest
, GetAllPagesStoreEmpty
) {
483 const std::vector
<OfflinePageItem
>& offline_pages
= model()->GetAllPages();
485 EXPECT_EQ(0UL, offline_pages
.size());
488 TEST_F(OfflinePageModelTest
, GetAllPagesStoreFailure
) {
489 GetStore()->set_test_scenario(
490 OfflinePageTestStore::TestScenario::LOAD_FAILED
);
491 const std::vector
<OfflinePageItem
>& offline_pages
= model()->GetAllPages();
493 EXPECT_EQ(0UL, offline_pages
.size());
496 TEST_F(OfflinePageModelTest
, DeletePageSuccessful
) {
497 OfflinePageTestStore
* store
= GetStore();
500 scoped_ptr
<OfflinePageTestArchiver
> archiver(
501 BuildArchiver(kTestUrl
,
502 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
505 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
506 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
509 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
510 EXPECT_EQ(1u, store
->offline_pages().size());
514 // Save another page.
515 scoped_ptr
<OfflinePageTestArchiver
> archiver2(
516 BuildArchiver(kTestUrl2
,
517 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
520 kTestUrl2
, kTestPageBookmarkId2
, archiver2
.Pass(),
521 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
524 EXPECT_EQ(SavePageResult::SUCCESS
, last_save_result());
525 EXPECT_EQ(2u, store
->offline_pages().size());
530 model()->DeletePageByBookmarkId(
531 kTestPageBookmarkId1
, base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
536 EXPECT_EQ(DeletePageResult::SUCCESS
, last_delete_result());
537 ASSERT_EQ(1u, store
->offline_pages().size());
538 EXPECT_EQ(kTestUrl2
, store
->offline_pages()[0].url
);
540 // Delete another page.
541 model()->DeletePageByBookmarkId(
542 kTestPageBookmarkId2
, base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
549 EXPECT_EQ(DeletePageResult::SUCCESS
, last_delete_result());
550 EXPECT_EQ(0u, store
->offline_pages().size());
553 TEST_F(OfflinePageModelTest
, DeletePageNotFound
) {
554 model()->DeletePageByBookmarkId(
555 kTestPageBookmarkId1
, base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
557 EXPECT_EQ(DeletePageResult::NOT_FOUND
, last_delete_result());
560 TEST_F(OfflinePageModelTest
, DeletePageStoreFailureOnRemove
) {
562 scoped_ptr
<OfflinePageTestArchiver
> archiver(
563 BuildArchiver(kTestUrl
,
564 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
567 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
568 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
573 // Try to delete this page.
574 GetStore()->set_test_scenario(
575 OfflinePageTestStore::TestScenario::REMOVE_FAILED
);
576 model()->DeletePageByBookmarkId(
577 kTestPageBookmarkId1
, base::Bind(&OfflinePageModelTest::OnDeletePageDone
,
580 EXPECT_EQ(DeletePageResult::STORE_FAILURE
, last_delete_result());
583 TEST_F(OfflinePageModelTest
, GetPageByBookmarkId
) {
584 scoped_ptr
<OfflinePageTestArchiver
> archiver(
585 BuildArchiver(kTestUrl
,
586 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
589 kTestUrl
, kTestPageBookmarkId1
, archiver
.Pass(),
590 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
593 scoped_ptr
<OfflinePageTestArchiver
> archiver2(
594 BuildArchiver(kTestUrl2
,
595 OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED
)
598 kTestUrl2
, kTestPageBookmarkId2
, archiver2
.Pass(),
599 base::Bind(&OfflinePageModelTest::OnSavePageDone
, AsWeakPtr()));
602 OfflinePageItem page
;
603 EXPECT_TRUE(model()->GetPageByBookmarkId(kTestPageBookmarkId1
, &page
));
604 EXPECT_EQ(kTestUrl
, page
.url
);
605 EXPECT_EQ(kTestPageBookmarkId1
, page
.bookmark_id
);
606 EXPECT_EQ(kTestFileSize
, page
.file_size
);
608 EXPECT_TRUE(model()->GetPageByBookmarkId(kTestPageBookmarkId2
, &page
));
609 EXPECT_EQ(kTestUrl2
, page
.url
);
610 EXPECT_EQ(kTestPageBookmarkId2
, page
.bookmark_id
);
611 EXPECT_EQ(kTestFileSize
, page
.file_size
);
613 EXPECT_FALSE(model()->GetPageByBookmarkId(-42, &page
));
616 } // namespace offline_pages