| // Copyright 2017 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 "content/browser/background_fetch/background_fetch_delegate_proxy.h" |
| |
| #include <set> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/task/post_task.h" |
| #include "content/browser/background_fetch/background_fetch_test_base.h" |
| #include "content/public/browser/background_fetch_delegate.h" |
| #include "content/public/browser/background_fetch_description.h" |
| #include "content/public/browser/background_fetch_response.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| const char kExampleUniqueId[] = "7e57ab1e-c0de-a150-ca75-1e75f005ba11"; |
| const char kExampleUniqueId2[] = "17467386-60b4-4c5b-b66c-aabf793fd39b"; |
| const int kIconDisplaySize = 192; |
| |
| class FakeBackgroundFetchDelegate : public BackgroundFetchDelegate { |
| public: |
| FakeBackgroundFetchDelegate() = default; |
| |
| // BackgroundFetchDelegate implementation: |
| void GetIconDisplaySize( |
| BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override { |
| std::move(callback).Run(gfx::Size(kIconDisplaySize, kIconDisplaySize)); |
| } |
| void GetPermissionForOrigin( |
| const url::Origin& origin, |
| const ResourceRequestInfo::WebContentsGetter& wc_getter, |
| GetPermissionForOriginCallback callback) override { |
| std::move(callback).Run(BackgroundFetchPermission::ALLOWED); |
| } |
| void CreateDownloadJob( |
| base::WeakPtr<Client> client, |
| std::unique_ptr<BackgroundFetchDescription> fetch_description) override { |
| job_id_to_client_.emplace(fetch_description->job_unique_id, |
| std::move(client)); |
| } |
| void DownloadUrl(const std::string& job_unique_id, |
| const std::string& guid, |
| const std::string& method, |
| const GURL& url, |
| const net::NetworkTrafficAnnotationTag& traffic_annotation, |
| const net::HttpRequestHeaders& headers, |
| bool has_request_body) override { |
| if (!job_id_to_client_[job_unique_id]) |
| return; |
| |
| download_guid_to_job_id_map_[guid] = job_unique_id; |
| download_guid_to_url_map_[guid] = url; |
| |
| auto response = std::make_unique<BackgroundFetchResponse>( |
| std::vector<GURL>({url}), |
| base::MakeRefCounted<net::HttpResponseHeaders>("200 OK")); |
| |
| job_id_to_client_[job_unique_id]->OnDownloadStarted(job_unique_id, guid, |
| std::move(response)); |
| if (complete_downloads_) { |
| base::PostTaskWithTraits( |
| FROM_HERE, {BrowserThread::IO}, |
| base::BindOnce(&FakeBackgroundFetchDelegate::CompleteDownload, |
| base::Unretained(this), job_unique_id, guid)); |
| } |
| } |
| |
| void Abort(const std::string& job_unique_id) override { |
| aborted_jobs_.insert(job_unique_id); |
| } |
| |
| void MarkJobComplete(const std::string& job_unique_id) override {} |
| |
| void UpdateUI(const std::string& job_unique_id, |
| const base::Optional<std::string>& title, |
| const base::Optional<SkBitmap>& icon) override { |
| ++ui_update_count_; |
| } |
| |
| void set_complete_downloads(bool complete_downloads) { |
| complete_downloads_ = complete_downloads; |
| } |
| |
| int ui_update_count_ = 0; |
| |
| private: |
| void CompleteDownload(const std::string& job_unique_id, |
| const std::string& guid) { |
| if (!job_id_to_client_[job_unique_id]) |
| return; |
| |
| if (aborted_jobs_.count(download_guid_to_job_id_map_[guid])) |
| return; |
| |
| auto response = std::make_unique<BackgroundFetchResponse>( |
| std::vector<GURL>({download_guid_to_url_map_[guid]}), |
| base::MakeRefCounted<net::HttpResponseHeaders>("200 OK")); |
| |
| job_id_to_client_[job_unique_id]->OnDownloadComplete( |
| job_unique_id, guid, |
| std::make_unique<BackgroundFetchResult>( |
| std::move(response), base::Time::Now(), base::FilePath(), |
| base::nullopt /* blob_handle */, 10u)); |
| download_guid_to_url_map_.erase(guid); |
| } |
| |
| std::set<std::string> aborted_jobs_; |
| std::map<std::string, std::string> download_guid_to_job_id_map_; |
| std::map<std::string, GURL> download_guid_to_url_map_; |
| std::map<std::string, base::WeakPtr<Client>> job_id_to_client_; |
| bool complete_downloads_ = true; |
| }; |
| |
| class FakeTestBrowserContext : public TestBrowserContext { |
| public: |
| FakeTestBrowserContext() = default; |
| ~FakeTestBrowserContext() override = default; |
| |
| FakeBackgroundFetchDelegate* GetBackgroundFetchDelegate() override { |
| if (!delegate_) |
| delegate_ = std::make_unique<FakeBackgroundFetchDelegate>(); |
| return delegate_.get(); |
| } |
| |
| private: |
| std::unique_ptr<FakeBackgroundFetchDelegate> delegate_; |
| }; |
| |
| class FakeController : public BackgroundFetchDelegateProxy::Controller { |
| public: |
| FakeController() : weak_ptr_factory_(this) {} |
| |
| void DidStartRequest( |
| const std::string& guid, |
| std::unique_ptr<BackgroundFetchResponse> response) override { |
| request_started_ = true; |
| } |
| |
| void DidUpdateRequest(const std::string& guid, |
| uint64_t bytes_uploaded, |
| uint64_t bytes_downloaded) override {} |
| |
| void DidCompleteRequest( |
| const std::string& guid, |
| std::unique_ptr<BackgroundFetchResult> result) override { |
| request_completed_ = true; |
| } |
| |
| void AbortFromDelegate( |
| blink::mojom::BackgroundFetchFailureReason reason_to_abort) override {} |
| |
| void GetUploadData( |
| const std::string& guid, |
| BackgroundFetchDelegate::GetUploadDataCallback callback) override {} |
| |
| bool request_started_ = false; |
| bool request_completed_ = false; |
| base::WeakPtrFactory<FakeController> weak_ptr_factory_; |
| }; |
| |
| class BackgroundFetchDelegateProxyTest : public BackgroundFetchTestBase { |
| public: |
| BackgroundFetchDelegateProxyTest() : delegate_proxy_(&browser_context_) { |
| delegate_ = browser_context_.GetBackgroundFetchDelegate(); |
| } |
| void DidGetIconDisplaySize(base::Closure quit_closure, |
| gfx::Size* out_display_size, |
| const gfx::Size& display_size) { |
| DCHECK(out_display_size); |
| *out_display_size = display_size; |
| std::move(quit_closure).Run(); |
| } |
| |
| protected: |
| FakeTestBrowserContext browser_context_; |
| FakeBackgroundFetchDelegate* delegate_; |
| BackgroundFetchDelegateProxy delegate_proxy_; |
| }; |
| |
| scoped_refptr<BackgroundFetchRequestInfo> CreateRequestInfo( |
| int request_index, |
| blink::mojom::FetchAPIRequestPtr fetch_request) { |
| auto request = base::MakeRefCounted<BackgroundFetchRequestInfo>( |
| request_index, std::move(fetch_request), /* has_request_body= */ false); |
| request->InitializeDownloadGuid(); |
| return request; |
| } |
| |
| } // namespace |
| |
| TEST_F(BackgroundFetchDelegateProxyTest, StartRequest) { |
| FakeController controller; |
| auto fetch_request = blink::mojom::FetchAPIRequest::New(); |
| auto request = |
| CreateRequestInfo(/* request_index= */ 0, std::move(fetch_request)); |
| |
| EXPECT_FALSE(controller.request_started_); |
| EXPECT_FALSE(controller.request_completed_); |
| |
| auto fetch_description = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId, url::Origin(), /* title= */ "Job 1", SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description)); |
| |
| delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(controller.request_started_); |
| EXPECT_TRUE(controller.request_completed_); |
| } |
| |
| TEST_F(BackgroundFetchDelegateProxyTest, StartRequest_NotCompleted) { |
| FakeController controller; |
| auto fetch_request = blink::mojom::FetchAPIRequest::New(); |
| auto request = |
| CreateRequestInfo(/* request_index= */ 0, std::move(fetch_request)); |
| |
| EXPECT_FALSE(controller.request_started_); |
| EXPECT_FALSE(controller.request_completed_); |
| |
| delegate_->set_complete_downloads(false); |
| auto fetch_description = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId, url::Origin(), /* title= */ "Job 1", SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description)); |
| |
| delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(controller.request_started_); |
| EXPECT_FALSE(controller.request_completed_); |
| } |
| |
| TEST_F(BackgroundFetchDelegateProxyTest, Abort) { |
| FakeController controller; |
| FakeController controller2; |
| auto fetch_request = blink::mojom::FetchAPIRequest::New(); |
| auto fetch_request2 = blink::mojom::FetchAPIRequest::New(); |
| auto request = |
| CreateRequestInfo(/* request_index= */ 0, std::move(fetch_request)); |
| auto request2 = |
| CreateRequestInfo(/* request_index= */ 1, std::move(fetch_request2)); |
| |
| EXPECT_FALSE(controller.request_started_); |
| EXPECT_FALSE(controller.request_completed_); |
| EXPECT_FALSE(controller2.request_started_); |
| EXPECT_FALSE(controller2.request_completed_); |
| |
| auto fetch_description1 = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId, url::Origin(), /* title= */ "Job 1", SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description1)); |
| |
| auto fetch_description2 = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId2, url::Origin(), /* title= */ "Job 2", SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| delegate_proxy_.CreateDownloadJob(controller2.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description2)); |
| |
| delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request); |
| delegate_proxy_.StartRequest(kExampleUniqueId2, url::Origin(), request2); |
| delegate_proxy_.Abort(kExampleUniqueId); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(controller.request_completed_) << "Aborted job completed"; |
| EXPECT_TRUE(controller2.request_started_) << "Normal job did not start"; |
| EXPECT_TRUE(controller2.request_completed_) << "Normal job did not complete"; |
| } |
| |
| TEST_F(BackgroundFetchDelegateProxyTest, GetIconDisplaySize) { |
| gfx::Size out_display_size; |
| base::RunLoop run_loop; |
| delegate_proxy_.GetIconDisplaySize(base::BindOnce( |
| &BackgroundFetchDelegateProxyTest::DidGetIconDisplaySize, |
| base::Unretained(this), run_loop.QuitClosure(), &out_display_size)); |
| run_loop.Run(); |
| EXPECT_EQ(out_display_size.width(), kIconDisplaySize); |
| EXPECT_EQ(out_display_size.height(), kIconDisplaySize); |
| } |
| |
| TEST_F(BackgroundFetchDelegateProxyTest, UpdateUI) { |
| FakeController controller; |
| auto fetch_request = blink::mojom::FetchAPIRequest::New(); |
| |
| auto request = |
| CreateRequestInfo(/* request_index= */ 0, std::move(fetch_request)); |
| auto fetch_description = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId, url::Origin(), /* title= */ "Job 1 Started.", |
| SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| |
| delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description)); |
| |
| delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(controller.request_started_); |
| EXPECT_TRUE(controller.request_completed_); |
| |
| delegate_proxy_.UpdateUI(kExampleUniqueId, "Job 1 Complete!", base::nullopt, |
| base::DoNothing()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(delegate_->ui_update_count_, 1); |
| } |
| |
| TEST_F(BackgroundFetchDelegateProxyTest, MultipleClients) { |
| FakeController controller1, controller2; |
| EXPECT_FALSE(controller1.request_started_); |
| EXPECT_FALSE(controller1.request_completed_); |
| EXPECT_FALSE(controller2.request_started_); |
| EXPECT_FALSE(controller2.request_completed_); |
| |
| BackgroundFetchDelegateProxy delegate_proxy1(&browser_context_); |
| BackgroundFetchDelegateProxy delegate_proxy2(&browser_context_); |
| |
| auto fetch_description1 = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId, url::Origin(), /* title= */ "Job 1", SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| auto fetch_description2 = std::make_unique<BackgroundFetchDescription>( |
| kExampleUniqueId2, url::Origin(), /* title= */ "Job 2", SkBitmap(), |
| /* completed_requests= */ 0, /* total_requests= */ 1, |
| /* downloaded_bytes= */ 0u, /* uploaded_bytes= */ 0u, |
| /* download_total= */ 0u, /* upload_total= */ 0u, |
| /* outstanding_guids= */ std::vector<std::string>(), |
| /* start_paused= */ false); |
| |
| delegate_proxy1.CreateDownloadJob(controller1.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description1)); |
| delegate_proxy2.CreateDownloadJob(controller2.weak_ptr_factory_.GetWeakPtr(), |
| std::move(fetch_description2)); |
| |
| auto request = CreateRequestInfo(/* request_index= */ 0, |
| blink::mojom::FetchAPIRequest::New()); |
| delegate_proxy1.StartRequest(kExampleUniqueId, url::Origin(), request); |
| delegate_proxy2.StartRequest(kExampleUniqueId2, url::Origin(), request); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(controller1.request_started_); |
| EXPECT_TRUE(controller1.request_completed_); |
| EXPECT_TRUE(controller2.request_started_); |
| EXPECT_TRUE(controller2.request_completed_); |
| } |
| |
| } // namespace content |