blob: 86f43657bd9bbd1ca687cbfbb9ce51d26056306b [file] [log] [blame]
// Copyright (c) 2012 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/dns_session.h"
#include <list>
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
#include "net/base/ip_address.h"
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_socket_pool.h"
#include "net/log/net_log_source.h"
#include "net/socket/socket_performance_watcher.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/stream_socket.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
class TestClientSocketFactory : public ClientSocketFactory {
public:
~TestClientSocketFactory() override;
std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
NetLog* net_log,
const NetLogSource& source) override;
std::unique_ptr<TransportClientSocket> CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher>,
NetLog*,
const NetLogSource&) override {
NOTIMPLEMENTED();
return nullptr;
}
std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
std::unique_ptr<ClientSocketHandle> transport_socket,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
const SSLClientSocketContext& context) override {
NOTIMPLEMENTED();
return std::unique_ptr<SSLClientSocket>();
}
std::unique_ptr<ProxyClientSocket> CreateProxyClientSocket(
std::unique_ptr<ClientSocketHandle> transport_socket,
const std::string& user_agent,
const HostPortPair& endpoint,
HttpAuthController* http_auth_controller,
bool tunnel,
bool using_spdy,
NextProto negotiated_protocol,
bool is_https_proxy,
const NetworkTrafficAnnotationTag& traffic_annotation) override {
NOTIMPLEMENTED();
return nullptr;
}
void ClearSSLSessionCache() override { NOTIMPLEMENTED(); }
private:
std::list<std::unique_ptr<SocketDataProvider>> data_providers_;
};
struct PoolEvent {
enum { ALLOCATE, FREE } action;
unsigned server_index;
};
class DnsSessionTest : public testing::Test {
public:
void OnSocketAllocated(unsigned server_index);
void OnSocketFreed(unsigned server_index);
protected:
void Initialize(unsigned num_servers);
std::unique_ptr<DnsSession::SocketLease> Allocate(unsigned server_index);
bool DidAllocate(unsigned server_index);
bool DidFree(unsigned server_index);
bool NoMoreEvents();
DnsConfig config_;
std::unique_ptr<TestClientSocketFactory> test_client_socket_factory_;
scoped_refptr<DnsSession> session_;
NetLogSource source_;
private:
bool ExpectEvent(const PoolEvent& event);
std::list<PoolEvent> events_;
};
class MockDnsSocketPool : public DnsSocketPool {
public:
MockDnsSocketPool(ClientSocketFactory* factory, DnsSessionTest* test)
: DnsSocketPool(factory, base::Bind(&base::RandInt)), test_(test) {}
~MockDnsSocketPool() override = default;
void Initialize(const std::vector<IPEndPoint>* nameservers,
NetLog* net_log) override {
InitializeInternal(nameservers, net_log);
}
std::unique_ptr<DatagramClientSocket> AllocateSocket(
unsigned server_index) override {
test_->OnSocketAllocated(server_index);
return CreateConnectedSocket(server_index);
}
void FreeSocket(unsigned server_index,
std::unique_ptr<DatagramClientSocket> socket) override {
test_->OnSocketFreed(server_index);
}
private:
DnsSessionTest* test_;
};
void DnsSessionTest::Initialize(unsigned num_servers) {
CHECK(num_servers < 256u);
config_.nameservers.clear();
for (unsigned char i = 0; i < num_servers; ++i) {
IPEndPoint dns_endpoint(IPAddress(192, 168, 1, i),
dns_protocol::kDefaultPort);
config_.nameservers.push_back(dns_endpoint);
}
test_client_socket_factory_.reset(new TestClientSocketFactory());
DnsSocketPool* dns_socket_pool =
new MockDnsSocketPool(test_client_socket_factory_.get(), this);
session_ =
new DnsSession(config_, std::unique_ptr<DnsSocketPool>(dns_socket_pool),
base::Bind(&base::RandInt), NULL /* NetLog */);
events_.clear();
}
std::unique_ptr<DnsSession::SocketLease> DnsSessionTest::Allocate(
unsigned server_index) {
return session_->AllocateSocket(server_index, source_);
}
bool DnsSessionTest::DidAllocate(unsigned server_index) {
PoolEvent expected_event = { PoolEvent::ALLOCATE, server_index };
return ExpectEvent(expected_event);
}
bool DnsSessionTest::DidFree(unsigned server_index) {
PoolEvent expected_event = { PoolEvent::FREE, server_index };
return ExpectEvent(expected_event);
}
bool DnsSessionTest::NoMoreEvents() {
return events_.empty();
}
void DnsSessionTest::OnSocketAllocated(unsigned server_index) {
PoolEvent event = { PoolEvent::ALLOCATE, server_index };
events_.push_back(event);
}
void DnsSessionTest::OnSocketFreed(unsigned server_index) {
PoolEvent event = { PoolEvent::FREE, server_index };
events_.push_back(event);
}
bool DnsSessionTest::ExpectEvent(const PoolEvent& expected) {
if (events_.empty()) {
return false;
}
const PoolEvent actual = events_.front();
if ((expected.action != actual.action)
|| (expected.server_index != actual.server_index)) {
return false;
}
events_.pop_front();
return true;
}
std::unique_ptr<DatagramClientSocket>
TestClientSocketFactory::CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
NetLog* net_log,
const NetLogSource& source) {
// We're not actually expecting to send or receive any data, so use the
// simplest SocketDataProvider with no data supplied.
SocketDataProvider* data_provider = new StaticSocketDataProvider();
data_providers_.push_back(base::WrapUnique(data_provider));
std::unique_ptr<MockUDPClientSocket> socket(
new MockUDPClientSocket(data_provider, net_log));
return std::move(socket);
}
TestClientSocketFactory::~TestClientSocketFactory() = default;
TEST_F(DnsSessionTest, AllocateFree) {
std::unique_ptr<DnsSession::SocketLease> lease1, lease2;
Initialize(2);
EXPECT_TRUE(NoMoreEvents());
lease1 = Allocate(0);
EXPECT_TRUE(DidAllocate(0));
EXPECT_TRUE(NoMoreEvents());
lease2 = Allocate(1);
EXPECT_TRUE(DidAllocate(1));
EXPECT_TRUE(NoMoreEvents());
lease1.reset();
EXPECT_TRUE(DidFree(0));
EXPECT_TRUE(NoMoreEvents());
lease2.reset();
EXPECT_TRUE(DidFree(1));
EXPECT_TRUE(NoMoreEvents());
}
// Expect default calculated timeout to be within 10ms of one in DnsConfig.
TEST_F(DnsSessionTest, HistogramTimeoutNormal) {
Initialize(2);
base::TimeDelta delta = session_->NextTimeout(0, 0) - config_.timeout;
EXPECT_LE(delta.InMilliseconds(), 10);
}
// Expect short calculated timeout to be within 10ms of one in DnsConfig.
TEST_F(DnsSessionTest, HistogramTimeoutShort) {
config_.timeout = base::TimeDelta::FromMilliseconds(15);
Initialize(2);
base::TimeDelta delta = session_->NextTimeout(0, 0) - config_.timeout;
EXPECT_LE(delta.InMilliseconds(), 10);
}
// Expect long calculated timeout to be equal to one in DnsConfig.
// (Default max timeout is 5 seconds, so NextTimeout should return exactly
// the config timeout.)
TEST_F(DnsSessionTest, HistogramTimeoutLong) {
config_.timeout = base::TimeDelta::FromSeconds(15);
Initialize(2);
base::TimeDelta timeout = session_->NextTimeout(0, 0);
EXPECT_EQ(timeout.InMilliseconds(), config_.timeout.InMilliseconds());
}
// Ensures that reported negative RTT values don't cause a crash. Regression
// test for https://crbug.com/753568.
TEST_F(DnsSessionTest, NegativeRtt) {
Initialize(2);
session_->RecordRTT(0, base::TimeDelta::FromMilliseconds(-1));
}
} // namespace
} // namespace net