| Index: net/dns/host_resolver_mojo_unittest.cc
|
| diff --git a/net/dns/host_resolver_mojo_unittest.cc b/net/dns/host_resolver_mojo_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d507326f8e3890d8232edd1408215c8573af03b8
|
| --- /dev/null
|
| +++ b/net/dns/host_resolver_mojo_unittest.cc
|
| @@ -0,0 +1,385 @@
|
| +// Copyright 2015 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 "net/dns/host_resolver_mojo.h"
|
| +
|
| +#include <string>
|
| +
|
| +#include "base/barrier_closure.h"
|
| +#include "base/memory/scoped_vector.h"
|
| +#include "base/run_loop.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/request_priority.h"
|
| +#include "net/dns/type_converters.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
|
| +#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
|
| +
|
| +namespace net {
|
| +namespace {
|
| +
|
| +enum class ConnectionErrorSource {
|
| + NONE,
|
| + RESOLVER,
|
| + REQUEST,
|
| + CLIENT,
|
| +};
|
| +
|
| +void OnResolveComplete(int* error_out,
|
| + const base::Closure& quit_run_loop,
|
| + int error) {
|
| + if (!quit_run_loop.is_null())
|
| + quit_run_loop.Run();
|
| + *error_out = error;
|
| +}
|
| +
|
| +void Fail(int result) {
|
| + FAIL() << "Unexpected callback called with error " << result;
|
| +}
|
| +
|
| +class MockMojoHostResolverRequest : public mojo::ErrorHandler {
|
| + public:
|
| + MockMojoHostResolverRequest(interfaces::HostResolverRequestClientPtr client,
|
| + const base::Closure& error_callback);
|
| + void OnConnectionError() override;
|
| +
|
| + private:
|
| + interfaces::HostResolverRequestClientPtr client_;
|
| + const base::Closure error_callback_;
|
| +};
|
| +
|
| +MockMojoHostResolverRequest::MockMojoHostResolverRequest(
|
| + interfaces::HostResolverRequestClientPtr client,
|
| + const base::Closure& error_callback)
|
| + : client_(client.Pass()), error_callback_(error_callback) {
|
| + client_.set_error_handler(this);
|
| +}
|
| +
|
| +void MockMojoHostResolverRequest::OnConnectionError() {
|
| + error_callback_.Run();
|
| +}
|
| +
|
| +struct HostResolverAction {
|
| + public:
|
| + enum Action {
|
| + COMPLETE,
|
| + DROP,
|
| + RETAIN,
|
| + };
|
| +
|
| + static scoped_ptr<HostResolverAction> ReturnError(int error) {
|
| + scoped_ptr<HostResolverAction> result(new HostResolverAction);
|
| + result->error = error;
|
| + return result.Pass();
|
| + }
|
| +
|
| + static scoped_ptr<HostResolverAction> ReturnResult(
|
| + const AddressList& address_list) {
|
| + scoped_ptr<HostResolverAction> result(new HostResolverAction);
|
| + result->addresses = interfaces::AddressList::From(address_list);
|
| + return result.Pass();
|
| + }
|
| +
|
| + static scoped_ptr<HostResolverAction> DropRequest() {
|
| + scoped_ptr<HostResolverAction> result(new HostResolverAction);
|
| + result->action = DROP;
|
| + return result.Pass();
|
| + }
|
| +
|
| + static scoped_ptr<HostResolverAction> RetainRequest() {
|
| + scoped_ptr<HostResolverAction> result(new HostResolverAction);
|
| + result->action = RETAIN;
|
| + return result.Pass();
|
| + }
|
| +
|
| + Action action = COMPLETE;
|
| + interfaces::AddressListPtr addresses;
|
| + int error = OK;
|
| +};
|
| +
|
| +class MockMojoHostResolver : public interfaces::HostResolver,
|
| + public mojo::ErrorHandler {
|
| + public:
|
| + explicit MockMojoHostResolver(
|
| + mojo::InterfaceRequest<interfaces::HostResolver> request,
|
| + const base::Closure& resolver_connection_error_callback,
|
| + const base::Closure& request_connection_error_callback);
|
| +
|
| + void AddAction(scoped_ptr<HostResolverAction> action);
|
| +
|
| + const mojo::Array<interfaces::HostResolverRequestInfoPtr>& requests() {
|
| + return requests_received_;
|
| + }
|
| +
|
| + private:
|
| + // interfaces::HostResolver override.
|
| + void Resolve(interfaces::HostResolverRequestInfoPtr request_info,
|
| + interfaces::HostResolverRequestClientPtr client) override;
|
| +
|
| + // mojo::ErrorHandler override.
|
| + void OnConnectionError() override;
|
| +
|
| + mojo::Binding<interfaces::HostResolver> binding_;
|
| + ScopedVector<HostResolverAction> actions_;
|
| + size_t results_returned_ = 0;
|
| + mojo::Array<interfaces::HostResolverRequestInfoPtr> requests_received_;
|
| + const base::Closure resolver_connection_error_callback_;
|
| + const base::Closure request_connection_error_callback_;
|
| + ScopedVector<MockMojoHostResolverRequest> requests_;
|
| +};
|
| +
|
| +MockMojoHostResolver::MockMojoHostResolver(
|
| + mojo::InterfaceRequest<interfaces::HostResolver> request,
|
| + const base::Closure& resolver_connection_error_callback,
|
| + const base::Closure& request_connection_error_callback)
|
| + : binding_(this, request.Pass()),
|
| + resolver_connection_error_callback_(resolver_connection_error_callback),
|
| + request_connection_error_callback_(request_connection_error_callback) {
|
| + binding_.set_error_handler(this);
|
| +}
|
| +
|
| +void MockMojoHostResolver::OnConnectionError() {
|
| + resolver_connection_error_callback_.Run();
|
| +}
|
| +
|
| +void MockMojoHostResolver::AddAction(scoped_ptr<HostResolverAction> action) {
|
| + actions_.push_back(action.release());
|
| +}
|
| +
|
| +void MockMojoHostResolver::Resolve(
|
| + interfaces::HostResolverRequestInfoPtr request_info,
|
| + interfaces::HostResolverRequestClientPtr client) {
|
| + requests_received_.push_back(request_info.Pass());
|
| + ASSERT_LE(results_returned_, actions_.size());
|
| + switch (actions_[results_returned_]->action) {
|
| + case HostResolverAction::COMPLETE:
|
| + client->ReportResult(actions_[results_returned_]->error,
|
| + actions_[results_returned_]->addresses.Pass());
|
| + break;
|
| + case HostResolverAction::RETAIN:
|
| + requests_.push_back(new MockMojoHostResolverRequest(
|
| + client.Pass(), request_connection_error_callback_));
|
| + break;
|
| + case HostResolverAction::DROP:
|
| + client.reset();
|
| + break;
|
| + }
|
| + results_returned_++;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class HostResolverMojoTest : public testing::Test, public mojo::ErrorHandler {
|
| + protected:
|
| + void SetUp() override {
|
| + interfaces::HostResolverPtr resolver_ptr;
|
| + mock_resolver_.reset(new MockMojoHostResolver(
|
| + mojo::GetProxy(&resolver_ptr),
|
| + base::Bind(&HostResolverMojoTest::HandleConnectionError,
|
| + base::Unretained(this), ConnectionErrorSource::RESOLVER),
|
| + base::Bind(&HostResolverMojoTest::HandleConnectionError,
|
| + base::Unretained(this), ConnectionErrorSource::REQUEST)));
|
| + resolver_.reset(new HostResolverMojo(resolver_ptr.Pass(), this));
|
| + }
|
| +
|
| + void OnConnectionError() override {
|
| + HandleConnectionError(ConnectionErrorSource::CLIENT);
|
| + }
|
| +
|
| + void HandleConnectionError(ConnectionErrorSource source) {
|
| + if (!run_loop_quit_closure_.is_null())
|
| + run_loop_quit_closure_.Run();
|
| + ASSERT_EQ(expected_connection_error_source_, source);
|
| + }
|
| +
|
| + int Resolve(const HostResolver::RequestInfo& request_info,
|
| + AddressList* result) {
|
| + HostResolver::RequestHandle request_handle = nullptr;
|
| + base::RunLoop run_loop;
|
| + int error = 1;
|
| + resolver_->Resolve(
|
| + request_info, DEFAULT_PRIORITY, result,
|
| + base::Bind(&OnResolveComplete, &error, run_loop.QuitClosure()),
|
| + &request_handle, BoundNetLog());
|
| + run_loop.Run();
|
| + return error;
|
| + }
|
| +
|
| + void WaitForConnectionError(ConnectionErrorSource source) {
|
| + expected_connection_error_source_ = source;
|
| + base::RunLoop run_loop;
|
| + run_loop_quit_closure_ = run_loop.QuitClosure();
|
| + run_loop.Run();
|
| + }
|
| +
|
| + scoped_ptr<MockMojoHostResolver> mock_resolver_;
|
| +
|
| + scoped_ptr<HostResolverMojo> resolver_;
|
| +
|
| + ConnectionErrorSource expected_connection_error_source_ =
|
| + ConnectionErrorSource::NONE;
|
| + base::Closure run_loop_quit_closure_;
|
| +};
|
| +
|
| +TEST_F(HostResolverMojoTest, Basic) {
|
| + AddressList address_list;
|
| + IPAddressNumber address_number;
|
| + ASSERT_TRUE(ParseIPLiteralToNumber("1.2.3.4", &address_number));
|
| + address_list.push_back(IPEndPoint(address_number, 12345));
|
| + address_list.push_back(
|
| + IPEndPoint(ConvertIPv4NumberToIPv6Number(address_number), 12345));
|
| + mock_resolver_->AddAction(HostResolverAction::ReturnResult(address_list));
|
| + HostResolver::RequestInfo request_info(
|
| + HostPortPair::FromString("example.com:12345"));
|
| + AddressList result;
|
| + EXPECT_EQ(OK, Resolve(request_info, &result));
|
| + ASSERT_EQ(2u, result.size());
|
| + EXPECT_EQ(address_list[0], result[0]);
|
| + EXPECT_EQ(address_list[1], result[1]);
|
| +
|
| + ASSERT_EQ(1u, mock_resolver_->requests().size());
|
| + interfaces::HostResolverRequestInfo& request = *mock_resolver_->requests()[0];
|
| + EXPECT_EQ("example.com", request.host.To<std::string>());
|
| + EXPECT_EQ(12345, request.port);
|
| + EXPECT_EQ(interfaces::ADDRESS_FAMILY_UNSPECIFIED, request.address_family);
|
| + EXPECT_FALSE(request.is_my_ip_address);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, Multiple) {
|
| + AddressList address_list;
|
| + IPAddressNumber address_number;
|
| + ASSERT_TRUE(ParseIPLiteralToNumber("1.2.3.4", &address_number));
|
| + address_list.push_back(IPEndPoint(address_number, 12345));
|
| + mock_resolver_->AddAction(HostResolverAction::ReturnResult(address_list));
|
| + mock_resolver_->AddAction(
|
| + HostResolverAction::ReturnError(ERR_NAME_NOT_RESOLVED));
|
| + HostResolver::RequestInfo request_info1(
|
| + HostPortPair::FromString("example.com:12345"));
|
| + request_info1.set_address_family(ADDRESS_FAMILY_IPV4);
|
| + request_info1.set_is_my_ip_address(true);
|
| + HostResolver::RequestInfo request_info2(
|
| + HostPortPair::FromString("example.org:80"));
|
| + request_info2.set_address_family(ADDRESS_FAMILY_IPV6);
|
| + AddressList result1;
|
| + AddressList result2;
|
| + HostResolver::RequestHandle request_handle1 = nullptr;
|
| + HostResolver::RequestHandle request_handle2 = nullptr;
|
| + int error1 = 1;
|
| + int error2 = 1;
|
| + base::RunLoop run_loop;
|
| + base::Closure barrier = base::BarrierClosure(2, run_loop.QuitClosure());
|
| + resolver_->Resolve(request_info1, DEFAULT_PRIORITY, &result1,
|
| + base::Bind(&OnResolveComplete, &error1, barrier),
|
| + &request_handle1, BoundNetLog());
|
| + resolver_->Resolve(request_info2, DEFAULT_PRIORITY, &result2,
|
| + base::Bind(&OnResolveComplete, &error2, barrier),
|
| + &request_handle2, BoundNetLog());
|
| + run_loop.Run();
|
| + EXPECT_EQ(OK, error1);
|
| + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, error2);
|
| + ASSERT_EQ(1u, result1.size());
|
| + EXPECT_EQ(address_list[0], result1[0]);
|
| + ASSERT_EQ(0u, result2.size());
|
| +
|
| + ASSERT_EQ(2u, mock_resolver_->requests().size());
|
| + interfaces::HostResolverRequestInfo& request1 =
|
| + *mock_resolver_->requests()[0];
|
| + EXPECT_EQ("example.com", request1.host.To<std::string>());
|
| + EXPECT_EQ(12345, request1.port);
|
| + EXPECT_EQ(interfaces::ADDRESS_FAMILY_IPV4, request1.address_family);
|
| + EXPECT_TRUE(request1.is_my_ip_address);
|
| + interfaces::HostResolverRequestInfo& request2 =
|
| + *mock_resolver_->requests()[1];
|
| + EXPECT_EQ("example.org", request2.host.To<std::string>());
|
| + EXPECT_EQ(80, request2.port);
|
| + EXPECT_EQ(interfaces::ADDRESS_FAMILY_IPV6, request2.address_family);
|
| + EXPECT_FALSE(request2.is_my_ip_address);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, Error) {
|
| + mock_resolver_->AddAction(
|
| + HostResolverAction::ReturnError(ERR_NAME_NOT_RESOLVED));
|
| + HostResolver::RequestInfo request_info(
|
| + HostPortPair::FromString("example.com:8080"));
|
| + request_info.set_address_family(ADDRESS_FAMILY_IPV4);
|
| + AddressList result;
|
| + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, Resolve(request_info, &result));
|
| + EXPECT_TRUE(result.empty());
|
| +
|
| + ASSERT_EQ(1u, mock_resolver_->requests().size());
|
| + interfaces::HostResolverRequestInfo& request = *mock_resolver_->requests()[0];
|
| + EXPECT_EQ("example.com", request.host.To<std::string>());
|
| + EXPECT_EQ(8080, request.port);
|
| + EXPECT_EQ(interfaces::ADDRESS_FAMILY_IPV4, request.address_family);
|
| + EXPECT_FALSE(request.is_my_ip_address);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, MissingResult) {
|
| + mock_resolver_->AddAction(HostResolverAction::ReturnError(OK));
|
| + HostResolver::RequestInfo request_info(
|
| + HostPortPair::FromString("example.com:8080"));
|
| + AddressList result;
|
| + EXPECT_EQ(ERR_FAILED, Resolve(request_info, &result));
|
| + EXPECT_TRUE(result.empty());
|
| +
|
| + ASSERT_EQ(1u, mock_resolver_->requests().size());
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, Cancel) {
|
| + mock_resolver_->AddAction(HostResolverAction::RetainRequest());
|
| + HostResolver::RequestInfo request_info(
|
| + HostPortPair::FromString("example.com:80"));
|
| + request_info.set_address_family(ADDRESS_FAMILY_IPV6);
|
| + AddressList result;
|
| + HostResolver::RequestHandle request_handle = nullptr;
|
| + resolver_->Resolve(request_info, DEFAULT_PRIORITY, &result, base::Bind(&Fail),
|
| + &request_handle, BoundNetLog());
|
| + resolver_->CancelRequest(request_handle);
|
| + WaitForConnectionError(ConnectionErrorSource::REQUEST);
|
| + EXPECT_TRUE(result.empty());
|
| +
|
| + ASSERT_EQ(1u, mock_resolver_->requests().size());
|
| + interfaces::HostResolverRequestInfo& request = *mock_resolver_->requests()[0];
|
| + EXPECT_EQ("example.com", request.host.To<std::string>());
|
| + EXPECT_EQ(80, request.port);
|
| + EXPECT_EQ(interfaces::ADDRESS_FAMILY_IPV6, request.address_family);
|
| + EXPECT_FALSE(request.is_my_ip_address);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, ImplDropsClientConnection) {
|
| + mock_resolver_->AddAction(HostResolverAction::DropRequest());
|
| + HostResolver::RequestInfo request_info(
|
| + HostPortPair::FromString("example.com:1"));
|
| + AddressList result;
|
| + EXPECT_EQ(ERR_FAILED, Resolve(request_info, &result));
|
| + EXPECT_TRUE(result.empty());
|
| +
|
| + ASSERT_EQ(1u, mock_resolver_->requests().size());
|
| + interfaces::HostResolverRequestInfo& request = *mock_resolver_->requests()[0];
|
| + EXPECT_EQ("example.com", request.host.To<std::string>());
|
| + EXPECT_EQ(1, request.port);
|
| + EXPECT_EQ(interfaces::ADDRESS_FAMILY_UNSPECIFIED, request.address_family);
|
| + EXPECT_FALSE(request.is_my_ip_address);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, DestroyImpl) {
|
| + mock_resolver_.reset();
|
| + WaitForConnectionError(ConnectionErrorSource::CLIENT);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, DestroyClient) {
|
| + resolver_.reset();
|
| + WaitForConnectionError(ConnectionErrorSource::RESOLVER);
|
| +}
|
| +
|
| +TEST_F(HostResolverMojoTest, ResolverFromCache) {
|
| + HostResolver::RequestInfo request_info(
|
| + HostPortPair::FromString("example.com:8080"));
|
| + AddressList result;
|
| + EXPECT_EQ(ERR_FAILED,
|
| + resolver_->ResolveFromCache(request_info, &result, BoundNetLog()));
|
| + EXPECT_TRUE(result.empty());
|
| +}
|
| +
|
| +} // namespace net
|
|
|