Fix more MSVC warnings, courgette/ edition.
[chromium-blink-merge.git] / net / dns / dns_transaction_unittest.cc
blobaf073ac2437231b17fee1aa55cf58f5a9bd0afb9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/dns/dns_transaction.h"
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/rand_util.h"
11 #include "base/sys_byteorder.h"
12 #include "base/test/test_timeouts.h"
13 #include "net/base/dns_util.h"
14 #include "net/base/net_log.h"
15 #include "net/dns/dns_protocol.h"
16 #include "net/dns/dns_query.h"
17 #include "net/dns/dns_response.h"
18 #include "net/dns/dns_session.h"
19 #include "net/dns/dns_test_util.h"
20 #include "net/socket/socket_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 namespace net {
25 namespace {
27 std::string DomainFromDot(const base::StringPiece& dotted) {
28 std::string out;
29 EXPECT_TRUE(DNSDomainFromDot(dotted, &out));
30 return out;
33 // A SocketDataProvider builder.
34 class DnsSocketData {
35 public:
36 // The ctor takes parameters for the DnsQuery.
37 DnsSocketData(uint16 id,
38 const char* dotted_name,
39 uint16 qtype,
40 IoMode mode,
41 bool use_tcp)
42 : query_(new DnsQuery(id, DomainFromDot(dotted_name), qtype)),
43 use_tcp_(use_tcp) {
44 if (use_tcp_) {
45 scoped_ptr<uint16> length(new uint16);
46 *length = base::HostToNet16(query_->io_buffer()->size());
47 writes_.push_back(MockWrite(mode,
48 reinterpret_cast<const char*>(length.get()),
49 sizeof(uint16)));
50 lengths_.push_back(length.release());
52 writes_.push_back(MockWrite(mode,
53 query_->io_buffer()->data(),
54 query_->io_buffer()->size()));
56 ~DnsSocketData() {}
58 // All responses must be added before GetProvider.
60 // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
61 void AddResponseWithLength(scoped_ptr<DnsResponse> response, IoMode mode,
62 uint16 tcp_length) {
63 CHECK(!provider_.get());
64 if (use_tcp_) {
65 scoped_ptr<uint16> length(new uint16);
66 *length = base::HostToNet16(tcp_length);
67 reads_.push_back(MockRead(mode,
68 reinterpret_cast<const char*>(length.get()),
69 sizeof(uint16)));
70 lengths_.push_back(length.release());
72 reads_.push_back(MockRead(mode,
73 response->io_buffer()->data(),
74 response->io_buffer()->size()));
75 responses_.push_back(response.release());
78 // Adds pre-built DnsResponse.
79 void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) {
80 uint16 tcp_length = response->io_buffer()->size();
81 AddResponseWithLength(response.Pass(), mode, tcp_length);
84 // Adds pre-built response from |data| buffer.
85 void AddResponseData(const uint8* data, size_t length, IoMode mode) {
86 CHECK(!provider_.get());
87 AddResponse(make_scoped_ptr(
88 new DnsResponse(reinterpret_cast<const char*>(data), length, 0)), mode);
91 // Add no-answer (RCODE only) response matching the query.
92 void AddRcode(int rcode, IoMode mode) {
93 scoped_ptr<DnsResponse> response(
94 new DnsResponse(query_->io_buffer()->data(),
95 query_->io_buffer()->size(),
96 0));
97 dns_protocol::Header* header =
98 reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data());
99 header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode);
100 AddResponse(response.Pass(), mode);
103 // Add error response.
104 void AddReadError(int error, IoMode mode) {
105 reads_.push_back(MockRead(mode, error));
108 // Build, if needed, and return the SocketDataProvider. No new responses
109 // should be added afterwards.
110 SocketDataProvider* GetProvider() {
111 if (provider_.get())
112 return provider_.get();
113 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
114 // timeout.
115 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
116 provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
117 &writes_[0], writes_.size()));
118 if (use_tcp_) {
119 provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
121 return provider_.get();
124 uint16 query_id() const {
125 return query_->id();
128 // Returns true if the expected query was written to the socket.
129 bool was_written() const {
130 CHECK(provider_.get());
131 return provider_->write_index() > 0;
134 private:
135 scoped_ptr<DnsQuery> query_;
136 bool use_tcp_;
137 ScopedVector<uint16> lengths_;
138 ScopedVector<DnsResponse> responses_;
139 std::vector<MockWrite> writes_;
140 std::vector<MockRead> reads_;
141 scoped_ptr<DelayedSocketData> provider_;
143 DISALLOW_COPY_AND_ASSIGN(DnsSocketData);
146 class TestSocketFactory;
148 // A variant of MockUDPClientSocket which always fails to Connect.
149 class FailingUDPClientSocket : public MockUDPClientSocket {
150 public:
151 FailingUDPClientSocket(SocketDataProvider* data,
152 net::NetLog* net_log)
153 : MockUDPClientSocket(data, net_log) {
155 virtual ~FailingUDPClientSocket() {}
156 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE {
157 return ERR_CONNECTION_REFUSED;
160 private:
161 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket);
164 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
165 class TestUDPClientSocket : public MockUDPClientSocket {
166 public:
167 TestUDPClientSocket(TestSocketFactory* factory,
168 SocketDataProvider* data,
169 net::NetLog* net_log)
170 : MockUDPClientSocket(data, net_log), factory_(factory) {
172 virtual ~TestUDPClientSocket() {}
173 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE;
175 private:
176 TestSocketFactory* factory_;
178 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket);
181 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
182 class TestSocketFactory : public MockClientSocketFactory {
183 public:
184 TestSocketFactory() : fail_next_socket_(false) {}
185 virtual ~TestSocketFactory() {}
187 virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
188 DatagramSocket::BindType bind_type,
189 const RandIntCallback& rand_int_cb,
190 net::NetLog* net_log,
191 const net::NetLog::Source& source) OVERRIDE {
192 if (fail_next_socket_) {
193 fail_next_socket_ = false;
194 return scoped_ptr<DatagramClientSocket>(
195 new FailingUDPClientSocket(&empty_data_, net_log));
197 SocketDataProvider* data_provider = mock_data().GetNext();
198 scoped_ptr<TestUDPClientSocket> socket(
199 new TestUDPClientSocket(this, data_provider, net_log));
200 data_provider->set_socket(socket.get());
201 return socket.PassAs<DatagramClientSocket>();
204 void OnConnect(const IPEndPoint& endpoint) {
205 remote_endpoints_.push_back(endpoint);
208 std::vector<IPEndPoint> remote_endpoints_;
209 bool fail_next_socket_;
211 private:
212 StaticSocketDataProvider empty_data_;
214 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory);
217 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
218 factory_->OnConnect(endpoint);
219 return MockUDPClientSocket::Connect(endpoint);
222 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
223 class TransactionHelper {
224 public:
225 // If |expected_answer_count| < 0 then it is the expected net error.
226 TransactionHelper(const char* hostname,
227 uint16 qtype,
228 int expected_answer_count)
229 : hostname_(hostname),
230 qtype_(qtype),
231 expected_answer_count_(expected_answer_count),
232 cancel_in_callback_(false),
233 quit_in_callback_(false),
234 completed_(false) {
237 // Mark that the transaction shall be destroyed immediately upon callback.
238 void set_cancel_in_callback() {
239 cancel_in_callback_ = true;
242 // Mark to call MessageLoop::Quit() upon callback.
243 void set_quit_in_callback() {
244 quit_in_callback_ = true;
247 void StartTransaction(DnsTransactionFactory* factory) {
248 EXPECT_EQ(NULL, transaction_.get());
249 transaction_ = factory->CreateTransaction(
250 hostname_,
251 qtype_,
252 base::Bind(&TransactionHelper::OnTransactionComplete,
253 base::Unretained(this)),
254 BoundNetLog());
255 EXPECT_EQ(hostname_, transaction_->GetHostname());
256 EXPECT_EQ(qtype_, transaction_->GetType());
257 transaction_->Start();
260 void Cancel() {
261 ASSERT_TRUE(transaction_.get() != NULL);
262 transaction_.reset(NULL);
265 void OnTransactionComplete(DnsTransaction* t,
266 int rv,
267 const DnsResponse* response) {
268 EXPECT_FALSE(completed_);
269 EXPECT_EQ(transaction_.get(), t);
271 completed_ = true;
273 if (cancel_in_callback_) {
274 Cancel();
275 return;
278 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
279 if (quit_in_callback_)
280 base::MessageLoop::current()->Quit();
282 if (expected_answer_count_ >= 0) {
283 ASSERT_EQ(OK, rv);
284 ASSERT_TRUE(response != NULL);
285 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
286 response->answer_count());
287 EXPECT_EQ(qtype_, response->qtype());
289 DnsRecordParser parser = response->Parser();
290 DnsResourceRecord record;
291 for (int i = 0; i < expected_answer_count_; ++i) {
292 EXPECT_TRUE(parser.ReadRecord(&record));
294 } else {
295 EXPECT_EQ(expected_answer_count_, rv);
299 bool has_completed() const {
300 return completed_;
303 // Shorthands for commonly used commands.
305 bool Run(DnsTransactionFactory* factory) {
306 StartTransaction(factory);
307 base::MessageLoop::current()->RunUntilIdle();
308 return has_completed();
311 // Use when some of the responses are timeouts.
312 bool RunUntilDone(DnsTransactionFactory* factory) {
313 set_quit_in_callback();
314 StartTransaction(factory);
315 base::MessageLoop::current()->Run();
316 return has_completed();
319 private:
320 std::string hostname_;
321 uint16 qtype_;
322 scoped_ptr<DnsTransaction> transaction_;
323 int expected_answer_count_;
324 bool cancel_in_callback_;
325 bool quit_in_callback_;
327 bool completed_;
330 class DnsTransactionTest : public testing::Test {
331 public:
332 DnsTransactionTest() {}
334 // Generates |nameservers| for DnsConfig.
335 void ConfigureNumServers(unsigned num_servers) {
336 CHECK_LE(num_servers, 255u);
337 config_.nameservers.clear();
338 IPAddressNumber dns_ip;
340 bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
341 EXPECT_TRUE(rv);
343 for (unsigned i = 0; i < num_servers; ++i) {
344 dns_ip[3] = i;
345 config_.nameservers.push_back(IPEndPoint(dns_ip,
346 dns_protocol::kDefaultPort));
350 // Called after fully configuring |config|.
351 void ConfigureFactory() {
352 socket_factory_.reset(new TestSocketFactory());
353 session_ = new DnsSession(
354 config_,
355 DnsSocketPool::CreateNull(socket_factory_.get()),
356 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
357 NULL /* NetLog */);
358 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
361 void AddSocketData(scoped_ptr<DnsSocketData> data) {
362 CHECK(socket_factory_.get());
363 transaction_ids_.push_back(data->query_id());
364 socket_factory_->AddSocketDataProvider(data->GetProvider());
365 socket_data_.push_back(data.release());
368 // Add expected query for |dotted_name| and |qtype| with |id| and response
369 // taken verbatim from |data| of |data_length| bytes. The transaction id in
370 // |data| should equal |id|, unless testing mismatched response.
371 void AddQueryAndResponse(uint16 id,
372 const char* dotted_name,
373 uint16 qtype,
374 const uint8* response_data,
375 size_t response_length,
376 IoMode mode,
377 bool use_tcp) {
378 CHECK(socket_factory_.get());
379 scoped_ptr<DnsSocketData> data(
380 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
381 data->AddResponseData(response_data, response_length, mode);
382 AddSocketData(data.Pass());
385 void AddAsyncQueryAndResponse(uint16 id,
386 const char* dotted_name,
387 uint16 qtype,
388 const uint8* data,
389 size_t data_length) {
390 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
391 false);
394 void AddSyncQueryAndResponse(uint16 id,
395 const char* dotted_name,
396 uint16 qtype,
397 const uint8* data,
398 size_t data_length) {
399 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
400 false);
403 // Add expected query of |dotted_name| and |qtype| and no response.
404 void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) {
405 uint16 id = base::RandInt(0, kuint16max);
406 scoped_ptr<DnsSocketData> data(
407 new DnsSocketData(id, dotted_name, qtype, ASYNC, false));
408 AddSocketData(data.Pass());
411 // Add expected query of |dotted_name| and |qtype| and matching response with
412 // no answer and RCODE set to |rcode|. The id will be generated randomly.
413 void AddQueryAndRcode(const char* dotted_name,
414 uint16 qtype,
415 int rcode,
416 IoMode mode,
417 bool use_tcp) {
418 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
419 uint16 id = base::RandInt(0, kuint16max);
420 scoped_ptr<DnsSocketData> data(
421 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
422 data->AddRcode(rcode, mode);
423 AddSocketData(data.Pass());
426 void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
427 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false);
430 void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
431 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false);
434 // Checks if the sockets were connected in the order matching the indices in
435 // |servers|.
436 void CheckServerOrder(const unsigned* servers, size_t num_attempts) {
437 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
438 for (size_t i = 0; i < num_attempts; ++i) {
439 EXPECT_EQ(socket_factory_->remote_endpoints_[i],
440 session_->config().nameservers[servers[i]]);
444 virtual void SetUp() OVERRIDE {
445 // By default set one server,
446 ConfigureNumServers(1);
447 // and no retransmissions,
448 config_.attempts = 1;
449 // but long enough timeout for memory tests.
450 config_.timeout = TestTimeouts::action_timeout();
451 ConfigureFactory();
454 virtual void TearDown() OVERRIDE {
455 // Check that all socket data was at least written to.
456 for (size_t i = 0; i < socket_data_.size(); ++i) {
457 EXPECT_TRUE(socket_data_[i]->was_written()) << i;
461 protected:
462 int GetNextId(int min, int max) {
463 EXPECT_FALSE(transaction_ids_.empty());
464 int id = transaction_ids_.front();
465 transaction_ids_.pop_front();
466 EXPECT_GE(id, min);
467 EXPECT_LE(id, max);
468 return id;
471 DnsConfig config_;
473 ScopedVector<DnsSocketData> socket_data_;
475 std::deque<int> transaction_ids_;
476 scoped_ptr<TestSocketFactory> socket_factory_;
477 scoped_refptr<DnsSession> session_;
478 scoped_ptr<DnsTransactionFactory> transaction_factory_;
481 TEST_F(DnsTransactionTest, Lookup) {
482 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
483 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
485 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
486 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
489 // Concurrent lookup tests assume that DnsTransaction::Start immediately
490 // consumes a socket from ClientSocketFactory.
491 TEST_F(DnsTransactionTest, ConcurrentLookup) {
492 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
493 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
494 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
495 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
497 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
498 helper0.StartTransaction(transaction_factory_.get());
499 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
500 helper1.StartTransaction(transaction_factory_.get());
502 base::MessageLoop::current()->RunUntilIdle();
504 EXPECT_TRUE(helper0.has_completed());
505 EXPECT_TRUE(helper1.has_completed());
508 TEST_F(DnsTransactionTest, CancelLookup) {
509 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
510 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
511 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
512 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
514 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
515 helper0.StartTransaction(transaction_factory_.get());
516 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
517 helper1.StartTransaction(transaction_factory_.get());
519 helper0.Cancel();
521 base::MessageLoop::current()->RunUntilIdle();
523 EXPECT_FALSE(helper0.has_completed());
524 EXPECT_TRUE(helper1.has_completed());
527 TEST_F(DnsTransactionTest, DestroyFactory) {
528 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
529 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
531 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
532 helper0.StartTransaction(transaction_factory_.get());
534 // Destroying the client does not affect running requests.
535 transaction_factory_.reset(NULL);
537 base::MessageLoop::current()->RunUntilIdle();
539 EXPECT_TRUE(helper0.has_completed());
542 TEST_F(DnsTransactionTest, CancelFromCallback) {
543 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
544 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
546 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
547 helper0.set_cancel_in_callback();
548 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
551 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
552 config_.attempts = 2;
553 config_.timeout = TestTimeouts::tiny_timeout();
554 ConfigureFactory();
556 // Attempt receives mismatched response followed by valid response.
557 scoped_ptr<DnsSocketData> data(
558 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false));
559 data->AddResponseData(kT1ResponseDatagram,
560 arraysize(kT1ResponseDatagram), SYNCHRONOUS);
561 data->AddResponseData(kT0ResponseDatagram,
562 arraysize(kT0ResponseDatagram), SYNCHRONOUS);
563 AddSocketData(data.Pass());
565 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
566 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
569 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
570 config_.attempts = 2;
571 config_.timeout = TestTimeouts::tiny_timeout();
572 ConfigureFactory();
574 // First attempt receives mismatched response followed by valid response.
575 // Second attempt times out.
576 scoped_ptr<DnsSocketData> data(
577 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false));
578 data->AddResponseData(kT1ResponseDatagram,
579 arraysize(kT1ResponseDatagram), ASYNC);
580 data->AddResponseData(kT0ResponseDatagram,
581 arraysize(kT0ResponseDatagram), ASYNC);
582 AddSocketData(data.Pass());
583 AddQueryAndTimeout(kT0HostName, kT0Qtype);
585 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
586 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
589 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
590 config_.timeout = TestTimeouts::tiny_timeout();
591 ConfigureFactory();
593 // Attempt receives mismatched response but times out because only one attempt
594 // is allowed.
595 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
596 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
598 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
599 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
602 TEST_F(DnsTransactionTest, ServerFail) {
603 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
605 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
606 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
609 TEST_F(DnsTransactionTest, NoDomain) {
610 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
612 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
613 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
616 TEST_F(DnsTransactionTest, Timeout) {
617 config_.attempts = 3;
618 // Use short timeout to speed up the test.
619 config_.timeout = TestTimeouts::tiny_timeout();
620 ConfigureFactory();
622 AddQueryAndTimeout(kT0HostName, kT0Qtype);
623 AddQueryAndTimeout(kT0HostName, kT0Qtype);
624 AddQueryAndTimeout(kT0HostName, kT0Qtype);
626 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
627 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
628 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
631 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) {
632 // Test that we fallback on both server failure and timeout.
633 config_.attempts = 2;
634 // The next request should start from the next server.
635 config_.rotate = true;
636 ConfigureNumServers(3);
637 // Use short timeout to speed up the test.
638 config_.timeout = TestTimeouts::tiny_timeout();
639 ConfigureFactory();
641 // Responses for first request.
642 AddQueryAndTimeout(kT0HostName, kT0Qtype);
643 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
644 AddQueryAndTimeout(kT0HostName, kT0Qtype);
645 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
646 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
647 // Responses for second request.
648 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
649 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
650 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
652 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
653 TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED);
655 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
656 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
658 unsigned kOrder[] = {
659 0, 1, 2, 0, 1, // The first transaction.
660 1, 2, 0, // The second transaction starts from the next server.
662 CheckServerOrder(kOrder, arraysize(kOrder));
665 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
666 config_.ndots = 2;
667 config_.search.push_back("a");
668 config_.search.push_back("b");
669 config_.search.push_back("c");
670 config_.rotate = true;
671 ConfigureNumServers(2);
672 ConfigureFactory();
674 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
675 dns_protocol::kRcodeNXDOMAIN);
676 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
677 dns_protocol::kRcodeNXDOMAIN);
678 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
679 dns_protocol::kRcodeNXDOMAIN);
680 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
681 dns_protocol::kRcodeNXDOMAIN);
683 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
684 ERR_NAME_NOT_RESOLVED);
686 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
688 // Also check if suffix search causes server rotation.
689 unsigned kOrder0[] = { 0, 1, 0, 1 };
690 CheckServerOrder(kOrder0, arraysize(kOrder0));
693 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
694 config_.ndots = 2;
695 config_.search.push_back("a");
696 config_.search.push_back("b");
697 config_.search.push_back("c");
698 ConfigureFactory();
700 // Responses for first transaction.
701 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
702 dns_protocol::kRcodeNXDOMAIN);
703 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
704 dns_protocol::kRcodeNXDOMAIN);
705 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
706 dns_protocol::kRcodeNXDOMAIN);
707 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
708 dns_protocol::kRcodeNXDOMAIN);
709 // Responses for second transaction.
710 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
711 dns_protocol::kRcodeNXDOMAIN);
712 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
713 dns_protocol::kRcodeNXDOMAIN);
714 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
715 dns_protocol::kRcodeNXDOMAIN);
716 // Responses for third transaction.
717 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
718 dns_protocol::kRcodeNXDOMAIN);
720 TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
722 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
724 // A single-label name.
725 TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
727 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
729 // A fully-qualified name.
730 TransactionHelper helper2("x.", dns_protocol::kTypeAAAA,
731 ERR_NAME_NOT_RESOLVED);
733 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
736 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
737 // Responses for first transaction.
738 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
739 dns_protocol::kRcodeNXDOMAIN);
741 // A fully-qualified name.
742 TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
744 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
746 // A single label name is not even attempted.
747 TransactionHelper helper1("singlelabel", dns_protocol::kTypeA,
748 ERR_DNS_SEARCH_EMPTY);
750 helper1.Run(transaction_factory_.get());
751 EXPECT_TRUE(helper1.has_completed());
754 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
755 config_.search.push_back("a");
756 config_.search.push_back("b");
757 config_.search.push_back("c");
758 config_.append_to_multi_label_name = false;
759 ConfigureFactory();
761 // Responses for first transaction.
762 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
763 dns_protocol::kRcodeNXDOMAIN);
764 // Responses for second transaction.
765 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
766 dns_protocol::kRcodeNXDOMAIN);
767 // Responses for third transaction.
768 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
769 dns_protocol::kRcodeNXDOMAIN);
770 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
771 dns_protocol::kRcodeNXDOMAIN);
772 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
773 dns_protocol::kRcodeNXDOMAIN);
775 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
776 ERR_NAME_NOT_RESOLVED);
777 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
779 TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
780 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
782 TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
783 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
786 const uint8 kResponseNoData[] = {
787 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
788 // Question
789 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
790 // Authority section, SOA record, TTL 0x3E6
791 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
792 // Minimal RDATA, 18 bytes
793 0x00, 0x12,
794 0x00, 0x00,
795 0x00, 0x00, 0x00, 0x00,
796 0x00, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00,
801 TEST_F(DnsTransactionTest, SuffixSearchStop) {
802 config_.ndots = 2;
803 config_.search.push_back("a");
804 config_.search.push_back("b");
805 config_.search.push_back("c");
806 ConfigureFactory();
808 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
809 dns_protocol::kRcodeNXDOMAIN);
810 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
811 dns_protocol::kRcodeNXDOMAIN);
812 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
813 kResponseNoData, arraysize(kResponseNoData));
815 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */);
817 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
820 TEST_F(DnsTransactionTest, SyncFirstQuery) {
821 config_.search.push_back("lab.ccs.neu.edu");
822 config_.search.push_back("ccs.neu.edu");
823 ConfigureFactory();
825 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
826 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
828 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
829 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
832 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
833 config_.search.push_back("lab.ccs.neu.edu");
834 config_.search.push_back("ccs.neu.edu");
835 ConfigureFactory();
837 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
838 dns_protocol::kRcodeNXDOMAIN);
839 // "www.ccs.neu.edu"
840 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
841 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
843 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
844 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
847 TEST_F(DnsTransactionTest, SyncSearchQuery) {
848 config_.search.push_back("lab.ccs.neu.edu");
849 config_.search.push_back("ccs.neu.edu");
850 ConfigureFactory();
852 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
853 dns_protocol::kRcodeNXDOMAIN);
854 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
855 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
857 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
858 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
861 TEST_F(DnsTransactionTest, ConnectFailure) {
862 socket_factory_->fail_next_socket_ = true;
863 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
864 TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA,
865 ERR_CONNECTION_REFUSED);
866 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
869 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
870 // Retry after server failure.
871 config_.attempts = 2;
872 ConfigureFactory();
873 // First server connection attempt fails.
874 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
875 socket_factory_->fail_next_socket_ = true;
876 // Second DNS query succeeds.
877 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
878 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
879 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
880 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
883 TEST_F(DnsTransactionTest, TCPLookup) {
884 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
885 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
886 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
887 kT0ResponseDatagram, arraysize(kT0ResponseDatagram),
888 ASYNC, true /* use_tcp */);
890 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
891 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
894 TEST_F(DnsTransactionTest, TCPFailure) {
895 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
896 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
897 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
898 ASYNC, true /* use_tcp */);
900 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
901 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
904 TEST_F(DnsTransactionTest, TCPMalformed) {
905 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
906 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
907 scoped_ptr<DnsSocketData> data(
908 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
909 // Valid response but length too short.
910 // This must be truncated in the question section. The DnsResponse doesn't
911 // examine the answer section until asked to parse it, so truncating it in
912 // the answer section would result in the DnsTransaction itself succeeding.
913 data->AddResponseWithLength(
914 make_scoped_ptr(
915 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
916 arraysize(kT0ResponseDatagram), 0)),
917 ASYNC,
918 static_cast<uint16>(kT0QuerySize - 1));
919 AddSocketData(data.Pass());
921 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE);
922 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
925 TEST_F(DnsTransactionTest, TCPTimeout) {
926 config_.timeout = TestTimeouts::tiny_timeout();
927 ConfigureFactory();
928 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
929 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
930 AddSocketData(make_scoped_ptr(
931 new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true)));
933 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
934 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
937 TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) {
938 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
939 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
940 scoped_ptr<DnsSocketData> data(
941 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
942 // Return all but the last byte of the response.
943 data->AddResponseWithLength(
944 make_scoped_ptr(
945 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
946 arraysize(kT0ResponseDatagram) - 1, 0)),
947 ASYNC,
948 static_cast<uint16>(arraysize(kT0ResponseDatagram)));
949 // Then return a 0-length read.
950 data->AddReadError(0, ASYNC);
951 AddSocketData(data.Pass());
953 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
954 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
957 TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) {
958 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
959 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
960 scoped_ptr<DnsSocketData> data(
961 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
962 // Return all but the last byte of the response.
963 data->AddResponseWithLength(
964 make_scoped_ptr(
965 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
966 arraysize(kT0ResponseDatagram) - 1, 0)),
967 SYNCHRONOUS,
968 static_cast<uint16>(arraysize(kT0ResponseDatagram)));
969 // Then return a 0-length read.
970 data->AddReadError(0, SYNCHRONOUS);
971 AddSocketData(data.Pass());
973 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
974 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
977 TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) {
978 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
979 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
980 scoped_ptr<DnsSocketData> data(
981 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
982 data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC);
983 AddSocketData(data.Pass());
985 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
986 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
989 TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) {
990 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
991 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
992 scoped_ptr<DnsSocketData> data(
993 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
994 data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS);
995 AddSocketData(data.Pass());
997 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
998 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
1001 TEST_F(DnsTransactionTest, InvalidQuery) {
1002 config_.timeout = TestTimeouts::tiny_timeout();
1003 ConfigureFactory();
1005 TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT);
1006 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
1009 } // namespace
1011 } // namespace net