#include "content/browser/background_fetch/mock_background_fetch_delegate.h"
#include <utility>
#include <vector>
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "content/public/browser/background_fetch_description.h"
#include "content/public/browser/background_fetch_response.h"
#include "content/public/browser/browser_thread.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/header_util.h"
namespace content {
MockBackgroundFetchDelegate::TestResponse::TestResponse() = default;
MockBackgroundFetchDelegate::TestResponse::~TestResponse() = default;
MockBackgroundFetchDelegate::TestResponseBuilder::TestResponseBuilder(
int response_code)
: response_(std::make_unique<TestResponse>()) {
response_->succeeded = network::IsSuccessfulStatus(response_code);
response_->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
"HTTP/1.1 " + base::NumberToString(response_code));
}
MockBackgroundFetchDelegate::TestResponseBuilder::~TestResponseBuilder() =
default;
MockBackgroundFetchDelegate::TestResponseBuilder&
MockBackgroundFetchDelegate::TestResponseBuilder::AddResponseHeader(
const std::string& name,
const std::string& value) {
DCHECK(response_);
response_->headers->AddHeader(name, value);
return *this;
}
MockBackgroundFetchDelegate::TestResponseBuilder&
MockBackgroundFetchDelegate::TestResponseBuilder::SetResponseData(
std::string data) {
DCHECK(response_);
response_->data.swap(data);
return *this;
}
MockBackgroundFetchDelegate::TestResponseBuilder&
MockBackgroundFetchDelegate::TestResponseBuilder::MakeIndefinitelyPending() {
response_->pending = true;
return *this;
}
std::unique_ptr<MockBackgroundFetchDelegate::TestResponse>
MockBackgroundFetchDelegate::TestResponseBuilder::Build() {
return std::move(response_);
}
MockBackgroundFetchDelegate::MockBackgroundFetchDelegate() {}
MockBackgroundFetchDelegate::~MockBackgroundFetchDelegate() {}
void MockBackgroundFetchDelegate::GetIconDisplaySize(
GetIconDisplaySizeCallback callback) {}
void MockBackgroundFetchDelegate::CreateDownloadJob(
base::WeakPtr<Client> client,
std::unique_ptr<BackgroundFetchDescription> fetch_description) {
job_id_to_client_map_[fetch_description->job_unique_id] = std::move(client);
}
void MockBackgroundFetchDelegate::DownloadUrl(
const std::string& job_unique_id,
const std::string& guid,
const std::string& method,
const GURL& url,
::network::mojom::CredentialsMode credentials_mode,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const net::HttpRequestHeaders& headers,
bool has_request_body) {
DCHECK(!seen_guids_.count(guid));
download_guid_to_job_id_map_[guid] = job_unique_id;
auto url_iter = url_responses_.find(url);
if (url_iter == url_responses_.end()) {
return;
}
std::unique_ptr<TestResponse> test_response = std::move(url_iter->second);
url_responses_.erase(url_iter);
if (test_response->pending)
return;
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadStarted,
job_id_to_client_map_[job_unique_id], job_unique_id, guid,
std::make_unique<BackgroundFetchResponse>(
std::vector<GURL>({url}), test_response->headers)));
uint64_t bytes_uploaded = 0u;
if (has_request_body) {
bytes_uploaded = 42u;
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadUpdated,
job_id_to_client_map_[job_unique_id], job_unique_id,
guid, bytes_uploaded, 0u));
}
if (test_response->data.size()) {
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadUpdated,
job_id_to_client_map_[job_unique_id], job_unique_id,
guid, bytes_uploaded, test_response->data.size() / 2));
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadUpdated,
job_id_to_client_map_[job_unique_id], job_unique_id,
guid, bytes_uploaded, test_response->data.size()));
}
if (test_response->succeeded) {
base::FilePath response_path;
if (!temp_directory_.IsValid()) {
CHECK(temp_directory_.CreateUniqueTempDir());
}
CHECK(base::CreateTemporaryFileInDir(temp_directory_.GetPath(),
&response_path));
CHECK(base::WriteFile(response_path, test_response->data));
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(
&BackgroundFetchDelegate::Client::OnDownloadComplete,
job_id_to_client_map_[job_unique_id], job_unique_id, guid,
std::make_unique<BackgroundFetchResult>(
std::make_unique<BackgroundFetchResponse>(
std::vector<GURL>({url}), test_response->headers),
base::Time::Now(), response_path,
std::nullopt, test_response->data.size())));
} else {
auto response = std::make_unique<BackgroundFetchResponse>(
std::vector<GURL>({url}), test_response->headers);
auto result = std::make_unique<BackgroundFetchResult>(
std::move(response), base::Time::Now(),
BackgroundFetchResult::FailureReason::FETCH_ERROR);
PostAbortCheckingTask(
job_unique_id,
base::BindOnce(&BackgroundFetchDelegate::Client::OnDownloadComplete,
job_id_to_client_map_[job_unique_id], job_unique_id,
guid, std::move(result)));
}
seen_guids_.insert(guid);
}
void MockBackgroundFetchDelegate::Abort(const std::string& job_unique_id) {
aborted_jobs_.insert(job_unique_id);
}
void MockBackgroundFetchDelegate::MarkJobComplete(
const std::string& job_unique_id) {
completed_jobs_.insert(job_unique_id);
}
void MockBackgroundFetchDelegate::UpdateUI(
const std::string& job_unique_id,
const std::optional<std::string>& title,
const std::optional<SkBitmap>& icon) {
job_id_to_client_map_[job_unique_id]->OnUIUpdated(job_unique_id);
}
void MockBackgroundFetchDelegate::RegisterResponse(
const GURL& url,
std::unique_ptr<TestResponse> response) {
DCHECK_EQ(0u, url_responses_.count(url));
url_responses_[url] = std::move(response);
}
void MockBackgroundFetchDelegate::PostAbortCheckingTask(
const std::string& job_unique_id,
base::OnceCallback<void()> callback) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&MockBackgroundFetchDelegate::RunAbortCheckingTask,
base::Unretained(this), job_unique_id,
std::move(callback)));
}
void MockBackgroundFetchDelegate::RunAbortCheckingTask(
const std::string& job_unique_id,
base::OnceCallback<void()> callback) {
if (!aborted_jobs_.count(job_unique_id))
std::move(callback).Run();
}
}