Chromium Code Reviews| Index: chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc |
| diff --git a/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7c2a55484e368b94d00f92c26e5d82b46e938960 |
| --- /dev/null |
| +++ b/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc |
| @@ -0,0 +1,236 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/android/offline_pages/background_loader_offliner.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/run_loop.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| +#include "chrome/test/base/testing_profile.h" |
| +#include "components/offline_pages/content/background_loader/background_loader_contents_stub.h" |
| +#include "components/offline_pages/core/background/offliner.h" |
| +#include "components/offline_pages/core/background/save_page_request.h" |
| +#include "components/offline_pages/core/stub_offline_page_model.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "content/public/test/web_contents_tester.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace offline_pages { |
| + |
| +namespace { |
| + |
| +const int64_t kRequestId = 7; |
| +const GURL kHttpUrl("http://www.tunafish.com"); |
| +const GURL kFileUrl("file://salmon.png"); |
| +const ClientId kClientId("AsyncLoading", "88"); |
| +const bool kUserRequested = true; |
| + |
| +// Mock OfflinePageModel for testing the SavePage calls |
| +class MockOfflinePageModel : public StubOfflinePageModel { |
|
Pete Williamson
2016/12/10 01:52:54
I wonder if this could be split out into a separat
|
| + public: |
| + MockOfflinePageModel() : mock_saving_(false) {} |
| + ~MockOfflinePageModel() override {} |
| + |
| + void SavePage(const SavePageParams& save_page_params, |
| + std::unique_ptr<OfflinePageArchiver> archiver, |
| + const SavePageCallback& callback) override { |
| + mock_saving_ = true; |
| + save_page_callback_ = callback; |
| + } |
| + |
| + void CompleteSavingAsArchiveCreationFailed() { |
| + DCHECK(mock_saving_); |
| + mock_saving_ = false; |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, base::Bind(save_page_callback_, |
| + SavePageResult::ARCHIVE_CREATION_FAILED, 0)); |
| + } |
| + |
| + void CompleteSavingAsSuccess() { |
| + DCHECK(mock_saving_); |
| + mock_saving_ = false; |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, |
| + base::Bind(save_page_callback_, SavePageResult::SUCCESS, 123456)); |
| + } |
| + |
| + bool mock_saving() const { return mock_saving_; } |
| + |
| + private: |
| + bool mock_saving_; |
| + SavePageCallback save_page_callback_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MockOfflinePageModel); |
| +}; |
| + |
| +void PumpLoop() { |
| + base::RunLoop().RunUntilIdle(); |
| +} |
| +} // namespace |
| + |
| +// A BackgroundLoader that we can run tests on. |
| +// Overrides the ResetState so we don't actually try to create any web contents. |
| +// This is a temporary solution to test core BackgroundLoaderOffliner |
| +// functionality until we straighten out assumptions made by RequestCoordinator |
| +// so that the ResetState method is no longer needed. |
| +class TestBackgroundLoaderOffliner : public BackgroundLoaderOffliner { |
| + public: |
| + explicit TestBackgroundLoaderOffliner( |
| + content::BrowserContext* browser_context, |
| + const OfflinerPolicy* policy, |
| + OfflinePageModel* offline_page_model); |
| + ~TestBackgroundLoaderOffliner() override; |
| + content::WebContentsTester* web_contents() { |
| + return content::WebContentsTester::For(stub_->web_contents()); |
| + } |
| + |
| + bool is_loading() { return stub_->is_loading(); } |
| + |
| + protected: |
| + void ResetState() override; |
| + |
| + private: |
| + background_loader::BackgroundLoaderContentsStub* stub_; |
| +}; |
| + |
| +TestBackgroundLoaderOffliner::TestBackgroundLoaderOffliner( |
| + content::BrowserContext* browser_context, |
| + const OfflinerPolicy* policy, |
| + OfflinePageModel* offline_page_model) |
| + : BackgroundLoaderOffliner(browser_context, policy, offline_page_model) {} |
| + |
| +TestBackgroundLoaderOffliner::~TestBackgroundLoaderOffliner() {} |
| + |
| +void TestBackgroundLoaderOffliner::ResetState() { |
| + stub_ = new background_loader::BackgroundLoaderContentsStub(browser_context_); |
| + loader_.reset(stub_); |
| + content::WebContentsObserver::Observe(stub_->web_contents()); |
| +} |
| + |
| +class BackgroundLoaderOfflinerTest : public testing::Test { |
| + public: |
| + BackgroundLoaderOfflinerTest(); |
| + ~BackgroundLoaderOfflinerTest() override; |
| + |
| + void SetUp() override; |
| + |
| + TestBackgroundLoaderOffliner* offliner() const { return offliner_.get(); } |
|
Pete Williamson
2016/12/10 01:52:54
Can this return the BackgroundLoaderOffliner inste
chili
2016/12/15 10:34:39
The Test has methods to call is_loading() (returns
|
| + Offliner::CompletionCallback const callback() { |
| + return base::Bind(&BackgroundLoaderOfflinerTest::OnCompletion, |
| + base::Unretained(this)); |
| + } |
| + Profile* profile() { return &profile_; } |
| + bool completion_callback_called() { return completion_callback_called_; } |
| + Offliner::RequestStatus request_status() { return request_status_; } |
| + bool SaveInProgress() const { return model_->mock_saving(); } |
| + MockOfflinePageModel* model() const { return model_; } |
| + |
| + void CompleteLoading() { |
| + offliner()->web_contents()->TestSetIsLoading(false); |
| + } |
| + |
| + private: |
| + void OnCompletion(const SavePageRequest& request, |
| + Offliner::RequestStatus status); |
| + content::TestBrowserThreadBundle thread_bundle_; |
| + TestingProfile profile_; |
| + std::unique_ptr<TestBackgroundLoaderOffliner> offliner_; |
| + MockOfflinePageModel* model_; |
| + bool completion_callback_called_; |
| + Offliner::RequestStatus request_status_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(BackgroundLoaderOfflinerTest); |
| +}; |
| + |
| +BackgroundLoaderOfflinerTest::BackgroundLoaderOfflinerTest() |
| + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), |
|
Pete Williamson
2016/12/10 01:52:54
Why use TestBrowserThreadBundle instead of ThreadT
dougarnett
2016/12/12 19:24:17
Not sure but I have faint recollection of needing
chili
2016/12/15 10:34:39
thread_task_runner_handle.cc fails with a "Must be
|
| + completion_callback_called_(false), |
| + request_status_(Offliner::RequestStatus::UNKNOWN) {} |
| + |
| +BackgroundLoaderOfflinerTest::~BackgroundLoaderOfflinerTest() {} |
| + |
| +void BackgroundLoaderOfflinerTest::SetUp() { |
| + model_ = new MockOfflinePageModel(); |
| + offliner_.reset(new TestBackgroundLoaderOffliner(profile(), nullptr, model_)); |
| +} |
| + |
| +void BackgroundLoaderOfflinerTest::OnCompletion( |
| + const SavePageRequest& request, |
| + Offliner::RequestStatus status) { |
| + DCHECK(!completion_callback_called_); // Expect 1 callback per request. |
| + completion_callback_called_ = true; |
| + request_status_ = status; |
| +} |
| + |
| +TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoading) { |
| + base::Time creation_time = base::Time::Now(); |
| + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, |
| + kUserRequested); |
| + EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); |
| + EXPECT_TRUE(offliner()->is_loading()); |
| + |
| + offliner()->Cancel(); |
| + EXPECT_FALSE(offliner()->is_loading()); |
| +} |
| + |
| +TEST_F(BackgroundLoaderOfflinerTest, CancelWhenLoaded) { |
| + base::Time creation_time = base::Time::Now(); |
| + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, |
| + kUserRequested); |
| + EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); |
| + EXPECT_TRUE(offliner()->is_loading()); |
| + |
| + CompleteLoading(); |
| + PumpLoop(); |
| + EXPECT_FALSE(completion_callback_called()); |
| + // Save still in progress because does not support canceling. |
|
Pete Williamson
2016/12/10 01:52:54
So what happens on a call to cancel when save is i
dougarnett
2016/12/12 19:24:17
This is a hole. We should have some bug opened or
dougarnett
2016/12/12 19:33:28
Actually, what happens to WebContents when ResetSt
chili
2016/12/15 10:34:39
This is a good point. ResetState would delete the
|
| + EXPECT_TRUE(SaveInProgress()); |
| + offliner()->Cancel(); |
| + |
| + // Subsequent save callback cause no crash. |
| + model()->CompleteSavingAsArchiveCreationFailed(); |
| + PumpLoop(); |
| + EXPECT_FALSE(completion_callback_called()); |
| + EXPECT_FALSE(SaveInProgress()); |
| +} |
| + |
| +TEST_F(BackgroundLoaderOfflinerTest, LoadedButSaveFails) { |
| + base::Time creation_time = base::Time::Now(); |
| + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, |
| + kUserRequested); |
| + EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); |
| + EXPECT_TRUE(offliner()->is_loading()); |
| + |
| + CompleteLoading(); |
| + PumpLoop(); |
| + model()->CompleteSavingAsArchiveCreationFailed(); |
| + PumpLoop(); |
| + EXPECT_TRUE(completion_callback_called()); |
| + EXPECT_EQ(Offliner::RequestStatus::SAVE_FAILED, request_status()); |
| + EXPECT_FALSE(offliner()->is_loading()); |
| + EXPECT_FALSE(SaveInProgress()); |
| +} |
| + |
| +TEST_F(BackgroundLoaderOfflinerTest, LoadAndSaveSuccess) { |
| + base::Time creation_time = base::Time::Now(); |
| + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, |
| + kUserRequested); |
| + EXPECT_TRUE(offliner()->LoadAndSave(request, callback())); |
| + EXPECT_TRUE(offliner()->is_loading()); |
| + EXPECT_EQ(Offliner::RequestStatus::UNKNOWN, request_status()); |
| + |
| + CompleteLoading(); |
| + PumpLoop(); |
| + EXPECT_FALSE(completion_callback_called()); |
| + EXPECT_TRUE(SaveInProgress()); |
| + |
| + model()->CompleteSavingAsSuccess(); |
| + PumpLoop(); |
| + EXPECT_TRUE(completion_callback_called()); |
| + EXPECT_EQ(Offliner::RequestStatus::SAVED, request_status()); |
| + EXPECT_FALSE(offliner()->is_loading()); |
| + EXPECT_FALSE(SaveInProgress()); |
| +} |
| + |
| +} // namespace offline_pages |