blob: 55853a39c82a0e06010238dc1a6bc0462b3d88e0 [file] [log] [blame]
// 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_job_controller.h"
#include <memory>
#include <string>
#include <unordered_map>
#include "base/guid.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "content/browser/background_fetch/background_fetch_constants.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/background_fetch/background_fetch_test_base.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/fake_download_item.h"
#include "content/public/test/mock_download_manager.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_context_getter.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_;
namespace content {
namespace {
const char kExampleTag[] = "my-example-tag";
class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
public:
BackgroundFetchJobControllerTest() : data_manager_(browser_context()) {}
~BackgroundFetchJobControllerTest() override = default;
// Creates a new Background Fetch registration, whose id will be stored in
// the |*registration_id|, and registers it with the DataManager for the
// included |request_data|. Should be wrapped in ASSERT_NO_FATAL_FAILURE().
void CreateRegistrationForRequests(
BackgroundFetchRegistrationId* registration_id,
std::vector<scoped_refptr<BackgroundFetchRequestInfo>>*
out_initial_requests,
std::map<std::string /* url */, std::string /* method */> request_data) {
DCHECK(registration_id);
DCHECK(out_initial_requests);
ASSERT_TRUE(CreateRegistrationId(kExampleTag, registration_id));
std::vector<ServiceWorkerFetchRequest> requests;
requests.reserve(request_data.size());
for (const auto& pair : request_data) {
requests.emplace_back(GURL(pair.first), pair.second /* method */,
ServiceWorkerHeaderMap(), Referrer(),
false /* is_reload */);
}
blink::mojom::BackgroundFetchError error;
base::RunLoop run_loop;
data_manager_.CreateRegistration(
*registration_id, requests, BackgroundFetchOptions(),
base::BindOnce(&BackgroundFetchJobControllerTest::DidCreateRegistration,
base::Unretained(this), &error, out_initial_requests,
run_loop.QuitClosure()));
run_loop.Run();
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
ASSERT_GE(out_initial_requests->size(), 1u);
ASSERT_LE(out_initial_requests->size(),
kMaximumBackgroundFetchParallelRequests);
// Provide fake responses for the given |request_data| pairs.
for (const auto& pair : request_data) {
CreateRequestWithProvidedResponse(
pair.second, pair.first,
TestResponseBuilder(200 /* response_code */).Build());
}
}
// Creates a new BackgroundFetchJobController instance.
std::unique_ptr<BackgroundFetchJobController> CreateJobController(
const BackgroundFetchRegistrationId& registration_id) {
StoragePartition* storage_partition =
BrowserContext::GetDefaultStoragePartition(browser_context());
return base::MakeUnique<BackgroundFetchJobController>(
registration_id, BackgroundFetchOptions(), &data_manager_,
browser_context(),
make_scoped_refptr(storage_partition->GetURLRequestContext()),
base::BindOnce(&BackgroundFetchJobControllerTest::DidCompleteJob,
base::Unretained(this)));
}
protected:
BackgroundFetchDataManager data_manager_;
bool did_complete_job_ = false;
// Closure that will be invoked when the JobController has completed all
// available jobs. Enables use of a run loop for deterministic waits.
base::OnceClosure job_completed_closure_;
private:
void DidCreateRegistration(
blink::mojom::BackgroundFetchError* out_error,
std::vector<scoped_refptr<BackgroundFetchRequestInfo>>*
out_initial_requests,
const base::Closure& quit_closure,
blink::mojom::BackgroundFetchError error,
std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) {
DCHECK(out_error);
DCHECK(out_initial_requests);
*out_error = error;
*out_initial_requests = std::move(initial_requests);
quit_closure.Run();
}
void DidCompleteJob(BackgroundFetchJobController* controller) {
DCHECK(controller);
EXPECT_TRUE(
controller->state() == BackgroundFetchJobController::State::ABORTED ||
controller->state() == BackgroundFetchJobController::State::COMPLETED);
did_complete_job_ = true;
if (job_completed_closure_)
std::move(job_completed_closure_).Run();
}
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchJobControllerTest);
};
TEST_F(BackgroundFetchJobControllerTest, SingleRequestJob) {
BackgroundFetchRegistrationId registration_id;
std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests;
ASSERT_NO_FATAL_FAILURE(CreateRegistrationForRequests(
&registration_id, &initial_requests,
{{"https://example.com/funny_cat.png", "GET"}}));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id);
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::INITIALIZED);
controller->Start(initial_requests /* deliberate copy */,
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::FETCHING);
// Mark the single download item as finished, completing the job.
{
base::RunLoop run_loop;
job_completed_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::COMPLETED);
EXPECT_TRUE(did_complete_job_);
}
TEST_F(BackgroundFetchJobControllerTest, MultipleRequestJob) {
BackgroundFetchRegistrationId registration_id;
std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests;
// This test should always issue more requests than the number of allowed
// parallel requests. That way we ensure testing the iteration behaviour.
ASSERT_GT(5u, kMaximumBackgroundFetchParallelRequests);
ASSERT_NO_FATAL_FAILURE(CreateRegistrationForRequests(
&registration_id, &initial_requests,
{{"https://example.com/funny_cat.png", "GET"},
{"https://example.com/scary_cat.png", "GET"},
{"https://example.com/crazy_cat.png", "GET"},
{"https://example.com/silly_cat.png", "GET"},
{"https://example.com/happy_cat.png", "GET"}}));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id);
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::INITIALIZED);
// Continue spinning until the Job Controller has completed all the requests.
// The Download Manager has been told to automatically mark them as finished.
{
base::RunLoop run_loop;
job_completed_closure_ = run_loop.QuitClosure();
controller->Start(initial_requests /* deliberate copy */,
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::FETCHING);
run_loop.Run();
}
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::COMPLETED);
EXPECT_TRUE(did_complete_job_);
}
TEST_F(BackgroundFetchJobControllerTest, AbortJob) {
BackgroundFetchRegistrationId registration_id;
std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests;
ASSERT_NO_FATAL_FAILURE(CreateRegistrationForRequests(
&registration_id, &initial_requests,
{{"https://example.com/sad_cat.png", "GET"}}));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id);
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::INITIALIZED);
// Start the set of |initial_requests|, and abort them immediately after.
{
base::RunLoop run_loop;
job_completed_closure_ = run_loop.QuitClosure();
controller->Start(initial_requests /* deliberate copy */,
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(controller->state(),
BackgroundFetchJobController::State::FETCHING);
controller->Abort();
run_loop.Run();
}
// TODO(peter): Verify that the issued download items have had their state
// updated to be cancelled as well.
EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::ABORTED);
EXPECT_TRUE(did_complete_job_);
}
} // namespace
} // namespace content