Index: net/dns/dns_transaction_unittest.cc |
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc |
deleted file mode 100644 |
index f22478c045024a2f5eade0a3efe8e0b603776e12..0000000000000000000000000000000000000000 |
--- a/net/dns/dns_transaction_unittest.cc |
+++ /dev/null |
@@ -1,1011 +0,0 @@ |
-// 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_transaction.h" |
- |
-#include "base/bind.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/memory/scoped_vector.h" |
-#include "base/rand_util.h" |
-#include "base/sys_byteorder.h" |
-#include "base/test/test_timeouts.h" |
-#include "net/base/dns_util.h" |
-#include "net/base/net_log.h" |
-#include "net/dns/dns_protocol.h" |
-#include "net/dns/dns_query.h" |
-#include "net/dns/dns_response.h" |
-#include "net/dns/dns_session.h" |
-#include "net/dns/dns_test_util.h" |
-#include "net/socket/socket_test_util.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-namespace net { |
- |
-namespace { |
- |
-std::string DomainFromDot(const base::StringPiece& dotted) { |
- std::string out; |
- EXPECT_TRUE(DNSDomainFromDot(dotted, &out)); |
- return out; |
-} |
- |
-// A SocketDataProvider builder. |
-class DnsSocketData { |
- public: |
- // The ctor takes parameters for the DnsQuery. |
- DnsSocketData(uint16 id, |
- const char* dotted_name, |
- uint16 qtype, |
- IoMode mode, |
- bool use_tcp) |
- : query_(new DnsQuery(id, DomainFromDot(dotted_name), qtype)), |
- use_tcp_(use_tcp) { |
- if (use_tcp_) { |
- scoped_ptr<uint16> length(new uint16); |
- *length = base::HostToNet16(query_->io_buffer()->size()); |
- writes_.push_back(MockWrite(mode, |
- reinterpret_cast<const char*>(length.get()), |
- sizeof(uint16))); |
- lengths_.push_back(length.release()); |
- } |
- writes_.push_back(MockWrite(mode, |
- query_->io_buffer()->data(), |
- query_->io_buffer()->size())); |
- } |
- ~DnsSocketData() {} |
- |
- // All responses must be added before GetProvider. |
- |
- // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only. |
- void AddResponseWithLength(scoped_ptr<DnsResponse> response, IoMode mode, |
- uint16 tcp_length) { |
- CHECK(!provider_.get()); |
- if (use_tcp_) { |
- scoped_ptr<uint16> length(new uint16); |
- *length = base::HostToNet16(tcp_length); |
- reads_.push_back(MockRead(mode, |
- reinterpret_cast<const char*>(length.get()), |
- sizeof(uint16))); |
- lengths_.push_back(length.release()); |
- } |
- reads_.push_back(MockRead(mode, |
- response->io_buffer()->data(), |
- response->io_buffer()->size())); |
- responses_.push_back(response.release()); |
- } |
- |
- // Adds pre-built DnsResponse. |
- void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) { |
- uint16 tcp_length = response->io_buffer()->size(); |
- AddResponseWithLength(response.Pass(), mode, tcp_length); |
- } |
- |
- // Adds pre-built response from |data| buffer. |
- void AddResponseData(const uint8* data, size_t length, IoMode mode) { |
- CHECK(!provider_.get()); |
- AddResponse(make_scoped_ptr( |
- new DnsResponse(reinterpret_cast<const char*>(data), length, 0)), mode); |
- } |
- |
- // Add no-answer (RCODE only) response matching the query. |
- void AddRcode(int rcode, IoMode mode) { |
- scoped_ptr<DnsResponse> response( |
- new DnsResponse(query_->io_buffer()->data(), |
- query_->io_buffer()->size(), |
- 0)); |
- dns_protocol::Header* header = |
- reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data()); |
- header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode); |
- AddResponse(response.Pass(), mode); |
- } |
- |
- // Add error response. |
- void AddReadError(int error, IoMode mode) { |
- reads_.push_back(MockRead(mode, error)); |
- } |
- |
- // Build, if needed, and return the SocketDataProvider. No new responses |
- // should be added afterwards. |
- SocketDataProvider* GetProvider() { |
- if (provider_.get()) |
- return provider_.get(); |
- // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to |
- // timeout. |
- reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING)); |
- provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(), |
- &writes_[0], writes_.size())); |
- if (use_tcp_) { |
- provider_->set_connect_data(MockConnect(reads_[0].mode, OK)); |
- } |
- return provider_.get(); |
- } |
- |
- uint16 query_id() const { |
- return query_->id(); |
- } |
- |
- // Returns true if the expected query was written to the socket. |
- bool was_written() const { |
- CHECK(provider_.get()); |
- return provider_->write_index() > 0; |
- } |
- |
- private: |
- scoped_ptr<DnsQuery> query_; |
- bool use_tcp_; |
- ScopedVector<uint16> lengths_; |
- ScopedVector<DnsResponse> responses_; |
- std::vector<MockWrite> writes_; |
- std::vector<MockRead> reads_; |
- scoped_ptr<DelayedSocketData> provider_; |
- |
- DISALLOW_COPY_AND_ASSIGN(DnsSocketData); |
-}; |
- |
-class TestSocketFactory; |
- |
-// A variant of MockUDPClientSocket which always fails to Connect. |
-class FailingUDPClientSocket : public MockUDPClientSocket { |
- public: |
- FailingUDPClientSocket(SocketDataProvider* data, |
- net::NetLog* net_log) |
- : MockUDPClientSocket(data, net_log) { |
- } |
- ~FailingUDPClientSocket() override {} |
- int Connect(const IPEndPoint& endpoint) override { |
- return ERR_CONNECTION_REFUSED; |
- } |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket); |
-}; |
- |
-// A variant of MockUDPClientSocket which notifies the factory OnConnect. |
-class TestUDPClientSocket : public MockUDPClientSocket { |
- public: |
- TestUDPClientSocket(TestSocketFactory* factory, |
- SocketDataProvider* data, |
- net::NetLog* net_log) |
- : MockUDPClientSocket(data, net_log), factory_(factory) { |
- } |
- ~TestUDPClientSocket() override {} |
- int Connect(const IPEndPoint& endpoint) override; |
- |
- private: |
- TestSocketFactory* factory_; |
- |
- DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket); |
-}; |
- |
-// Creates TestUDPClientSockets and keeps endpoints reported via OnConnect. |
-class TestSocketFactory : public MockClientSocketFactory { |
- public: |
- TestSocketFactory() : fail_next_socket_(false) {} |
- ~TestSocketFactory() override {} |
- |
- scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket( |
- DatagramSocket::BindType bind_type, |
- const RandIntCallback& rand_int_cb, |
- net::NetLog* net_log, |
- const net::NetLog::Source& source) override { |
- if (fail_next_socket_) { |
- fail_next_socket_ = false; |
- return scoped_ptr<DatagramClientSocket>( |
- new FailingUDPClientSocket(&empty_data_, net_log)); |
- } |
- SocketDataProvider* data_provider = mock_data().GetNext(); |
- scoped_ptr<TestUDPClientSocket> socket( |
- new TestUDPClientSocket(this, data_provider, net_log)); |
- data_provider->set_socket(socket.get()); |
- return socket.Pass(); |
- } |
- |
- void OnConnect(const IPEndPoint& endpoint) { |
- remote_endpoints_.push_back(endpoint); |
- } |
- |
- std::vector<IPEndPoint> remote_endpoints_; |
- bool fail_next_socket_; |
- |
- private: |
- StaticSocketDataProvider empty_data_; |
- |
- DISALLOW_COPY_AND_ASSIGN(TestSocketFactory); |
-}; |
- |
-int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) { |
- factory_->OnConnect(endpoint); |
- return MockUDPClientSocket::Connect(endpoint); |
-} |
- |
-// Helper class that holds a DnsTransaction and handles OnTransactionComplete. |
-class TransactionHelper { |
- public: |
- // If |expected_answer_count| < 0 then it is the expected net error. |
- TransactionHelper(const char* hostname, |
- uint16 qtype, |
- int expected_answer_count) |
- : hostname_(hostname), |
- qtype_(qtype), |
- expected_answer_count_(expected_answer_count), |
- cancel_in_callback_(false), |
- quit_in_callback_(false), |
- completed_(false) { |
- } |
- |
- // Mark that the transaction shall be destroyed immediately upon callback. |
- void set_cancel_in_callback() { |
- cancel_in_callback_ = true; |
- } |
- |
- // Mark to call MessageLoop::Quit() upon callback. |
- void set_quit_in_callback() { |
- quit_in_callback_ = true; |
- } |
- |
- void StartTransaction(DnsTransactionFactory* factory) { |
- EXPECT_EQ(NULL, transaction_.get()); |
- transaction_ = factory->CreateTransaction( |
- hostname_, |
- qtype_, |
- base::Bind(&TransactionHelper::OnTransactionComplete, |
- base::Unretained(this)), |
- BoundNetLog()); |
- EXPECT_EQ(hostname_, transaction_->GetHostname()); |
- EXPECT_EQ(qtype_, transaction_->GetType()); |
- transaction_->Start(); |
- } |
- |
- void Cancel() { |
- ASSERT_TRUE(transaction_.get() != NULL); |
- transaction_.reset(NULL); |
- } |
- |
- void OnTransactionComplete(DnsTransaction* t, |
- int rv, |
- const DnsResponse* response) { |
- EXPECT_FALSE(completed_); |
- EXPECT_EQ(transaction_.get(), t); |
- |
- completed_ = true; |
- |
- if (cancel_in_callback_) { |
- Cancel(); |
- return; |
- } |
- |
- // Tell MessageLoop to quit now, in case any ASSERT_* fails. |
- if (quit_in_callback_) |
- base::MessageLoop::current()->Quit(); |
- |
- if (expected_answer_count_ >= 0) { |
- ASSERT_EQ(OK, rv); |
- ASSERT_TRUE(response != NULL); |
- EXPECT_EQ(static_cast<unsigned>(expected_answer_count_), |
- response->answer_count()); |
- EXPECT_EQ(qtype_, response->qtype()); |
- |
- DnsRecordParser parser = response->Parser(); |
- DnsResourceRecord record; |
- for (int i = 0; i < expected_answer_count_; ++i) { |
- EXPECT_TRUE(parser.ReadRecord(&record)); |
- } |
- } else { |
- EXPECT_EQ(expected_answer_count_, rv); |
- } |
- } |
- |
- bool has_completed() const { |
- return completed_; |
- } |
- |
- // Shorthands for commonly used commands. |
- |
- bool Run(DnsTransactionFactory* factory) { |
- StartTransaction(factory); |
- base::MessageLoop::current()->RunUntilIdle(); |
- return has_completed(); |
- } |
- |
- // Use when some of the responses are timeouts. |
- bool RunUntilDone(DnsTransactionFactory* factory) { |
- set_quit_in_callback(); |
- StartTransaction(factory); |
- base::MessageLoop::current()->Run(); |
- return has_completed(); |
- } |
- |
- private: |
- std::string hostname_; |
- uint16 qtype_; |
- scoped_ptr<DnsTransaction> transaction_; |
- int expected_answer_count_; |
- bool cancel_in_callback_; |
- bool quit_in_callback_; |
- |
- bool completed_; |
-}; |
- |
-class DnsTransactionTest : public testing::Test { |
- public: |
- DnsTransactionTest() {} |
- |
- // Generates |nameservers| for DnsConfig. |
- void ConfigureNumServers(unsigned num_servers) { |
- CHECK_LE(num_servers, 255u); |
- config_.nameservers.clear(); |
- IPAddressNumber dns_ip; |
- { |
- bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip); |
- EXPECT_TRUE(rv); |
- } |
- for (unsigned i = 0; i < num_servers; ++i) { |
- dns_ip[3] = i; |
- config_.nameservers.push_back(IPEndPoint(dns_ip, |
- dns_protocol::kDefaultPort)); |
- } |
- } |
- |
- // Called after fully configuring |config|. |
- void ConfigureFactory() { |
- socket_factory_.reset(new TestSocketFactory()); |
- session_ = new DnsSession( |
- config_, |
- DnsSocketPool::CreateNull(socket_factory_.get()), |
- base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)), |
- NULL /* NetLog */); |
- transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get()); |
- } |
- |
- void AddSocketData(scoped_ptr<DnsSocketData> data) { |
- CHECK(socket_factory_.get()); |
- transaction_ids_.push_back(data->query_id()); |
- socket_factory_->AddSocketDataProvider(data->GetProvider()); |
- socket_data_.push_back(data.release()); |
- } |
- |
- // Add expected query for |dotted_name| and |qtype| with |id| and response |
- // taken verbatim from |data| of |data_length| bytes. The transaction id in |
- // |data| should equal |id|, unless testing mismatched response. |
- void AddQueryAndResponse(uint16 id, |
- const char* dotted_name, |
- uint16 qtype, |
- const uint8* response_data, |
- size_t response_length, |
- IoMode mode, |
- bool use_tcp) { |
- CHECK(socket_factory_.get()); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(id, dotted_name, qtype, mode, use_tcp)); |
- data->AddResponseData(response_data, response_length, mode); |
- AddSocketData(data.Pass()); |
- } |
- |
- void AddAsyncQueryAndResponse(uint16 id, |
- const char* dotted_name, |
- uint16 qtype, |
- const uint8* data, |
- size_t data_length) { |
- AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC, |
- false); |
- } |
- |
- void AddSyncQueryAndResponse(uint16 id, |
- const char* dotted_name, |
- uint16 qtype, |
- const uint8* data, |
- size_t data_length) { |
- AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS, |
- false); |
- } |
- |
- // Add expected query of |dotted_name| and |qtype| and no response. |
- void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) { |
- uint16 id = base::RandInt(0, kuint16max); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(id, dotted_name, qtype, ASYNC, false)); |
- AddSocketData(data.Pass()); |
- } |
- |
- // Add expected query of |dotted_name| and |qtype| and matching response with |
- // no answer and RCODE set to |rcode|. The id will be generated randomly. |
- void AddQueryAndRcode(const char* dotted_name, |
- uint16 qtype, |
- int rcode, |
- IoMode mode, |
- bool use_tcp) { |
- CHECK_NE(dns_protocol::kRcodeNOERROR, rcode); |
- uint16 id = base::RandInt(0, kuint16max); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(id, dotted_name, qtype, mode, use_tcp)); |
- data->AddRcode(rcode, mode); |
- AddSocketData(data.Pass()); |
- } |
- |
- void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) { |
- AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false); |
- } |
- |
- void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) { |
- AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false); |
- } |
- |
- // Checks if the sockets were connected in the order matching the indices in |
- // |servers|. |
- void CheckServerOrder(const unsigned* servers, size_t num_attempts) { |
- ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size()); |
- for (size_t i = 0; i < num_attempts; ++i) { |
- EXPECT_EQ(socket_factory_->remote_endpoints_[i], |
- session_->config().nameservers[servers[i]]); |
- } |
- } |
- |
- void SetUp() override { |
- // By default set one server, |
- ConfigureNumServers(1); |
- // and no retransmissions, |
- config_.attempts = 1; |
- // but long enough timeout for memory tests. |
- config_.timeout = TestTimeouts::action_timeout(); |
- ConfigureFactory(); |
- } |
- |
- void TearDown() override { |
- // Check that all socket data was at least written to. |
- for (size_t i = 0; i < socket_data_.size(); ++i) { |
- EXPECT_TRUE(socket_data_[i]->was_written()) << i; |
- } |
- } |
- |
- protected: |
- int GetNextId(int min, int max) { |
- EXPECT_FALSE(transaction_ids_.empty()); |
- int id = transaction_ids_.front(); |
- transaction_ids_.pop_front(); |
- EXPECT_GE(id, min); |
- EXPECT_LE(id, max); |
- return id; |
- } |
- |
- DnsConfig config_; |
- |
- ScopedVector<DnsSocketData> socket_data_; |
- |
- std::deque<int> transaction_ids_; |
- scoped_ptr<TestSocketFactory> socket_factory_; |
- scoped_refptr<DnsSession> session_; |
- scoped_ptr<DnsTransactionFactory> transaction_factory_; |
-}; |
- |
-TEST_F(DnsTransactionTest, Lookup) { |
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-// Concurrent lookup tests assume that DnsTransaction::Start immediately |
-// consumes a socket from ClientSocketFactory. |
-TEST_F(DnsTransactionTest, ConcurrentLookup) { |
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype, |
- kT1ResponseDatagram, arraysize(kT1ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- helper0.StartTransaction(transaction_factory_.get()); |
- TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount); |
- helper1.StartTransaction(transaction_factory_.get()); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_TRUE(helper0.has_completed()); |
- EXPECT_TRUE(helper1.has_completed()); |
-} |
- |
-TEST_F(DnsTransactionTest, CancelLookup) { |
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype, |
- kT1ResponseDatagram, arraysize(kT1ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- helper0.StartTransaction(transaction_factory_.get()); |
- TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount); |
- helper1.StartTransaction(transaction_factory_.get()); |
- |
- helper0.Cancel(); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_FALSE(helper0.has_completed()); |
- EXPECT_TRUE(helper1.has_completed()); |
-} |
- |
-TEST_F(DnsTransactionTest, DestroyFactory) { |
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- helper0.StartTransaction(transaction_factory_.get()); |
- |
- // Destroying the client does not affect running requests. |
- transaction_factory_.reset(NULL); |
- |
- base::MessageLoop::current()->RunUntilIdle(); |
- |
- EXPECT_TRUE(helper0.has_completed()); |
-} |
- |
-TEST_F(DnsTransactionTest, CancelFromCallback) { |
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- helper0.set_cancel_in_callback(); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, MismatchedResponseSync) { |
- config_.attempts = 2; |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- |
- // Attempt receives mismatched response followed by valid response. |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false)); |
- data->AddResponseData(kT1ResponseDatagram, |
- arraysize(kT1ResponseDatagram), SYNCHRONOUS); |
- data->AddResponseData(kT0ResponseDatagram, |
- arraysize(kT0ResponseDatagram), SYNCHRONOUS); |
- AddSocketData(data.Pass()); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, MismatchedResponseAsync) { |
- config_.attempts = 2; |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- |
- // First attempt receives mismatched response followed by valid response. |
- // Second attempt times out. |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false)); |
- data->AddResponseData(kT1ResponseDatagram, |
- arraysize(kT1ResponseDatagram), ASYNC); |
- data->AddResponseData(kT0ResponseDatagram, |
- arraysize(kT0ResponseDatagram), ASYNC); |
- AddSocketData(data.Pass()); |
- AddQueryAndTimeout(kT0HostName, kT0Qtype); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, MismatchedResponseFail) { |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- |
- // Attempt receives mismatched response but times out because only one attempt |
- // is allowed. |
- AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); |
- EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, ServerFail) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, NoDomain) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, Timeout) { |
- config_.attempts = 3; |
- // Use short timeout to speed up the test. |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- |
- AddQueryAndTimeout(kT0HostName, kT0Qtype); |
- AddQueryAndTimeout(kT0HostName, kT0Qtype); |
- AddQueryAndTimeout(kT0HostName, kT0Qtype); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); |
- EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); |
- EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); |
-} |
- |
-TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { |
- // Test that we fallback on both server failure and timeout. |
- config_.attempts = 2; |
- // The next request should start from the next server. |
- config_.rotate = true; |
- ConfigureNumServers(3); |
- // Use short timeout to speed up the test. |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- |
- // Responses for first request. |
- AddQueryAndTimeout(kT0HostName, kT0Qtype); |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); |
- AddQueryAndTimeout(kT0HostName, kT0Qtype); |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); |
- // Responses for second request. |
- AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); |
- AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); |
- AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); |
- TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED); |
- |
- EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); |
- EXPECT_TRUE(helper1.Run(transaction_factory_.get())); |
- |
- unsigned kOrder[] = { |
- 0, 1, 2, 0, 1, // The first transaction. |
- 1, 2, 0, // The second transaction starts from the next server. |
- }; |
- CheckServerOrder(kOrder, arraysize(kOrder)); |
-} |
- |
-TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) { |
- config_.ndots = 2; |
- config_.search.push_back("a"); |
- config_.search.push_back("b"); |
- config_.search.push_back("c"); |
- config_.rotate = true; |
- ConfigureNumServers(2); |
- ConfigureFactory(); |
- |
- AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- |
- TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, |
- ERR_NAME_NOT_RESOLVED); |
- |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
- |
- // Also check if suffix search causes server rotation. |
- unsigned kOrder0[] = { 0, 1, 0, 1 }; |
- CheckServerOrder(kOrder0, arraysize(kOrder0)); |
-} |
- |
-TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) { |
- config_.ndots = 2; |
- config_.search.push_back("a"); |
- config_.search.push_back("b"); |
- config_.search.push_back("c"); |
- ConfigureFactory(); |
- |
- // Responses for first transaction. |
- AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- // Responses for second transaction. |
- AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- // Responses for third transaction. |
- AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA, |
- dns_protocol::kRcodeNXDOMAIN); |
- |
- TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); |
- |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
- |
- // A single-label name. |
- TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); |
- |
- EXPECT_TRUE(helper1.Run(transaction_factory_.get())); |
- |
- // A fully-qualified name. |
- TransactionHelper helper2("x.", dns_protocol::kTypeAAAA, |
- ERR_NAME_NOT_RESOLVED); |
- |
- EXPECT_TRUE(helper2.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, EmptySuffixSearch) { |
- // Responses for first transaction. |
- AddAsyncQueryAndRcode("x", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- |
- // A fully-qualified name. |
- TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); |
- |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
- |
- // A single label name is not even attempted. |
- TransactionHelper helper1("singlelabel", dns_protocol::kTypeA, |
- ERR_DNS_SEARCH_EMPTY); |
- |
- helper1.Run(transaction_factory_.get()); |
- EXPECT_TRUE(helper1.has_completed()); |
-} |
- |
-TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) { |
- config_.search.push_back("a"); |
- config_.search.push_back("b"); |
- config_.search.push_back("c"); |
- config_.append_to_multi_label_name = false; |
- ConfigureFactory(); |
- |
- // Responses for first transaction. |
- AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- // Responses for second transaction. |
- AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- // Responses for third transaction. |
- AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- |
- TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, |
- ERR_NAME_NOT_RESOLVED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
- |
- TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); |
- EXPECT_TRUE(helper1.Run(transaction_factory_.get())); |
- |
- TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); |
- EXPECT_TRUE(helper2.Run(transaction_factory_.get())); |
-} |
- |
-const uint8 kResponseNoData[] = { |
- 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, |
- // Question |
- 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, |
- // Authority section, SOA record, TTL 0x3E6 |
- 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6, |
- // Minimal RDATA, 18 bytes |
- 0x00, 0x12, |
- 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, |
-}; |
- |
-TEST_F(DnsTransactionTest, SuffixSearchStop) { |
- config_.ndots = 2; |
- config_.search.push_back("a"); |
- config_.search.push_back("b"); |
- config_.search.push_back("c"); |
- ConfigureFactory(); |
- |
- AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA, |
- kResponseNoData, arraysize(kResponseNoData)); |
- |
- TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */); |
- |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, SyncFirstQuery) { |
- config_.search.push_back("lab.ccs.neu.edu"); |
- config_.search.push_back("ccs.neu.edu"); |
- ConfigureFactory(); |
- |
- AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) { |
- config_.search.push_back("lab.ccs.neu.edu"); |
- config_.search.push_back("ccs.neu.edu"); |
- ConfigureFactory(); |
- |
- AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype, |
- dns_protocol::kRcodeNXDOMAIN); |
- // "www.ccs.neu.edu" |
- AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype, |
- kT2ResponseDatagram, arraysize(kT2ResponseDatagram)); |
- |
- TransactionHelper helper0("www", kT2Qtype, kT2RecordCount); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, SyncSearchQuery) { |
- config_.search.push_back("lab.ccs.neu.edu"); |
- config_.search.push_back("ccs.neu.edu"); |
- ConfigureFactory(); |
- |
- AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA, |
- dns_protocol::kRcodeNXDOMAIN); |
- AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype, |
- kT2ResponseDatagram, arraysize(kT2ResponseDatagram)); |
- |
- TransactionHelper helper0("www", kT2Qtype, kT2RecordCount); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, ConnectFailure) { |
- socket_factory_->fail_next_socket_ = true; |
- transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. |
- TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA, |
- ERR_CONNECTION_REFUSED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) { |
- // Retry after server failure. |
- config_.attempts = 2; |
- ConfigureFactory(); |
- // First server connection attempt fails. |
- transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. |
- socket_factory_->fail_next_socket_ = true; |
- // Second DNS query succeeds. |
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPLookup) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, |
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram), |
- ASYNC, true /* use_tcp */); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPFailure) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, |
- ASYNC, true /* use_tcp */); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPMalformed) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); |
- // Valid response but length too short. |
- // This must be truncated in the question section. The DnsResponse doesn't |
- // examine the answer section until asked to parse it, so truncating it in |
- // the answer section would result in the DnsTransaction itself succeeding. |
- data->AddResponseWithLength( |
- make_scoped_ptr( |
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), |
- arraysize(kT0ResponseDatagram), 0)), |
- ASYNC, |
- static_cast<uint16>(kT0QuerySize - 1)); |
- AddSocketData(data.Pass()); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPTimeout) { |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- AddSocketData(make_scoped_ptr( |
- new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true))); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); |
- EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); |
- // Return all but the last byte of the response. |
- data->AddResponseWithLength( |
- make_scoped_ptr( |
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), |
- arraysize(kT0ResponseDatagram) - 1, 0)), |
- ASYNC, |
- static_cast<uint16>(arraysize(kT0ResponseDatagram))); |
- // Then return a 0-length read. |
- data->AddReadError(0, ASYNC); |
- AddSocketData(data.Pass()); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); |
- // Return all but the last byte of the response. |
- data->AddResponseWithLength( |
- make_scoped_ptr( |
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), |
- arraysize(kT0ResponseDatagram) - 1, 0)), |
- SYNCHRONOUS, |
- static_cast<uint16>(arraysize(kT0ResponseDatagram))); |
- // Then return a 0-length read. |
- data->AddReadError(0, SYNCHRONOUS); |
- AddSocketData(data.Pass()); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); |
- data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC); |
- AddSocketData(data.Pass()); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) { |
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, |
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); |
- scoped_ptr<DnsSocketData> data( |
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); |
- data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS); |
- AddSocketData(data.Pass()); |
- |
- TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-TEST_F(DnsTransactionTest, InvalidQuery) { |
- config_.timeout = TestTimeouts::tiny_timeout(); |
- ConfigureFactory(); |
- |
- TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT); |
- EXPECT_TRUE(helper0.Run(transaction_factory_.get())); |
-} |
- |
-} // namespace |
- |
-} // namespace net |