blob: ebf8ded148241237177581714d6ccc3f9113a9c3 [file] [log] [blame]
// Copyright 2018 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 <atomic>
#include <memory>
#include <tuple>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/task_environment.h"
#include "components/cronet/native/test/test_request_finished_info_listener.h"
#include "components/cronet/native/test/test_upload_data_provider.h"
#include "components/cronet/native/test/test_url_request_callback.h"
#include "components/cronet/native/test/test_util.h"
#include "components/cronet/test/test_server.h"
#include "cronet_c.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using cronet::test::TestRequestFinishedInfoListener;
using cronet::test::TestUploadDataProvider;
using cronet::test::TestUrlRequestCallback;
using ::testing::HasSubstr;
namespace {
// A Cronet_UrlRequestStatusListener impl that waits for OnStatus callback.
class StatusListener {
public:
// |callback| is verified to not yet have reached a final state when
// OnStatus() is called back.
explicit StatusListener(TestUrlRequestCallback* callback)
: status_listener_(Cronet_UrlRequestStatusListener_CreateWith(
StatusListener::OnStatus)),
callback_(callback),
expect_request_not_done_(false) {
Cronet_UrlRequestStatusListener_SetClientContext(status_listener_, this);
}
~StatusListener() {
Cronet_UrlRequestStatusListener_Destroy(status_listener_);
}
// Wait for and return request status.
Cronet_UrlRequestStatusListener_Status GetStatus(
Cronet_UrlRequestPtr request) {
Cronet_UrlRequest_GetStatus(request, status_listener_);
// NOTE(pauljensen): There's no guarantee this line will get executed
// before OnStatus() reads |expect_request_not_done_|. It's very unlikely
// it will get read before this write, but if it does it just means
// OnStatus() won't check that the final callback has not been issued yet.
expect_request_not_done_ = !Cronet_UrlRequest_IsDone(request);
awaiting_status_.Wait();
return status_;
}
private:
// Cronet_UrlRequestStatusListener OnStatus impl.
static void OnStatus(Cronet_UrlRequestStatusListenerPtr self,
Cronet_UrlRequestStatusListener_Status status) {
StatusListener* listener = static_cast<StatusListener*>(
Cronet_UrlRequestStatusListener_GetClientContext(self));
// Enforce we call OnStatus() before OnSucceeded/OnFailed/OnCanceled().
if (listener->expect_request_not_done_)
EXPECT_FALSE(listener->callback_->IsDone());
listener->status_ = status;
listener->awaiting_status_.Signal();
}
Cronet_UrlRequestStatusListenerPtr const status_listener_;
TestUrlRequestCallback* const callback_;
Cronet_UrlRequestStatusListener_Status status_ =
Cronet_UrlRequestStatusListener_Status_INVALID;
base::WaitableEvent awaiting_status_;
// Indicates if GetStatus() was called before request finished, indicating
// that OnStatus() should be called before request finishes. The writing of
// this variable races the reading of it, but it's initialized to a safe
// value.
std::atomic_bool expect_request_not_done_;
DISALLOW_COPY_AND_ASSIGN(StatusListener);
};
// Query and return status of |request|. |callback| is verified to not yet have
// reached a final state by the time OnStatus is called.
Cronet_UrlRequestStatusListener_Status GetRequestStatus(
Cronet_UrlRequestPtr request,
TestUrlRequestCallback* callback) {
return StatusListener(callback).GetStatus(request);
}
enum class RequestFinishedListenerType {
kNoListener, // Don't add a request finished listener.
kUrlRequestListener, // Add a request finished listener to the UrlRequest.
kEngineListener, // Add a request finished listener to the Engine.
};
// Converts a Cronet_DateTimePtr into the int64 number of milliseconds since
// the UNIX epoch.
//
// Returns -1 if |date_time| is nullptr.
int64_t DateToMillis(Cronet_DateTimePtr date_time) {
if (date_time == nullptr) {
return -1;
}
int64_t value = Cronet_DateTime_value_get(date_time);
// Cronet_DateTime fields shouldn't be before the UNIX epoch.
//
// While DateToMillis() callers can easily check this themselves (and
// produce more descriptive errors showing which field is violating), they
// can't easily distinguish a nullptr vs -1 value, so we check for -1 here.
EXPECT_NE(-1, value);
return value;
}
// Sanity check that the date isn't wildly off, somehow (perhaps due to read of
// used memory, wild pointer, etc.).
//
// Interpreted as milliseconds after the UNIX timestamp, this timestamp occurs
// at 37,648 C.E.
constexpr int64_t kDateOverrunThreshold = 1LL << 50;
// Basic sanity checking of all Cronet_Metrics fields. For optional fields, we
// allow the field to be non-present. Start/end pairs should be monotonic (end
// not less than start).
//
// Ordering of events is also checked.
void VerifyRequestMetrics(Cronet_MetricsPtr metrics) {
EXPECT_GE(DateToMillis(Cronet_Metrics_request_start_get(metrics)), 0);
EXPECT_LT(DateToMillis(Cronet_Metrics_request_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_request_end_get(metrics)),
DateToMillis(Cronet_Metrics_request_start_get(metrics)));
EXPECT_LT(DateToMillis(Cronet_Metrics_request_end_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_dns_start_get(metrics)), -1);
EXPECT_LT(DateToMillis(Cronet_Metrics_dns_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_dns_end_get(metrics)),
DateToMillis(Cronet_Metrics_dns_start_get(metrics)));
EXPECT_LT(DateToMillis(Cronet_Metrics_dns_end_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_connect_start_get(metrics)), -1);
EXPECT_LT(DateToMillis(Cronet_Metrics_connect_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_connect_end_get(metrics)),
DateToMillis(Cronet_Metrics_connect_start_get(metrics)));
EXPECT_LT(DateToMillis(Cronet_Metrics_connect_end_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_ssl_start_get(metrics)), -1);
EXPECT_LT(DateToMillis(Cronet_Metrics_ssl_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_ssl_end_get(metrics)),
DateToMillis(Cronet_Metrics_ssl_start_get(metrics)));
EXPECT_LT(DateToMillis(Cronet_Metrics_ssl_end_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_sending_start_get(metrics)), -1);
EXPECT_LT(DateToMillis(Cronet_Metrics_sending_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_sending_end_get(metrics)),
DateToMillis(Cronet_Metrics_sending_start_get(metrics)));
EXPECT_LT(DateToMillis(Cronet_Metrics_sending_end_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_push_start_get(metrics)), -1);
EXPECT_LT(DateToMillis(Cronet_Metrics_push_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_push_end_get(metrics)),
DateToMillis(Cronet_Metrics_push_start_get(metrics)));
EXPECT_LT(DateToMillis(Cronet_Metrics_push_end_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(DateToMillis(Cronet_Metrics_response_start_get(metrics)), -1);
EXPECT_LT(DateToMillis(Cronet_Metrics_response_start_get(metrics)),
kDateOverrunThreshold);
EXPECT_GE(Cronet_Metrics_sent_byte_count_get(metrics), -1);
EXPECT_GE(Cronet_Metrics_received_byte_count_get(metrics), -1);
// Verify order of events.
if (Cronet_Metrics_dns_start_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_dns_start_get(metrics)),
DateToMillis(Cronet_Metrics_request_start_get(metrics)));
}
if (Cronet_Metrics_connect_start_get(metrics) != nullptr &&
Cronet_Metrics_dns_end_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_connect_start_get(metrics)),
DateToMillis(Cronet_Metrics_dns_end_get(metrics)));
}
if (Cronet_Metrics_ssl_start_get(metrics) != nullptr &&
Cronet_Metrics_connect_start_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_ssl_start_get(metrics)),
DateToMillis(Cronet_Metrics_connect_start_get(metrics)));
}
if (Cronet_Metrics_connect_end_get(metrics) != nullptr &&
Cronet_Metrics_ssl_end_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_connect_end_get(metrics)),
DateToMillis(Cronet_Metrics_ssl_end_get(metrics)));
}
if (Cronet_Metrics_sending_start_get(metrics) != nullptr &&
Cronet_Metrics_connect_end_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_sending_start_get(metrics)),
DateToMillis(Cronet_Metrics_connect_end_get(metrics)));
}
if (Cronet_Metrics_response_start_get(metrics) != nullptr &&
Cronet_Metrics_sending_end_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_response_start_get(metrics)),
DateToMillis(Cronet_Metrics_sending_end_get(metrics)));
}
if (Cronet_Metrics_response_start_get(metrics) != nullptr) {
EXPECT_GE(DateToMillis(Cronet_Metrics_request_end_get(metrics)),
DateToMillis(Cronet_Metrics_response_start_get(metrics)));
}
}
// Convert a TestUrlRequestCallback::ResponseStep into the equivalent
// RequestFinishedInfo.FINISHED_REASON.
Cronet_RequestFinishedInfo_FINISHED_REASON MapFinishedReason(
TestUrlRequestCallback::ResponseStep response_step) {
switch (response_step) {
case TestUrlRequestCallback::ON_SUCCEEDED:
return Cronet_RequestFinishedInfo_FINISHED_REASON_SUCCEEDED;
case TestUrlRequestCallback::ON_FAILED:
return Cronet_RequestFinishedInfo_FINISHED_REASON_FAILED;
case TestUrlRequestCallback::ON_CANCELED:
return Cronet_RequestFinishedInfo_FINISHED_REASON_CANCELED;
default:
CHECK(false) << "Unknown TestUrlRequestCallback::ResponseStep: "
<< response_step;
return Cronet_RequestFinishedInfo_FINISHED_REASON_FAILED;
}
}
// Basic sanity checking of all Cronet_RequestFinishedInfo,
// Cronet_UrlResponseInfoPtr, and Cronet_ErrorPtr fields passed to
// RequestFinishedInfoListener.OnRequestFinished().
//
// All fields are checked except for |annotations|.
//
// |test_request_finished_info_listener| Test listener -- will verify all fields
// of this listener.
// |callback| Callback associated with the UrlRequest associated with
// |request_info|.
void VerifyRequestFinishedInfoListener(
TestRequestFinishedInfoListener* test_request_finished_info_listener,
const TestUrlRequestCallback& callback) {
Cronet_RequestFinishedInfoPtr request_info =
test_request_finished_info_listener->request_finished_info();
VerifyRequestMetrics(Cronet_RequestFinishedInfo_metrics_get(request_info));
auto finished_reason =
Cronet_RequestFinishedInfo_finished_reason_get(request_info);
EXPECT_EQ(MapFinishedReason(callback.response_step_), finished_reason);
EXPECT_EQ(callback.original_response_info_,
test_request_finished_info_listener->url_response_info());
EXPECT_EQ(callback.last_error_, test_request_finished_info_listener->error());
}
// Parameterized off whether to use a direct executor, and whether (if so, how)
// to add a RequestFinishedInfoListener.
class UrlRequestTest : public ::testing::TestWithParam<
std::tuple<bool, RequestFinishedListenerType>> {
protected:
UrlRequestTest() {}
~UrlRequestTest() override {}
void SetUp() override { EXPECT_TRUE(cronet::TestServer::Start()); }
void TearDown() override { cronet::TestServer::Shutdown(); }
bool GetDirectExecutorParam() { return std::get<0>(GetParam()); }
RequestFinishedListenerType GetRequestFinishedListenerTypeParam() {
return std::get<1>(GetParam());
}
std::unique_ptr<TestUrlRequestCallback> StartAndWaitForComplete(
const std::string& url,
std::unique_ptr<TestUrlRequestCallback> test_callback,
const std::string& http_method,
TestUploadDataProvider* test_upload_data_provider,
int remapped_port) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(remapped_port);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params =
Cronet_UrlRequestParams_Create();
Cronet_UrlRequestParams_http_method_set(request_params,
http_method.c_str());
Cronet_UploadDataProviderPtr upload_data_provider = nullptr;
// Add upload data provider and set content type required for upload.
if (test_upload_data_provider != nullptr) {
test_upload_data_provider->set_url_request(request);
upload_data_provider =
test_upload_data_provider->CreateUploadDataProvider();
Cronet_UrlRequestParams_upload_data_provider_set(request_params,
upload_data_provider);
Cronet_UrlRequestParams_upload_data_provider_executor_set(
request_params, test_upload_data_provider->executor());
Cronet_HttpHeaderPtr header = Cronet_HttpHeader_Create();
Cronet_HttpHeader_name_set(header, "Content-Type");
Cronet_HttpHeader_value_set(header, "Useless/string");
Cronet_UrlRequestParams_request_headers_add(request_params, header);
Cronet_HttpHeader_Destroy(header);
}
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback->GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback->CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor);
Cronet_UrlRequest_Start(request);
test_callback->WaitForDone();
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
*test_callback);
CleanupRequestFinishedListener(request_params, engine);
// Wait for all posted tasks to be executed to ensure there is no unhandled
// exception.
test_callback->ShutdownExecutor();
EXPECT_TRUE(test_callback->IsDone());
EXPECT_TRUE(Cronet_UrlRequest_IsDone(request));
if (upload_data_provider != nullptr)
Cronet_UploadDataProvider_Destroy(upload_data_provider);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
return test_callback;
}
std::unique_ptr<TestUrlRequestCallback> StartAndWaitForComplete(
const std::string& url,
std::unique_ptr<TestUrlRequestCallback> test_callback,
const std::string& http_method,
TestUploadDataProvider* test_upload_data_provider) {
return StartAndWaitForComplete(url, std::move(test_callback), http_method,
test_upload_data_provider,
/* remapped_port = */ 0);
}
std::unique_ptr<TestUrlRequestCallback> StartAndWaitForComplete(
const std::string& url,
std::unique_ptr<TestUrlRequestCallback> test_callback) {
return StartAndWaitForComplete(url, std::move(test_callback),
/* http_method = */ std::string(),
/* upload_data_provider = */ nullptr);
}
std::unique_ptr<TestUrlRequestCallback> StartAndWaitForComplete(
const std::string& url) {
return StartAndWaitForComplete(
url,
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam()));
}
void CheckResponseInfo(
const TestUrlRequestCallback::UrlResponseInfo& response_info,
const std::string& expected_url,
int expected_http_status_code,
const std::string& expected_http_status_text) {
EXPECT_EQ(expected_url, response_info.url);
EXPECT_EQ(expected_url, response_info.url_chain.back());
EXPECT_EQ(expected_http_status_code, response_info.http_status_code);
EXPECT_EQ(expected_http_status_text, response_info.http_status_text);
EXPECT_FALSE(response_info.was_cached);
}
void ExpectResponseInfoEquals(
const TestUrlRequestCallback::UrlResponseInfo& expected,
const TestUrlRequestCallback::UrlResponseInfo& actual) {
EXPECT_EQ(expected.url, actual.url);
EXPECT_EQ(expected.url_chain, actual.url_chain);
EXPECT_EQ(expected.http_status_code, actual.http_status_code);
EXPECT_EQ(expected.http_status_text, actual.http_status_text);
EXPECT_EQ(expected.all_headers, actual.all_headers);
EXPECT_EQ(expected.was_cached, actual.was_cached);
EXPECT_EQ(expected.negotiated_protocol, actual.negotiated_protocol);
EXPECT_EQ(expected.proxy_server, actual.proxy_server);
EXPECT_EQ(expected.received_byte_count, actual.received_byte_count);
}
// Depending on the test parameterization, adds a RequestFinishedInfoListener
// to the Engine or UrlRequest, or does nothing.
//
// This method should be called before the call to
// Cronet_UrlRequest_InitWithParams().
void MaybeAddRequestFinishedListener(
Cronet_UrlRequestParamsPtr url_request_params,
Cronet_EnginePtr engine,
Cronet_ExecutorPtr executor,
TestRequestFinishedInfoListener* test_request_finished_info_listener) {
auto request_finished_listener_type = GetRequestFinishedListenerTypeParam();
if (request_finished_listener_type ==
RequestFinishedListenerType::kNoListener)
return;
request_finished_listener_ =
test_request_finished_info_listener->CreateRequestFinishedListener();
switch (request_finished_listener_type) {
case RequestFinishedListenerType::kUrlRequestListener:
Cronet_UrlRequestParams_request_finished_listener_set(
url_request_params, request_finished_listener_);
Cronet_UrlRequestParams_request_finished_executor_set(
url_request_params, executor);
break;
case RequestFinishedListenerType::kEngineListener:
Cronet_Engine_AddRequestFinishedListener(
engine, request_finished_listener_, executor);
break;
default:
NOTREACHED();
}
}
// Cleans up any leftover resources from MaybeAddRequestFinishedListener().
//
// NOTE: It's only necessary to call this method if
// MaybeAddRequestFinishedListener() is called multiple times in a test case
// (like in a loop).
void CleanupRequestFinishedListener(
Cronet_UrlRequestParamsPtr url_request_params,
Cronet_EnginePtr engine) {
auto request_finished_listener_type = GetRequestFinishedListenerTypeParam();
if (request_finished_listener_type ==
RequestFinishedListenerType::kEngineListener) {
Cronet_Engine_RemoveRequestFinishedListener(engine,
request_finished_listener_);
}
Cronet_UrlRequestParams_request_finished_listener_set(url_request_params,
nullptr);
Cronet_UrlRequestParams_request_finished_executor_set(url_request_params,
nullptr);
}
// TestRequestFinishedInfoListener.WaitForDone() is called and checks are
// performed only if a RequestFinishedInfoListener is registered.
//
// This method should be called after TestUrlRequestCallback.WaitForDone().
void MaybeVerifyRequestFinishedInfo(
TestRequestFinishedInfoListener* test_request_finished_info_listener,
const TestUrlRequestCallback& callback) {
if (GetRequestFinishedListenerTypeParam() ==
RequestFinishedListenerType::kNoListener)
return;
test_request_finished_info_listener->WaitForDone();
VerifyRequestFinishedInfoListener(test_request_finished_info_listener,
callback);
}
void TestCancel(TestUrlRequestCallback::FailureType failure_type,
TestUrlRequestCallback::ResponseStep failure_step,
bool expect_response_info,
bool expect_error);
protected:
// Provide a task environment for use by TestExecutor instances. Do not
// initialize the ThreadPool as this is done by the Cronet_Engine
base::test::SingleThreadTaskEnvironment task_environment_;
// Not owned, |request_finished_listener_| destroys itself when run. This
// pointer is only needed to unregister the listener from the Engine in
// CleanupRequestFinishedListener() and to allow tests that never run the
// |request_finished_listener_| to be able to destroy it.
Cronet_RequestFinishedInfoListenerPtr request_finished_listener_ = nullptr;
private:
DISALLOW_COPY_AND_ASSIGN(UrlRequestTest);
};
const bool kDirectExecutorEnabled[]{true, false};
INSTANTIATE_TEST_SUITE_P(
NoRequestFinishedListener,
UrlRequestTest,
testing::Combine(
testing::ValuesIn(kDirectExecutorEnabled),
testing::Values(RequestFinishedListenerType::kNoListener)));
INSTANTIATE_TEST_SUITE_P(
RequestFinishedListenerOnUrlRequest,
UrlRequestTest,
testing::Combine(
testing::ValuesIn(kDirectExecutorEnabled),
testing::Values(RequestFinishedListenerType::kUrlRequestListener)));
INSTANTIATE_TEST_SUITE_P(
RequestFinishedListenerOnEngine,
UrlRequestTest,
testing::Combine(
testing::ValuesIn(kDirectExecutorEnabled),
testing::Values(RequestFinishedListenerType::kEngineListener)));
TEST_P(UrlRequestTest, InitChecks) {
Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
Cronet_EnginePtr engine = Cronet_Engine_Create();
// Disable runtime CHECK of the result, so it could be verified.
Cronet_EngineParams_enable_check_result_set(engine_params, false);
EXPECT_EQ(Cronet_RESULT_SUCCESS,
Cronet_Engine_StartWithParams(engine, engine_params));
Cronet_EngineParams_Destroy(engine_params);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
const std::string url = cronet::TestServer::GetEchoMethodURL();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
EXPECT_EQ(Cronet_RESULT_NULL_POINTER_URL,
Cronet_UrlRequest_InitWithParams(
request, engine, /* url = */ nullptr,
/* request_params = */ nullptr, /* callback = */ nullptr,
/* executor = */ nullptr));
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
EXPECT_EQ(Cronet_RESULT_NULL_POINTER_PARAMS,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
/* request_params = */ nullptr,
/* callback = */ nullptr,
/* executor = */ nullptr));
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
EXPECT_EQ(Cronet_RESULT_NULL_POINTER_CALLBACK,
Cronet_UrlRequest_InitWithParams(
request, engine, url.c_str(), request_params,
/* callback = */ nullptr, /* executor = */ nullptr));
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
EXPECT_EQ(Cronet_RESULT_NULL_POINTER_EXECUTOR,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback,
/* executor = */ nullptr));
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
EXPECT_EQ(Cronet_RESULT_NULL_POINTER_EXECUTOR,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback,
/* executor = */ nullptr));
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParams_http_method_set(request_params, "bad:method");
EXPECT_EQ(
Cronet_RESULT_ILLEGAL_ARGUMENT_INVALID_HTTP_METHOD,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor));
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParams_http_method_set(request_params, "HEAD");
Cronet_UrlRequestParams_priority_set(
request_params,
Cronet_UrlRequestParams_REQUEST_PRIORITY_REQUEST_PRIORITY_IDLE);
// Check header validation
Cronet_HttpHeaderPtr http_header = Cronet_HttpHeader_Create();
Cronet_UrlRequestParams_request_headers_add(request_params, http_header);
EXPECT_EQ(
Cronet_RESULT_NULL_POINTER_HEADER_NAME,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor));
Cronet_UrlRequestParams_request_headers_clear(request_params);
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParams_priority_set(
request_params,
Cronet_UrlRequestParams_REQUEST_PRIORITY_REQUEST_PRIORITY_LOWEST);
Cronet_HttpHeader_name_set(http_header, "bad:name");
Cronet_UrlRequestParams_request_headers_add(request_params, http_header);
EXPECT_EQ(
Cronet_RESULT_NULL_POINTER_HEADER_VALUE,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor));
Cronet_UrlRequestParams_request_headers_clear(request_params);
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParams_priority_set(
request_params,
Cronet_UrlRequestParams_REQUEST_PRIORITY_REQUEST_PRIORITY_LOW);
Cronet_HttpHeader_value_set(http_header, "header value");
Cronet_UrlRequestParams_request_headers_add(request_params, http_header);
EXPECT_EQ(
Cronet_RESULT_ILLEGAL_ARGUMENT_INVALID_HTTP_HEADER,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor));
Cronet_UrlRequestParams_request_headers_clear(request_params);
Cronet_UrlRequest_Destroy(request);
request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParams_priority_set(
request_params,
Cronet_UrlRequestParams_REQUEST_PRIORITY_REQUEST_PRIORITY_HIGHEST);
Cronet_HttpHeader_name_set(http_header, "header-name");
Cronet_UrlRequestParams_request_headers_add(request_params, http_header);
EXPECT_EQ(Cronet_RESULT_SUCCESS, Cronet_UrlRequest_InitWithParams(
request, engine, url.c_str(),
request_params, callback, executor));
EXPECT_EQ(
Cronet_RESULT_ILLEGAL_STATE_REQUEST_ALREADY_INITIALIZED,
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor));
Cronet_HttpHeader_Destroy(http_header);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
if (request_finished_listener_ != nullptr) {
// This test never actually runs |request_finished_listener_|, so we delete
// it here.
Cronet_RequestFinishedInfoListener_Destroy(request_finished_listener_);
}
}
TEST_P(UrlRequestTest, SimpleGet) {
const std::string url = cronet::TestServer::GetEchoMethodURL();
auto callback = StartAndWaitForComplete(url);
EXPECT_EQ(200, callback->response_info_->http_status_code);
// Default method is 'GET'.
EXPECT_EQ("GET", callback->response_as_string_);
EXPECT_EQ(0, callback->redirect_count_);
EXPECT_EQ(callback->response_step_, callback->ON_SUCCEEDED);
CheckResponseInfo(*callback->response_info_, url, 200, "OK");
TestUrlRequestCallback::UrlResponseInfo expected_response_info(
std::vector<std::string>({url}), "OK", 200, 86,
std::vector<std::string>({"Connection", "close", "Content-Length", "3",
"Content-Type", "text/plain"}));
ExpectResponseInfoEquals(expected_response_info, *callback->response_info_);
}
TEST_P(UrlRequestTest, UploadEmptyBodySync) {
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(0, data_provider.GetUploadedLength());
EXPECT_EQ(0, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadSync) {
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
data_provider.AddRead("Test");
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Test", callback->response_as_string_);
}
TEST_P(UrlRequestTest, SSLCertificateError) {
net::EmbeddedTestServer ssl_server(net::EmbeddedTestServer::TYPE_HTTPS);
ssl_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
ASSERT_TRUE(ssl_server.Start());
const std::string url = ssl_server.GetURL("/").spec();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
data_provider.AddRead("Test");
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(0, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(nullptr, callback->response_info_);
EXPECT_EQ("", callback->response_as_string_);
EXPECT_EQ("net::ERR_CERT_INVALID", callback->last_error_message_);
}
TEST_P(UrlRequestTest, SSLUpload) {
net::EmbeddedTestServer ssl_server(net::EmbeddedTestServer::TYPE_HTTPS);
net::test_server::RegisterDefaultHandlers(&ssl_server);
ASSERT_TRUE(ssl_server.Start());
constexpr char kUrl[] = "https://test.example.com/echoall";
constexpr char kUploadString[] =
"The quick brown fox jumps over the lazy dog.";
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
data_provider.AddRead(kUploadString);
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(kUrl, std::move(callback), std::string(),
&data_provider, ssl_server.port());
data_provider.AssertClosed();
EXPECT_NE(nullptr, callback->response_info_);
EXPECT_EQ("", callback->last_error_message_);
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_THAT(callback->response_as_string_, HasSubstr(kUploadString));
}
TEST_P(UrlRequestTest, UploadMultiplePiecesSync) {
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.AddRead("Y");
data_provider.AddRead("et ");
data_provider.AddRead("another ");
data_provider.AddRead("test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(16, data_provider.GetUploadedLength());
EXPECT_EQ(4, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Yet another test", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadMultiplePiecesAsync) {
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
TestUploadDataProvider data_provider(TestUploadDataProvider::ASYNC,
callback->GetExecutor());
data_provider.AddRead("Y");
data_provider.AddRead("et ");
data_provider.AddRead("another ");
data_provider.AddRead("test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(16, data_provider.GetUploadedLength());
EXPECT_EQ(4, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Yet another test", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadChangesDefaultMethod) {
const std::string url = cronet::TestServer::GetEchoMethodURL();
TestUploadDataProvider upload_data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
upload_data_provider.AddRead("Test");
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&upload_data_provider);
EXPECT_EQ(200, callback->response_info_->http_status_code);
// Setting upload provider should change method to 'POST'.
EXPECT_EQ("POST", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadWithSetMethod) {
const std::string url = cronet::TestServer::GetEchoMethodURL();
TestUploadDataProvider upload_data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
upload_data_provider.AddRead("Test");
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback),
std::string("PUT"), &upload_data_provider);
EXPECT_EQ(200, callback->response_info_->http_status_code);
// Setting upload provider should change method to 'POST'.
EXPECT_EQ("PUT", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadWithBigRead) {
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider upload_data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
// Use reads that match exact size of read buffer, which is 16384 bytes.
upload_data_provider.AddRead(std::string(16384, 'a'));
upload_data_provider.AddRead(std::string(32768 - 16384, 'a'));
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback),
std::string("PUT"), &upload_data_provider);
EXPECT_EQ(200, callback->response_info_->http_status_code);
// Confirm that body is uploaded correctly.
EXPECT_EQ(std::string(32768, 'a'), callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadWithDirectExecutor) {
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
auto callback = std::make_unique<TestUrlRequestCallback>(true);
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Test", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadRedirectSync) {
const std::string url = cronet::TestServer::GetRedirectToEchoBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
data_provider.AddRead("Test");
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(2, data_provider.num_read_calls());
EXPECT_EQ(1, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Test", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadRedirectAsync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetRedirectToEchoBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::ASYNC,
callback->GetExecutor());
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(2, data_provider.num_read_calls());
EXPECT_EQ(1, data_provider.num_rewind_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Test", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadWithBadLength) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.set_bad_length(1ll);
data_provider.AddRead("12");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(2, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(nullptr, callback->response_info_);
EXPECT_NE(nullptr, callback->last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_CALLBACK, callback->last_error_code_);
EXPECT_EQ(0ul, callback->last_error_message_.find(
"Failure from UploadDataProvider"));
EXPECT_NE(std::string::npos,
callback->last_error_message_.find(
"Read upload data length 2 exceeds expected length 1"));
}
TEST_P(UrlRequestTest, UploadWithBadLengthBufferAligned) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.set_bad_length(8191ll);
// Add 8192 bytes to read.
for (int i = 0; i < 512; ++i)
data_provider.AddRead("0123456789abcdef");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(8192, data_provider.GetUploadedLength());
EXPECT_EQ(512, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(nullptr, callback->response_info_);
EXPECT_NE(nullptr, callback->last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_CALLBACK, callback->last_error_code_);
EXPECT_EQ(0ul, callback->last_error_message_.find(
"Failure from UploadDataProvider"));
EXPECT_NE(std::string::npos,
callback->last_error_message_.find(
"Read upload data length 8192 exceeds expected length 8191"));
}
TEST_P(UrlRequestTest, UploadReadFailSync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.SetReadFailure(0, TestUploadDataProvider::CALLBACK_SYNC);
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(nullptr, callback->response_info_);
EXPECT_NE(nullptr, callback->last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_CALLBACK, callback->last_error_code_);
EXPECT_EQ(0ul, callback->last_error_message_.find(
"Failure from UploadDataProvider"));
EXPECT_NE(std::string::npos,
callback->last_error_message_.find("Sync read failure"));
}
TEST_P(UrlRequestTest, UploadReadFailAsync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.SetReadFailure(0, TestUploadDataProvider::CALLBACK_ASYNC);
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(nullptr, callback->response_info_);
EXPECT_NE(nullptr, callback->last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_CALLBACK, callback->last_error_code_);
EXPECT_EQ(0ul, callback->last_error_message_.find(
"Failure from UploadDataProvider"));
EXPECT_NE(std::string::npos,
callback->last_error_message_.find("Async read failure"));
}
TEST_P(UrlRequestTest, UploadRewindFailSync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetRedirectToEchoBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.SetRewindFailure(TestUploadDataProvider::CALLBACK_SYNC);
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(1, data_provider.num_rewind_calls());
EXPECT_NE(nullptr, callback->last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_CALLBACK, callback->last_error_code_);
EXPECT_EQ(0ul, callback->last_error_message_.find(
"Failure from UploadDataProvider"));
EXPECT_NE(std::string::npos,
callback->last_error_message_.find("Sync rewind failure"));
}
TEST_P(UrlRequestTest, UploadRewindFailAsync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetRedirectToEchoBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.SetRewindFailure(TestUploadDataProvider::CALLBACK_ASYNC);
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(1, data_provider.num_rewind_calls());
EXPECT_NE(nullptr, callback->last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_CALLBACK, callback->last_error_code_);
EXPECT_EQ(0ul, callback->last_error_message_.find(
"Failure from UploadDataProvider"));
EXPECT_NE(std::string::npos,
callback->last_error_message_.find("Async rewind failure"));
}
TEST_P(UrlRequestTest, UploadChunked) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
data_provider.AddRead("Test Hello");
data_provider.set_chunked(true);
EXPECT_EQ(-1, data_provider.GetLength());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(-1, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("Test Hello", callback->response_as_string_);
}
TEST_P(UrlRequestTest, UploadChunkedLastReadZeroLengthBody) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
callback->GetExecutor());
// Add 3 reads. The last read has a 0-length body.
data_provider.AddRead("hello there");
data_provider.AddRead("!");
data_provider.AddRead("");
data_provider.set_chunked(true);
EXPECT_EQ(-1, data_provider.GetLength());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(-1, data_provider.GetUploadedLength());
// 2 read call for the first two data chunks, and 1 for final chunk.
EXPECT_EQ(3, data_provider.num_read_calls());
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ("hello there!", callback->response_as_string_);
}
// Test where an upload fails without ever initializing the
// UploadDataStream, because it can't connect to the server.
TEST_P(UrlRequestTest, UploadFailsWithoutInitializingStream) {
// The port for PTP will always refuse a TCP connection
const std::string url = "http://127.0.0.1:319";
TestUploadDataProvider data_provider(TestUploadDataProvider::SYNC,
/* executor = */ nullptr);
data_provider.AddRead("Test");
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(0, data_provider.num_read_calls());
EXPECT_EQ(0, data_provider.num_rewind_calls());
EXPECT_EQ(nullptr, callback->response_info_);
EXPECT_EQ("", callback->response_as_string_);
EXPECT_TRUE(callback->on_error_called_);
}
// TODO(https://crbug.com/954372): Flakes in AssertClosed().
TEST_P(UrlRequestTest, DISABLED_UploadCancelReadSync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::ASYNC,
callback->GetExecutor());
data_provider.AddRead("One");
data_provider.AddRead("Two");
data_provider.AddRead("Three");
data_provider.SetReadCancel(1, TestUploadDataProvider::CANCEL_SYNC);
data_provider.SetReadFailure(1, TestUploadDataProvider::CALLBACK_ASYNC);
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(11, data_provider.GetUploadedLength());
EXPECT_EQ(2, data_provider.num_read_calls());
EXPECT_TRUE(callback->on_canceled_called_);
}
TEST_P(UrlRequestTest, UploadCancelReadAsync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetEchoRequestBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::ASYNC,
callback->GetExecutor());
data_provider.AddRead("One");
data_provider.AddRead("Two");
data_provider.AddRead("Three");
data_provider.SetReadCancel(2, TestUploadDataProvider::CANCEL_ASYNC);
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(11, data_provider.GetUploadedLength());
EXPECT_EQ(3, data_provider.num_read_calls());
EXPECT_TRUE(callback->on_canceled_called_);
}
// TODO(https://crbug.com/954372): Flakes in AssertClosed().
TEST_P(UrlRequestTest, DISABLED_UploadCancelRewindSync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetRedirectToEchoBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::ASYNC,
callback->GetExecutor());
data_provider.SetRewindCancel(TestUploadDataProvider::CANCEL_SYNC);
data_provider.SetRewindFailure(TestUploadDataProvider::CALLBACK_ASYNC);
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(1, data_provider.num_rewind_calls());
EXPECT_TRUE(callback->on_canceled_called_);
}
TEST_P(UrlRequestTest, UploadCancelRewindAsync) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
const std::string url = cronet::TestServer::GetRedirectToEchoBodyURL();
TestUploadDataProvider data_provider(TestUploadDataProvider::ASYNC,
callback->GetExecutor());
data_provider.SetRewindCancel(TestUploadDataProvider::CANCEL_ASYNC);
data_provider.AddRead("Test");
callback = StartAndWaitForComplete(url, std::move(callback), std::string(),
&data_provider);
data_provider.AssertClosed();
EXPECT_EQ(4, data_provider.GetUploadedLength());
EXPECT_EQ(1, data_provider.num_read_calls());
EXPECT_EQ(1, data_provider.num_rewind_calls());
EXPECT_TRUE(callback->on_canceled_called_);
}
TEST_P(UrlRequestTest, SimpleRequest) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
test_callback.WaitForDone();
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
test_callback);
EXPECT_TRUE(test_callback.IsDone());
ASSERT_EQ("The quick brown fox jumps over the lazy dog.",
test_callback.response_as_string_);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_P(UrlRequestTest, ReceiveBackAnnotations) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
int object_to_annotate = 0;
Cronet_UrlRequestParams_annotations_add(request_params, &object_to_annotate);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
test_callback.WaitForDone();
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
test_callback);
EXPECT_TRUE(test_callback.IsDone());
if (GetRequestFinishedListenerTypeParam() !=
RequestFinishedListenerType::kNoListener) {
ASSERT_EQ(1u,
Cronet_RequestFinishedInfo_annotations_size(
test_request_finished_info_listener.request_finished_info()));
EXPECT_EQ(
&object_to_annotate,
Cronet_RequestFinishedInfo_annotations_at(
test_request_finished_info_listener.request_finished_info(), 0));
}
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_P(UrlRequestTest, UrlParamsAnnotationsUnchanged) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
int object_to_annotate = 0;
Cronet_UrlRequestParams_annotations_add(request_params, &object_to_annotate);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
ASSERT_EQ(1u, Cronet_UrlRequestParams_annotations_size(request_params));
EXPECT_EQ(&object_to_annotate,
Cronet_UrlRequestParams_annotations_at(request_params, 0));
EXPECT_EQ(0, object_to_annotate);
if (request_finished_listener_ != nullptr) {
// This test never actually runs |request_finished_listener_|, so we delete
// it here.
Cronet_RequestFinishedInfoListener_Destroy(request_finished_listener_);
}
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_P(UrlRequestTest, MultiRedirect) {
const std::string url = cronet::TestServer::GetMultiRedirectURL();
auto callback = StartAndWaitForComplete(url);
EXPECT_EQ(2, callback->redirect_count_);
EXPECT_EQ(200, callback->response_info_->http_status_code);
EXPECT_EQ(2ul, callback->redirect_response_info_list_.size());
EXPECT_EQ(2ul, callback->redirect_url_list_.size());
// Check first redirect (multiredirect.html -> redirect.html).
TestUrlRequestCallback::UrlResponseInfo first_expected_response_info(
std::vector<std::string>({url}), "Found", 302, 76,
std::vector<std::string>(
{"Location", GURL(cronet::TestServer::GetRedirectURL()).path(),
"redirect-header0", "header-value"}));
ExpectResponseInfoEquals(first_expected_response_info,
*callback->redirect_response_info_list_.front());
EXPECT_EQ(cronet::TestServer::GetRedirectURL(),
callback->redirect_url_list_.front());
// Check second redirect (redirect.html -> success.txt).
TestUrlRequestCallback::UrlResponseInfo second_expected_response_info(
std::vector<std::string>({cronet::TestServer::GetMultiRedirectURL(),
cronet::TestServer::GetRedirectURL()}),
"Found", 302, 149,
std::vector<std::string>(
{"Location", GURL(cronet::TestServer::GetSuccessURL()).path(),
"redirect-header", "header-value"}));
ExpectResponseInfoEquals(second_expected_response_info,
*callback->redirect_response_info_list_.back());
EXPECT_EQ(cronet::TestServer::GetSuccessURL(),
callback->redirect_url_list_.back());
// Check final response (success.txt).
TestUrlRequestCallback::UrlResponseInfo final_expected_response_info(
std::vector<std::string>({cronet::TestServer::GetMultiRedirectURL(),
cronet::TestServer::GetRedirectURL(),
cronet::TestServer::GetSuccessURL()}),
"OK", 200, 334,
std::vector<std::string>(
{"Content-Type", "text/plain", "Access-Control-Allow-Origin", "*",
"header-name", "header-value", "multi-header-name", "header-value1",
"multi-header-name", "header-value2"}));
ExpectResponseInfoEquals(final_expected_response_info,
*callback->response_info_);
EXPECT_NE(0, callback->response_data_length_);
EXPECT_EQ(callback->ON_SUCCEEDED, callback->response_step_);
}
TEST_P(UrlRequestTest, CancelRequest) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
test_callback.set_failure(test_callback.CANCEL_SYNC,
test_callback.ON_RESPONSE_STARTED);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
test_callback.WaitForDone();
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
test_callback);
EXPECT_TRUE(test_callback.IsDone());
EXPECT_TRUE(test_callback.on_canceled_called_);
ASSERT_FALSE(test_callback.on_error_called_);
EXPECT_TRUE(test_callback.response_as_string_.empty());
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_P(UrlRequestTest, FailedRequestHostNotFound) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = "https://notfound.example.com";
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
test_callback.WaitForDone();
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
test_callback);
EXPECT_TRUE(test_callback.IsDone());
EXPECT_TRUE(test_callback.on_error_called_);
EXPECT_FALSE(test_callback.on_canceled_called_);
EXPECT_TRUE(test_callback.response_as_string_.empty());
EXPECT_EQ(nullptr, test_callback.response_info_);
EXPECT_NE(nullptr, test_callback.last_error_);
EXPECT_EQ(Cronet_Error_ERROR_CODE_ERROR_HOSTNAME_NOT_RESOLVED,
Cronet_Error_error_code_get(test_callback.last_error_));
EXPECT_FALSE(
Cronet_Error_immediately_retryable_get(test_callback.last_error_));
EXPECT_STREQ("net::ERR_NAME_NOT_RESOLVED",
Cronet_Error_message_get(test_callback.last_error_));
EXPECT_EQ(-105,
Cronet_Error_internal_error_code_get(test_callback.last_error_));
EXPECT_EQ(
0, Cronet_Error_quic_detailed_error_code_get(test_callback.last_error_));
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
void UrlRequestTest::TestCancel(
TestUrlRequestCallback::FailureType failure_type,
TestUrlRequestCallback::ResponseStep failure_step,
bool expect_response_info,
bool expect_error) {
auto callback =
std::make_unique<TestUrlRequestCallback>(GetDirectExecutorParam());
callback->set_failure(failure_type, failure_step);
const std::string url = cronet::TestServer::GetRedirectURL();
callback = StartAndWaitForComplete(url, std::move(callback));
EXPECT_EQ(1, callback->redirect_count_);
EXPECT_EQ(1ul, callback->redirect_response_info_list_.size());
if (failure_type == TestUrlRequestCallback::CANCEL_SYNC ||
failure_type == TestUrlRequestCallback::CANCEL_ASYNC) {
EXPECT_EQ(TestUrlRequestCallback::ON_CANCELED, callback->response_step_);
}
EXPECT_EQ(expect_response_info, callback->response_info_ != nullptr);
EXPECT_EQ(expect_error, callback->last_error_ != nullptr);
EXPECT_EQ(expect_error, callback->on_error_called_);
// When |failure_type| is CANCEL_ASYNC_WITHOUT_PAUSE and |failure_step|
// is ON_READ_COMPLETED, there might be an onSucceeded() task
// already posted. If that's the case, onCanceled() will not be invoked. See
// crbug.com/657415.
if (!(failure_type == TestUrlRequestCallback::CANCEL_ASYNC_WITHOUT_PAUSE &&
failure_step == TestUrlRequestCallback::ON_READ_COMPLETED)) {
EXPECT_TRUE(callback->on_canceled_called_);
}
}
TEST_P(UrlRequestTest, TestCancel) {
TestCancel(TestUrlRequestCallback::CANCEL_SYNC,
TestUrlRequestCallback::ON_RECEIVED_REDIRECT, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_ASYNC,
TestUrlRequestCallback::ON_RECEIVED_REDIRECT, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_ASYNC_WITHOUT_PAUSE,
TestUrlRequestCallback::ON_RECEIVED_REDIRECT, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_SYNC,
TestUrlRequestCallback::ON_RESPONSE_STARTED, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_ASYNC,
TestUrlRequestCallback::ON_RESPONSE_STARTED, true, false);
// https://crbug.com/812334 - If request is canceled asynchronously, the
// 'OnReadCompleted' callback may arrive AFTER 'OnCanceled'.
TestCancel(TestUrlRequestCallback::CANCEL_ASYNC_WITHOUT_PAUSE,
TestUrlRequestCallback::ON_RESPONSE_STARTED, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_SYNC,
TestUrlRequestCallback::ON_READ_COMPLETED, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_ASYNC,
TestUrlRequestCallback::ON_READ_COMPLETED, true, false);
TestCancel(TestUrlRequestCallback::CANCEL_ASYNC_WITHOUT_PAUSE,
TestUrlRequestCallback::ON_READ_COMPLETED, true, false);
}
TEST_P(UrlRequestTest, PerfTest) {
const int kTestIterations = 10;
const int kDownloadSize = 19307439; // used for internal server only
Cronet_EnginePtr engine = Cronet_Engine_Create();
Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
Cronet_Engine_StartWithParams(engine, engine_params);
std::string url = cronet::TestServer::PrepareBigDataURL(kDownloadSize);
base::Time start = base::Time::Now();
for (int i = 0; i < kTestIterations; ++i) {
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params =
Cronet_UrlRequestParams_Create();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
test_callback.set_accumulate_response_data(false);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(),
request_params, callback, executor);
Cronet_UrlRequest_Start(request);
test_callback.WaitForDone();
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
test_callback);
EXPECT_TRUE(test_callback.IsDone());
ASSERT_EQ(kDownloadSize, test_callback.response_data_length_);
CleanupRequestFinishedListener(request_params, engine);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
}
base::Time end = base::Time::Now();
base::TimeDelta delta = end - start;
LOG(INFO) << "Total time " << delta.InMillisecondsF() << " ms";
LOG(INFO) << "Single Iteration time "
<< delta.InMillisecondsF() / kTestIterations << " ms";
double bytes_per_ms =
kDownloadSize * kTestIterations / delta.InMillisecondsF();
double megabytes_per_ms = bytes_per_ms / 1000000;
double megabits_per_second = megabytes_per_ms * 8 * 1000;
LOG(INFO) << "Average Throughput: " << megabits_per_second << " mbps";
Cronet_EngineParams_Destroy(engine_params);
Cronet_Engine_Destroy(engine);
cronet::TestServer::ReleaseBigDataURL();
}
TEST_P(UrlRequestTest, GetStatus) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
TestUrlRequestCallback test_callback(GetDirectExecutorParam());
test_callback.set_auto_advance(false);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
TestRequestFinishedInfoListener test_request_finished_info_listener;
MaybeAddRequestFinishedListener(request_params, engine, executor,
&test_request_finished_info_listener);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
EXPECT_EQ(Cronet_UrlRequestStatusListener_Status_INVALID,
GetRequestStatus(request, &test_callback));
Cronet_UrlRequest_Start(request);
EXPECT_LE(Cronet_UrlRequestStatusListener_Status_IDLE,
GetRequestStatus(request, &test_callback));
EXPECT_GE(Cronet_UrlRequestStatusListener_Status_READING_RESPONSE,
GetRequestStatus(request, &test_callback));
test_callback.WaitForNextStep();
EXPECT_EQ(Cronet_UrlRequestStatusListener_Status_WAITING_FOR_DELEGATE,
GetRequestStatus(request, &test_callback));
Cronet_BufferPtr buffer = Cronet_Buffer_Create();
Cronet_Buffer_InitWithAlloc(buffer, 100);
Cronet_UrlRequest_Read(request, buffer);
EXPECT_LE(Cronet_UrlRequestStatusListener_Status_IDLE,
GetRequestStatus(request, &test_callback));
EXPECT_GE(Cronet_UrlRequestStatusListener_Status_READING_RESPONSE,
GetRequestStatus(request, &test_callback));
test_callback.WaitForNextStep();
EXPECT_LE(Cronet_UrlRequestStatusListener_Status_IDLE,
GetRequestStatus(request, &test_callback));
EXPECT_GE(Cronet_UrlRequestStatusListener_Status_READING_RESPONSE,
GetRequestStatus(request, &test_callback));
do {
buffer = Cronet_Buffer_Create();
Cronet_Buffer_InitWithAlloc(buffer, 100);
Cronet_UrlRequest_Read(request, buffer);
// Verify that late calls to GetStatus() don't invoke OnStatus() after
// final callbacks.
GetRequestStatus(request, &test_callback);
test_callback.WaitForNextStep();
} while (!Cronet_UrlRequest_IsDone(request));
MaybeVerifyRequestFinishedInfo(&test_request_finished_info_listener,
test_callback);
EXPECT_EQ(Cronet_UrlRequestStatusListener_Status_INVALID,
GetRequestStatus(request, &test_callback));
ASSERT_EQ("The quick brown fox jumps over the lazy dog.",
test_callback.response_as_string_);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
class UrlRequestTestNoParam : public ::testing::Test {
void SetUp() override { cronet::TestServer::Start(); }
void TearDown() override { cronet::TestServer::Shutdown(); }
};
TEST_F(UrlRequestTestNoParam,
RequestFinishedListenerWithoutExecutorReturnsError) {
Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
Cronet_EnginePtr engine = Cronet_Engine_Create();
// Disable runtime CHECK of the result, so it could be verified.
Cronet_EngineParams_enable_check_result_set(engine_params, false);
EXPECT_EQ(Cronet_RESULT_SUCCESS,
Cronet_Engine_StartWithParams(engine, engine_params));
Cronet_EngineParams_Destroy(engine_params);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
TestRequestFinishedInfoListener test_request_finished_info_listener;
Cronet_RequestFinishedInfoListenerPtr request_finished_listener =
test_request_finished_info_listener.CreateRequestFinishedListener();
// Executor type doesn't matter for this test.
TestUrlRequestCallback test_callback(/*direct_executor=*/true);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
Cronet_UrlRequestParams_request_finished_listener_set(
request_params, request_finished_listener);
EXPECT_EQ(Cronet_RESULT_NULL_POINTER_REQUEST_FINISHED_INFO_LISTENER_EXECUTOR,
Cronet_UrlRequest_InitWithParams(
request, engine, "http://fakeurl.example.com", request_params,
callback, executor));
// This test never actually runs |request_finished_listener|, so we delete
// it here.
Cronet_RequestFinishedInfoListener_Destroy(request_finished_listener);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_F(UrlRequestTestNoParam,
UseRequestFinishedInfoAfterUrlRequestDestructionSuccess) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
// The UrlRequest executor type doesn't matter, but the
// RequestFinishedInfoListener executor type can't be direct.
TestUrlRequestCallback test_callback(/* direct_executor= */ false);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
base::WaitableEvent done_event;
struct ListenerContext {
TestUrlRequestCallback* test_callback;
Cronet_UrlRequestPtr url_request;
base::WaitableEvent* done_event;
};
ListenerContext listener_context = {&test_callback, request, &done_event};
auto* request_finished_listener =
Cronet_RequestFinishedInfoListener_CreateWith(
+[](Cronet_RequestFinishedInfoListenerPtr self,
Cronet_RequestFinishedInfoPtr request_finished_info,
Cronet_UrlResponseInfoPtr response_info, Cronet_ErrorPtr error) {
auto* listener_context = static_cast<ListenerContext*>(
Cronet_RequestFinishedInfoListener_GetClientContext(self));
listener_context->test_callback->WaitForDone();
Cronet_UrlRequest_Destroy(listener_context->url_request);
// The next few get methods shouldn't use-after-free on
// |request_finished_info| or |response_info|.
EXPECT_NE(nullptr, Cronet_RequestFinishedInfo_metrics_get(
request_finished_info));
EXPECT_NE(nullptr, Cronet_UrlResponseInfo_url_get(response_info));
Cronet_RequestFinishedInfoListener_Destroy(self);
listener_context->done_event->Signal();
});
Cronet_RequestFinishedInfoListener_SetClientContext(request_finished_listener,
&listener_context);
Cronet_UrlRequestParams_request_finished_listener_set(
request_params, request_finished_listener);
Cronet_UrlRequestParams_request_finished_executor_set(request_params,
executor);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
done_event.Wait();
EXPECT_TRUE(test_callback.IsDone());
ASSERT_EQ("The quick brown fox jumps over the lazy dog.",
test_callback.response_as_string_);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_F(UrlRequestTestNoParam,
UseRequestFinishedInfoAfterUrlRequestDestructionFailure) {
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = "https://notfound.example.com";
// The UrlRequest executor type doesn't matter, but the
// RequestFinishedInfoListener executor type can't be direct.
TestUrlRequestCallback test_callback(/* direct_executor= */ false);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
base::WaitableEvent done_event;
struct ListenerContext {
TestUrlRequestCallback* test_callback;
Cronet_UrlRequestPtr url_request;
base::WaitableEvent* done_event;
};
ListenerContext listener_context = {&test_callback, request, &done_event};
auto* request_finished_listener =
Cronet_RequestFinishedInfoListener_CreateWith(
+[](Cronet_RequestFinishedInfoListenerPtr self,
Cronet_RequestFinishedInfoPtr request_finished_info,
Cronet_UrlResponseInfoPtr response_info, Cronet_ErrorPtr error) {
auto* listener_context = static_cast<ListenerContext*>(
Cronet_RequestFinishedInfoListener_GetClientContext(self));
listener_context->test_callback->WaitForDone();
Cronet_UrlRequest_Destroy(listener_context->url_request);
// The next few get methods shouldn't use-after-free on
// |request_finished_info| or |error|.
EXPECT_NE(nullptr, Cronet_RequestFinishedInfo_metrics_get(
request_finished_info));
EXPECT_NE(nullptr, Cronet_Error_message_get(error));
Cronet_RequestFinishedInfoListener_Destroy(self);
listener_context->done_event->Signal();
});
Cronet_RequestFinishedInfoListener_SetClientContext(request_finished_listener,
&listener_context);
Cronet_UrlRequestParams_request_finished_listener_set(
request_params, request_finished_listener);
Cronet_UrlRequestParams_request_finished_executor_set(request_params,
executor);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
done_event.Wait();
EXPECT_TRUE(test_callback.IsDone());
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
TEST_F(UrlRequestTestNoParam,
CorrelateCallbackAndRequestInfoWithoutSynchronization) {
class TestUrlRequestCallbackWithCorrelation : public TestUrlRequestCallback {
public:
using TestUrlRequestCallback::TestUrlRequestCallback;
void OnSucceeded(Cronet_UrlRequestPtr request,
Cronet_UrlResponseInfoPtr info) override {
// This method is guaranteed to run after
// RequestFinishedInfoListener.OnRequestFinished(), **on the same
// thread** (due to the use of a direct executor with the
// RequestFinishedInfoListener).
//
// The following read should therefore not need synchronization -- we rely
// on running this test under sanitizers to verify this.
EXPECT_NE(nullptr,
Cronet_RequestFinishedInfo_metrics_get(request_finished_info_));
TestUrlRequestCallback::OnSucceeded(request, info);
}
Cronet_RequestFinishedInfoPtr request_finished_info_;
};
Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
std::string url = cronet::TestServer::GetSimpleURL();
// The UrlRequest executor type doesn't matter, but the
// RequestFinishedInfoListener executor type *must* be direct.
TestUrlRequestCallbackWithCorrelation test_callback(
/* direct_executor= */ true);
// Executor provided by the application is owned by |test_callback|.
Cronet_ExecutorPtr executor = test_callback.GetExecutor();
// Callback provided by the application.
Cronet_UrlRequestCallbackPtr callback =
test_callback.CreateUrlRequestCallback();
auto* request_finished_listener =
Cronet_RequestFinishedInfoListener_CreateWith(
+[](Cronet_RequestFinishedInfoListenerPtr self,
Cronet_RequestFinishedInfoPtr request_finished_info,
Cronet_UrlResponseInfoPtr, Cronet_ErrorPtr) {
auto* test_callback =
static_cast<TestUrlRequestCallbackWithCorrelation*>(
Cronet_RequestFinishedInfoListener_GetClientContext(self));
test_callback->request_finished_info_ = request_finished_info;
Cronet_RequestFinishedInfoListener_Destroy(self);
});
Cronet_RequestFinishedInfoListener_SetClientContext(request_finished_listener,
&test_callback);
Cronet_UrlRequestParams_request_finished_listener_set(
request_params, request_finished_listener);
Cronet_UrlRequestParams_request_finished_executor_set(request_params,
executor);
Cronet_UrlRequest_InitWithParams(request, engine, url.c_str(), request_params,
callback, executor);
Cronet_UrlRequest_Start(request);
test_callback.WaitForDone();
EXPECT_TRUE(test_callback.IsDone());
ASSERT_EQ("The quick brown fox jumps over the lazy dog.",
test_callback.response_as_string_);
Cronet_UrlRequest_Destroy(request);
Cronet_UrlRequestParams_Destroy(request_params);
Cronet_UrlRequestCallback_Destroy(callback);
Cronet_Engine_Destroy(engine);
}
} // namespace