| // 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 "base/bind.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/rand_util.h" |
| #include "base/stl_util.h" |
| #include "net/base/net_log.h" |
| #include "net/dns/dns_protocol.h" |
| #include "net/dns/dns_socket_pool.h" |
| #include "net/socket/socket_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| class TestClientSocketFactory : public ClientSocketFactory { |
| public: |
| virtual ~TestClientSocketFactory(); |
| |
| virtual DatagramClientSocket* CreateDatagramClientSocket( |
| DatagramSocket::BindType bind_type, |
| const RandIntCallback& rand_int_cb, |
| net::NetLog* net_log, |
| const net::NetLog::Source& source) OVERRIDE; |
| |
| virtual StreamSocket* CreateTransportClientSocket( |
| const AddressList& addresses, |
| NetLog*, const NetLog::Source&) OVERRIDE { |
| NOTIMPLEMENTED(); |
| return NULL; |
| } |
| |
| virtual SSLClientSocket* CreateSSLClientSocket( |
| ClientSocketHandle* transport_socket, |
| const HostPortPair& host_and_port, |
| const SSLConfig& ssl_config, |
| const SSLClientSocketContext& context) OVERRIDE { |
| NOTIMPLEMENTED(); |
| return NULL; |
| } |
| |
| virtual void ClearSSLSessionCache() OVERRIDE { |
| NOTIMPLEMENTED(); |
| } |
| |
| private: |
| std::list<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); |
| scoped_ptr<DnsSession::SocketLease> Allocate(unsigned server_index); |
| bool DidAllocate(unsigned server_index); |
| bool DidFree(unsigned server_index); |
| bool NoMoreEvents(); |
| |
| DnsConfig config_; |
| scoped_ptr<TestClientSocketFactory> test_client_socket_factory_; |
| scoped_refptr<DnsSession> session_; |
| NetLog::Source source_; |
| |
| private: |
| bool ExpectEvent(const PoolEvent& event); |
| std::list<PoolEvent> events_; |
| }; |
| |
| class MockDnsSocketPool : public DnsSocketPool { |
| public: |
| MockDnsSocketPool(ClientSocketFactory* factory, DnsSessionTest* test) |
| : DnsSocketPool(factory), test_(test) { } |
| |
| virtual ~MockDnsSocketPool() { } |
| |
| virtual void Initialize( |
| const std::vector<IPEndPoint>* nameservers, |
| NetLog* net_log) OVERRIDE { |
| InitializeInternal(nameservers, net_log); |
| } |
| |
| virtual scoped_ptr<DatagramClientSocket> AllocateSocket( |
| unsigned server_index) OVERRIDE { |
| test_->OnSocketAllocated(server_index); |
| return CreateConnectedSocket(server_index); |
| } |
| |
| virtual void FreeSocket( |
| unsigned server_index, |
| scoped_ptr<DatagramClientSocket> socket) OVERRIDE { |
| test_->OnSocketFreed(server_index); |
| } |
| |
| private: |
| DnsSessionTest* test_; |
| }; |
| |
| void DnsSessionTest::Initialize(unsigned num_servers) { |
| CHECK(num_servers < 256u); |
| config_.nameservers.clear(); |
| IPAddressNumber dns_ip; |
| bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip); |
| EXPECT_TRUE(rv); |
| for (unsigned char i = 0; i < num_servers; ++i) { |
| dns_ip[3] = i; |
| IPEndPoint dns_endpoint(dns_ip, 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_, |
| scoped_ptr<DnsSocketPool>(dns_socket_pool), |
| base::Bind(&base::RandInt), |
| NULL /* NetLog */); |
| |
| events_.clear(); |
| } |
| |
| scoped_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; |
| } |
| |
| DatagramClientSocket* TestClientSocketFactory::CreateDatagramClientSocket( |
| DatagramSocket::BindType bind_type, |
| const RandIntCallback& rand_int_cb, |
| net::NetLog* net_log, |
| const net::NetLog::Source& 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(data_provider); |
| MockUDPClientSocket* socket = new MockUDPClientSocket(data_provider, net_log); |
| data_provider->set_socket(socket); |
| return socket; |
| } |
| |
| TestClientSocketFactory::~TestClientSocketFactory() { |
| STLDeleteElements(&data_providers_); |
| } |
| |
| TEST_F(DnsSessionTest, AllocateFree) { |
| scoped_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()); |
| } |
| |
| } // namespace |
| |
| } // namespace net |