blob: 7fc81cd450a113a45d4c5ced76398fcc67e5d0ba [file] [log] [blame]
// 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 "content/browser/loader/test_resource_handler.h"
#include "base/logging.h"
#include "content/browser/loader/resource_controller.h"
#include "services/network/public/cpp/resource_response.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
class ScopedCallDepthTracker {
public:
explicit ScopedCallDepthTracker(int* call_depth) : call_depth_(call_depth) {
EXPECT_EQ(0, *call_depth_);
(*call_depth_)++;
}
~ScopedCallDepthTracker() {
EXPECT_EQ(1, *call_depth_);
(*call_depth_)--;
}
private:
int* const call_depth_;
DISALLOW_COPY_AND_ASSIGN(ScopedCallDepthTracker);
};
} // namespace
TestResourceHandler::TestResourceHandler(net::URLRequestStatus* request_status,
std::string* body)
: ResourceHandler(nullptr),
request_status_ptr_(request_status),
body_ptr_(body),
deferred_run_loop_(new base::RunLoop()),
weak_ptr_factory_(this) {
SetBufferSize(2048);
}
TestResourceHandler::TestResourceHandler()
: TestResourceHandler(nullptr, nullptr) {}
TestResourceHandler::~TestResourceHandler() {}
void TestResourceHandler::OnRequestRedirected(
const net::RedirectInfo& redirect_info,
network::ResourceResponse* response,
std::unique_ptr<ResourceController> controller) {
EXPECT_FALSE(canceled_);
EXPECT_EQ(1, on_will_start_called_);
EXPECT_EQ(0, on_response_started_called_);
EXPECT_EQ(0, on_response_completed_called_);
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
++on_request_redirected_called_;
if (!on_request_redirected_result_) {
canceled_ = true;
controller->Cancel();
return;
}
if (defer_on_request_redirected_) {
defer_on_request_redirected_ = false;
HoldController(std::move(controller));
deferred_run_loop_->Quit();
return;
}
controller->Resume();
}
void TestResourceHandler::OnResponseStarted(
network::ResourceResponse* response,
std::unique_ptr<ResourceController> controller) {
EXPECT_FALSE(canceled_);
EXPECT_EQ(1, on_will_start_called_);
EXPECT_EQ(0, on_response_started_called_);
EXPECT_EQ(0, on_response_completed_called_);
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
++on_response_started_called_;
EXPECT_FALSE(resource_response_);
resource_response_ = response;
response_started_run_loop_.Quit();
if (!on_response_started_result_) {
canceled_ = true;
controller->Cancel();
return;
}
if (!on_request_redirected_result_) {
controller->Cancel();
return;
}
if (defer_on_response_started_) {
defer_on_response_started_ = false;
HoldController(std::move(controller));
deferred_run_loop_->Quit();
return;
}
controller->Resume();
}
void TestResourceHandler::OnWillStart(
const GURL& url,
std::unique_ptr<ResourceController> controller) {
EXPECT_FALSE(canceled_);
EXPECT_EQ(0, on_response_started_called_);
EXPECT_EQ(0, on_will_start_called_);
EXPECT_EQ(0, on_response_completed_called_);
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
++on_will_start_called_;
start_url_ = url;
if (!on_will_start_result_) {
canceled_ = true;
controller->Cancel();
return;
}
if (defer_on_will_start_) {
defer_on_will_start_ = false;
HoldController(std::move(controller));
deferred_run_loop_->Quit();
return;
}
controller->Resume();
}
void TestResourceHandler::OnWillRead(
scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
std::unique_ptr<ResourceController> controller) {
EXPECT_FALSE(canceled_);
EXPECT_EQ(0, on_response_completed_called_);
// Only create a ScopedCallDepthTracker if not called re-entrantly, as
// OnWillRead may be called synchronously in response to a Resume(), but
// nothing may be called synchronously in response to the OnWillRead call.
std::unique_ptr<ScopedCallDepthTracker> call_depth_tracker;
if (call_depth_ == 0)
call_depth_tracker = std::make_unique<ScopedCallDepthTracker>(&call_depth_);
++on_will_read_called_;
if (!on_will_read_result_) {
canceled_ = true;
controller->Cancel();
return;
}
if (defer_on_will_read_) {
parent_read_buffer_ = buf;
parent_read_buffer_size_ = buf_size;
defer_on_will_read_ = false;
HoldController(std::move(controller));
deferred_run_loop_->Quit();
return;
}
*buf = buffer_;
*buf_size = buffer_size_;
controller->Resume();
}
void TestResourceHandler::OnReadCompleted(
int bytes_read,
std::unique_ptr<ResourceController> controller) {
EXPECT_FALSE(canceled_);
EXPECT_EQ(1, on_will_start_called_);
EXPECT_EQ(1, on_response_started_called_);
EXPECT_EQ(0, on_response_completed_called_);
EXPECT_EQ(0, on_read_eof_called_);
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
++on_read_completed_called_;
EXPECT_EQ(on_read_completed_called_, on_will_read_called_);
if (bytes_read == 0)
++on_read_eof_called_;
EXPECT_LE(static_cast<size_t>(bytes_read), buffer_size_);
if (body_ptr_)
body_ptr_->append(buffer_->data(), bytes_read);
body_.append(buffer_->data(), bytes_read);
if (!on_read_completed_result_ || (!on_read_eof_result_ && bytes_read == 0)) {
canceled_ = true;
controller->Cancel();
return;
}
if (defer_on_read_completed_ || (bytes_read == 0 && defer_on_read_eof_)) {
defer_on_read_completed_ = false;
HoldController(std::move(controller));
deferred_run_loop_->Quit();
return;
}
controller->Resume();
}
void TestResourceHandler::OnResponseCompleted(
const net::URLRequestStatus& status,
std::unique_ptr<ResourceController> controller) {
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
// These may be non-NULL if there was an out-of-band cancel.
parent_read_buffer_ = nullptr;
parent_read_buffer_size_ = nullptr;
EXPECT_EQ(0, on_response_completed_called_);
if (status.is_success() && expect_eof_read_)
EXPECT_EQ(1, on_read_eof_called_);
++on_response_completed_called_;
if (request_status_ptr_)
*request_status_ptr_ = status;
final_status_ = status;
// Consider response completed. Even if deferring, the TestResourceHandler
// won't be called again.
response_complete_run_loop_.Quit();
if (defer_on_response_completed_) {
defer_on_response_completed_ = false;
HoldController(std::move(controller));
deferred_run_loop_->Quit();
return;
}
controller->Resume();
}
void TestResourceHandler::Resume() {
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
if (parent_read_buffer_) {
*parent_read_buffer_ = buffer_;
*parent_read_buffer_size_ = buffer_size_;
parent_read_buffer_ = nullptr;
parent_read_buffer_size_ = nullptr;
memset(buffer_->data(), '\0', buffer_size_);
}
ResourceHandler::Resume();
}
void TestResourceHandler::CancelWithError(net::Error net_error) {
ScopedCallDepthTracker call_depth_tracker(&call_depth_);
canceled_ = true;
// Don't want to populate these after a cancel.
parent_read_buffer_ = nullptr;
parent_read_buffer_size_ = nullptr;
ResourceHandler::CancelWithError(net_error);
}
void TestResourceHandler::SetBufferSize(int buffer_size) {
buffer_ = base::MakeRefCounted<net::IOBuffer>(buffer_size);
buffer_size_ = buffer_size;
memset(buffer_->data(), '\0', buffer_size);
}
void TestResourceHandler::WaitUntilDeferred() {
deferred_run_loop_->Run();
deferred_run_loop_.reset(new base::RunLoop());
}
void TestResourceHandler::WaitUntilResponseStarted() {
response_started_run_loop_.Run();
}
void TestResourceHandler::WaitUntilResponseComplete() {
response_complete_run_loop_.Run();
}
base::WeakPtr<TestResourceHandler> TestResourceHandler::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace content