Probably broke Win7 Tests (dbg)(6). http://build.chromium.org/p/chromium.win/builders...
[chromium-blink-merge.git] / net / dns / dns_transaction_unittest.cc
blob67a045719b054f08a865799fe6e4bcf44bcfe38a
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 // Build, if needed, and return the SocketDataProvider. No new responses
104 // should be added afterwards.
105 SocketDataProvider* GetProvider() {
106 if (provider_.get())
107 return provider_.get();
108 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
109 // timeout.
110 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
111 provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
112 &writes_[0], writes_.size()));
113 if (use_tcp_) {
114 provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
116 return provider_.get();
119 uint16 query_id() const {
120 return query_->id();
123 // Returns true if the expected query was written to the socket.
124 bool was_written() const {
125 CHECK(provider_.get());
126 return provider_->write_index() > 0;
129 private:
130 scoped_ptr<DnsQuery> query_;
131 bool use_tcp_;
132 ScopedVector<uint16> lengths_;
133 ScopedVector<DnsResponse> responses_;
134 std::vector<MockWrite> writes_;
135 std::vector<MockRead> reads_;
136 scoped_ptr<DelayedSocketData> provider_;
138 DISALLOW_COPY_AND_ASSIGN(DnsSocketData);
141 class TestSocketFactory;
143 // A variant of MockUDPClientSocket which always fails to Connect.
144 class FailingUDPClientSocket : public MockUDPClientSocket {
145 public:
146 FailingUDPClientSocket(SocketDataProvider* data,
147 net::NetLog* net_log)
148 : MockUDPClientSocket(data, net_log) {
150 virtual ~FailingUDPClientSocket() {}
151 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE {
152 return ERR_CONNECTION_REFUSED;
155 private:
156 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket);
159 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
160 class TestUDPClientSocket : public MockUDPClientSocket {
161 public:
162 TestUDPClientSocket(TestSocketFactory* factory,
163 SocketDataProvider* data,
164 net::NetLog* net_log)
165 : MockUDPClientSocket(data, net_log), factory_(factory) {
167 virtual ~TestUDPClientSocket() {}
168 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE;
170 private:
171 TestSocketFactory* factory_;
173 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket);
176 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
177 class TestSocketFactory : public MockClientSocketFactory {
178 public:
179 TestSocketFactory() : fail_next_socket_(false) {}
180 virtual ~TestSocketFactory() {}
182 virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
183 DatagramSocket::BindType bind_type,
184 const RandIntCallback& rand_int_cb,
185 net::NetLog* net_log,
186 const net::NetLog::Source& source) OVERRIDE {
187 if (fail_next_socket_) {
188 fail_next_socket_ = false;
189 return scoped_ptr<DatagramClientSocket>(
190 new FailingUDPClientSocket(&empty_data_, net_log));
192 SocketDataProvider* data_provider = mock_data().GetNext();
193 scoped_ptr<TestUDPClientSocket> socket(
194 new TestUDPClientSocket(this, data_provider, net_log));
195 data_provider->set_socket(socket.get());
196 return socket.PassAs<DatagramClientSocket>();
199 void OnConnect(const IPEndPoint& endpoint) {
200 remote_endpoints_.push_back(endpoint);
203 std::vector<IPEndPoint> remote_endpoints_;
204 bool fail_next_socket_;
206 private:
207 StaticSocketDataProvider empty_data_;
209 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory);
212 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
213 factory_->OnConnect(endpoint);
214 return MockUDPClientSocket::Connect(endpoint);
217 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
218 class TransactionHelper {
219 public:
220 // If |expected_answer_count| < 0 then it is the expected net error.
221 TransactionHelper(const char* hostname,
222 uint16 qtype,
223 int expected_answer_count)
224 : hostname_(hostname),
225 qtype_(qtype),
226 expected_answer_count_(expected_answer_count),
227 cancel_in_callback_(false),
228 quit_in_callback_(false),
229 completed_(false) {
232 // Mark that the transaction shall be destroyed immediately upon callback.
233 void set_cancel_in_callback() {
234 cancel_in_callback_ = true;
237 // Mark to call MessageLoop::Quit() upon callback.
238 void set_quit_in_callback() {
239 quit_in_callback_ = true;
242 void StartTransaction(DnsTransactionFactory* factory) {
243 EXPECT_EQ(NULL, transaction_.get());
244 transaction_ = factory->CreateTransaction(
245 hostname_,
246 qtype_,
247 base::Bind(&TransactionHelper::OnTransactionComplete,
248 base::Unretained(this)),
249 BoundNetLog());
250 EXPECT_EQ(hostname_, transaction_->GetHostname());
251 EXPECT_EQ(qtype_, transaction_->GetType());
252 transaction_->Start();
255 void Cancel() {
256 ASSERT_TRUE(transaction_.get() != NULL);
257 transaction_.reset(NULL);
260 void OnTransactionComplete(DnsTransaction* t,
261 int rv,
262 const DnsResponse* response) {
263 EXPECT_FALSE(completed_);
264 EXPECT_EQ(transaction_.get(), t);
266 completed_ = true;
268 if (cancel_in_callback_) {
269 Cancel();
270 return;
273 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
274 if (quit_in_callback_)
275 base::MessageLoop::current()->Quit();
277 if (expected_answer_count_ >= 0) {
278 ASSERT_EQ(OK, rv);
279 ASSERT_TRUE(response != NULL);
280 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
281 response->answer_count());
282 EXPECT_EQ(qtype_, response->qtype());
284 DnsRecordParser parser = response->Parser();
285 DnsResourceRecord record;
286 for (int i = 0; i < expected_answer_count_; ++i) {
287 EXPECT_TRUE(parser.ReadRecord(&record));
289 } else {
290 EXPECT_EQ(expected_answer_count_, rv);
294 bool has_completed() const {
295 return completed_;
298 // Shorthands for commonly used commands.
300 bool Run(DnsTransactionFactory* factory) {
301 StartTransaction(factory);
302 base::MessageLoop::current()->RunUntilIdle();
303 return has_completed();
306 // Use when some of the responses are timeouts.
307 bool RunUntilDone(DnsTransactionFactory* factory) {
308 set_quit_in_callback();
309 StartTransaction(factory);
310 base::MessageLoop::current()->Run();
311 return has_completed();
314 private:
315 std::string hostname_;
316 uint16 qtype_;
317 scoped_ptr<DnsTransaction> transaction_;
318 int expected_answer_count_;
319 bool cancel_in_callback_;
320 bool quit_in_callback_;
322 bool completed_;
325 class DnsTransactionTest : public testing::Test {
326 public:
327 DnsTransactionTest() {}
329 // Generates |nameservers| for DnsConfig.
330 void ConfigureNumServers(unsigned num_servers) {
331 CHECK_LE(num_servers, 255u);
332 config_.nameservers.clear();
333 IPAddressNumber dns_ip;
335 bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
336 EXPECT_TRUE(rv);
338 for (unsigned i = 0; i < num_servers; ++i) {
339 dns_ip[3] = i;
340 config_.nameservers.push_back(IPEndPoint(dns_ip,
341 dns_protocol::kDefaultPort));
345 // Called after fully configuring |config|.
346 void ConfigureFactory() {
347 socket_factory_.reset(new TestSocketFactory());
348 session_ = new DnsSession(
349 config_,
350 DnsSocketPool::CreateNull(socket_factory_.get()),
351 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
352 NULL /* NetLog */);
353 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
356 void AddSocketData(scoped_ptr<DnsSocketData> data) {
357 CHECK(socket_factory_.get());
358 transaction_ids_.push_back(data->query_id());
359 socket_factory_->AddSocketDataProvider(data->GetProvider());
360 socket_data_.push_back(data.release());
363 // Add expected query for |dotted_name| and |qtype| with |id| and response
364 // taken verbatim from |data| of |data_length| bytes. The transaction id in
365 // |data| should equal |id|, unless testing mismatched response.
366 void AddQueryAndResponse(uint16 id,
367 const char* dotted_name,
368 uint16 qtype,
369 const uint8* response_data,
370 size_t response_length,
371 IoMode mode,
372 bool use_tcp) {
373 CHECK(socket_factory_.get());
374 scoped_ptr<DnsSocketData> data(
375 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
376 data->AddResponseData(response_data, response_length, mode);
377 AddSocketData(data.Pass());
380 void AddAsyncQueryAndResponse(uint16 id,
381 const char* dotted_name,
382 uint16 qtype,
383 const uint8* data,
384 size_t data_length) {
385 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
386 false);
389 void AddSyncQueryAndResponse(uint16 id,
390 const char* dotted_name,
391 uint16 qtype,
392 const uint8* data,
393 size_t data_length) {
394 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
395 false);
398 // Add expected query of |dotted_name| and |qtype| and no response.
399 void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) {
400 uint16 id = base::RandInt(0, kuint16max);
401 scoped_ptr<DnsSocketData> data(
402 new DnsSocketData(id, dotted_name, qtype, ASYNC, false));
403 AddSocketData(data.Pass());
406 // Add expected query of |dotted_name| and |qtype| and matching response with
407 // no answer and RCODE set to |rcode|. The id will be generated randomly.
408 void AddQueryAndRcode(const char* dotted_name,
409 uint16 qtype,
410 int rcode,
411 IoMode mode,
412 bool use_tcp) {
413 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
414 uint16 id = base::RandInt(0, kuint16max);
415 scoped_ptr<DnsSocketData> data(
416 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
417 data->AddRcode(rcode, mode);
418 AddSocketData(data.Pass());
421 void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
422 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false);
425 void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
426 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false);
429 // Checks if the sockets were connected in the order matching the indices in
430 // |servers|.
431 void CheckServerOrder(const unsigned* servers, size_t num_attempts) {
432 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
433 for (size_t i = 0; i < num_attempts; ++i) {
434 EXPECT_EQ(socket_factory_->remote_endpoints_[i],
435 session_->config().nameservers[servers[i]]);
439 virtual void SetUp() OVERRIDE {
440 // By default set one server,
441 ConfigureNumServers(1);
442 // and no retransmissions,
443 config_.attempts = 1;
444 // but long enough timeout for memory tests.
445 config_.timeout = TestTimeouts::action_timeout();
446 ConfigureFactory();
449 virtual void TearDown() OVERRIDE {
450 // Check that all socket data was at least written to.
451 for (size_t i = 0; i < socket_data_.size(); ++i) {
452 EXPECT_TRUE(socket_data_[i]->was_written()) << i;
456 protected:
457 int GetNextId(int min, int max) {
458 EXPECT_FALSE(transaction_ids_.empty());
459 int id = transaction_ids_.front();
460 transaction_ids_.pop_front();
461 EXPECT_GE(id, min);
462 EXPECT_LE(id, max);
463 return id;
466 DnsConfig config_;
468 ScopedVector<DnsSocketData> socket_data_;
470 std::deque<int> transaction_ids_;
471 scoped_ptr<TestSocketFactory> socket_factory_;
472 scoped_refptr<DnsSession> session_;
473 scoped_ptr<DnsTransactionFactory> transaction_factory_;
476 TEST_F(DnsTransactionTest, Lookup) {
477 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
478 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
480 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
481 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
484 // Concurrent lookup tests assume that DnsTransaction::Start immediately
485 // consumes a socket from ClientSocketFactory.
486 TEST_F(DnsTransactionTest, ConcurrentLookup) {
487 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
488 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
489 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
490 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
492 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
493 helper0.StartTransaction(transaction_factory_.get());
494 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
495 helper1.StartTransaction(transaction_factory_.get());
497 base::MessageLoop::current()->RunUntilIdle();
499 EXPECT_TRUE(helper0.has_completed());
500 EXPECT_TRUE(helper1.has_completed());
503 TEST_F(DnsTransactionTest, CancelLookup) {
504 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
505 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
506 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
507 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
509 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
510 helper0.StartTransaction(transaction_factory_.get());
511 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
512 helper1.StartTransaction(transaction_factory_.get());
514 helper0.Cancel();
516 base::MessageLoop::current()->RunUntilIdle();
518 EXPECT_FALSE(helper0.has_completed());
519 EXPECT_TRUE(helper1.has_completed());
522 TEST_F(DnsTransactionTest, DestroyFactory) {
523 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
524 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
526 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
527 helper0.StartTransaction(transaction_factory_.get());
529 // Destroying the client does not affect running requests.
530 transaction_factory_.reset(NULL);
532 base::MessageLoop::current()->RunUntilIdle();
534 EXPECT_TRUE(helper0.has_completed());
537 TEST_F(DnsTransactionTest, CancelFromCallback) {
538 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
539 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
541 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
542 helper0.set_cancel_in_callback();
543 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
546 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
547 config_.attempts = 2;
548 config_.timeout = TestTimeouts::tiny_timeout();
549 ConfigureFactory();
551 // Attempt receives mismatched response followed by valid response.
552 scoped_ptr<DnsSocketData> data(
553 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false));
554 data->AddResponseData(kT1ResponseDatagram,
555 arraysize(kT1ResponseDatagram), SYNCHRONOUS);
556 data->AddResponseData(kT0ResponseDatagram,
557 arraysize(kT0ResponseDatagram), SYNCHRONOUS);
558 AddSocketData(data.Pass());
560 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
561 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
564 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
565 config_.attempts = 2;
566 config_.timeout = TestTimeouts::tiny_timeout();
567 ConfigureFactory();
569 // First attempt receives mismatched response followed by valid response.
570 // Second attempt times out.
571 scoped_ptr<DnsSocketData> data(
572 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false));
573 data->AddResponseData(kT1ResponseDatagram,
574 arraysize(kT1ResponseDatagram), ASYNC);
575 data->AddResponseData(kT0ResponseDatagram,
576 arraysize(kT0ResponseDatagram), ASYNC);
577 AddSocketData(data.Pass());
578 AddQueryAndTimeout(kT0HostName, kT0Qtype);
580 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
581 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
584 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
585 config_.timeout = TestTimeouts::tiny_timeout();
586 ConfigureFactory();
588 // Attempt receives mismatched response but times out because only one attempt
589 // is allowed.
590 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
591 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
593 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
594 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
597 TEST_F(DnsTransactionTest, ServerFail) {
598 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
600 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
601 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
604 TEST_F(DnsTransactionTest, NoDomain) {
605 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
607 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
608 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
611 TEST_F(DnsTransactionTest, Timeout) {
612 config_.attempts = 3;
613 // Use short timeout to speed up the test.
614 config_.timeout = TestTimeouts::tiny_timeout();
615 ConfigureFactory();
617 AddQueryAndTimeout(kT0HostName, kT0Qtype);
618 AddQueryAndTimeout(kT0HostName, kT0Qtype);
619 AddQueryAndTimeout(kT0HostName, kT0Qtype);
621 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
622 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
623 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
626 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) {
627 // Test that we fallback on both server failure and timeout.
628 config_.attempts = 2;
629 // The next request should start from the next server.
630 config_.rotate = true;
631 ConfigureNumServers(3);
632 // Use short timeout to speed up the test.
633 config_.timeout = TestTimeouts::tiny_timeout();
634 ConfigureFactory();
636 // Responses for first request.
637 AddQueryAndTimeout(kT0HostName, kT0Qtype);
638 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
639 AddQueryAndTimeout(kT0HostName, kT0Qtype);
640 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
641 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
642 // Responses for second request.
643 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
644 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
645 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
647 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
648 TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED);
650 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
651 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
653 unsigned kOrder[] = {
654 0, 1, 2, 0, 1, // The first transaction.
655 1, 2, 0, // The second transaction starts from the next server.
657 CheckServerOrder(kOrder, arraysize(kOrder));
660 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
661 config_.ndots = 2;
662 config_.search.push_back("a");
663 config_.search.push_back("b");
664 config_.search.push_back("c");
665 config_.rotate = true;
666 ConfigureNumServers(2);
667 ConfigureFactory();
669 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
670 dns_protocol::kRcodeNXDOMAIN);
671 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
672 dns_protocol::kRcodeNXDOMAIN);
673 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
674 dns_protocol::kRcodeNXDOMAIN);
675 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
676 dns_protocol::kRcodeNXDOMAIN);
678 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
679 ERR_NAME_NOT_RESOLVED);
681 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
683 // Also check if suffix search causes server rotation.
684 unsigned kOrder0[] = { 0, 1, 0, 1 };
685 CheckServerOrder(kOrder0, arraysize(kOrder0));
688 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
689 config_.ndots = 2;
690 config_.search.push_back("a");
691 config_.search.push_back("b");
692 config_.search.push_back("c");
693 ConfigureFactory();
695 // Responses for first transaction.
696 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
697 dns_protocol::kRcodeNXDOMAIN);
698 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
699 dns_protocol::kRcodeNXDOMAIN);
700 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
701 dns_protocol::kRcodeNXDOMAIN);
702 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
703 dns_protocol::kRcodeNXDOMAIN);
704 // Responses for second transaction.
705 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
706 dns_protocol::kRcodeNXDOMAIN);
707 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
708 dns_protocol::kRcodeNXDOMAIN);
709 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
710 dns_protocol::kRcodeNXDOMAIN);
711 // Responses for third transaction.
712 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
713 dns_protocol::kRcodeNXDOMAIN);
715 TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
717 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
719 // A single-label name.
720 TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
722 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
724 // A fully-qualified name.
725 TransactionHelper helper2("x.", dns_protocol::kTypeAAAA,
726 ERR_NAME_NOT_RESOLVED);
728 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
731 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
732 // Responses for first transaction.
733 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
734 dns_protocol::kRcodeNXDOMAIN);
736 // A fully-qualified name.
737 TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
739 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
741 // A single label name is not even attempted.
742 TransactionHelper helper1("singlelabel", dns_protocol::kTypeA,
743 ERR_DNS_SEARCH_EMPTY);
745 helper1.Run(transaction_factory_.get());
746 EXPECT_TRUE(helper1.has_completed());
749 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
750 config_.search.push_back("a");
751 config_.search.push_back("b");
752 config_.search.push_back("c");
753 config_.append_to_multi_label_name = false;
754 ConfigureFactory();
756 // Responses for first transaction.
757 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
758 dns_protocol::kRcodeNXDOMAIN);
759 // Responses for second transaction.
760 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
761 dns_protocol::kRcodeNXDOMAIN);
762 // Responses for third transaction.
763 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
764 dns_protocol::kRcodeNXDOMAIN);
765 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
766 dns_protocol::kRcodeNXDOMAIN);
767 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
768 dns_protocol::kRcodeNXDOMAIN);
770 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
771 ERR_NAME_NOT_RESOLVED);
772 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
774 TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
775 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
777 TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
778 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
781 const uint8 kResponseNoData[] = {
782 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
783 // Question
784 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
785 // Authority section, SOA record, TTL 0x3E6
786 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
787 // Minimal RDATA, 18 bytes
788 0x00, 0x12,
789 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00,
791 0x00, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00,
793 0x00, 0x00, 0x00, 0x00,
796 TEST_F(DnsTransactionTest, SuffixSearchStop) {
797 config_.ndots = 2;
798 config_.search.push_back("a");
799 config_.search.push_back("b");
800 config_.search.push_back("c");
801 ConfigureFactory();
803 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
804 dns_protocol::kRcodeNXDOMAIN);
805 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
806 dns_protocol::kRcodeNXDOMAIN);
807 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
808 kResponseNoData, arraysize(kResponseNoData));
810 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */);
812 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
815 TEST_F(DnsTransactionTest, SyncFirstQuery) {
816 config_.search.push_back("lab.ccs.neu.edu");
817 config_.search.push_back("ccs.neu.edu");
818 ConfigureFactory();
820 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
821 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
823 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
824 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
827 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
828 config_.search.push_back("lab.ccs.neu.edu");
829 config_.search.push_back("ccs.neu.edu");
830 ConfigureFactory();
832 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
833 dns_protocol::kRcodeNXDOMAIN);
834 // "www.ccs.neu.edu"
835 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
836 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
838 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
839 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
842 TEST_F(DnsTransactionTest, SyncSearchQuery) {
843 config_.search.push_back("lab.ccs.neu.edu");
844 config_.search.push_back("ccs.neu.edu");
845 ConfigureFactory();
847 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
848 dns_protocol::kRcodeNXDOMAIN);
849 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
850 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
852 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
853 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
856 TEST_F(DnsTransactionTest, ConnectFailure) {
857 socket_factory_->fail_next_socket_ = true;
858 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
859 TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA,
860 ERR_CONNECTION_REFUSED);
861 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
864 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
865 // Retry after server failure.
866 config_.attempts = 2;
867 ConfigureFactory();
868 // First server connection attempt fails.
869 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
870 socket_factory_->fail_next_socket_ = true;
871 // Second DNS query succeeds.
872 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
873 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
874 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
875 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
878 TEST_F(DnsTransactionTest, TCPLookup) {
879 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
880 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
881 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
882 kT0ResponseDatagram, arraysize(kT0ResponseDatagram),
883 ASYNC, true /* use_tcp */);
885 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
886 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
889 TEST_F(DnsTransactionTest, TCPFailure) {
890 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
891 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
892 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
893 ASYNC, true /* use_tcp */);
895 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
896 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
899 TEST_F(DnsTransactionTest, TCPMalformed) {
900 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
901 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
902 scoped_ptr<DnsSocketData> data(
903 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
904 // Valid response but length too short.
905 data->AddResponseWithLength(
906 make_scoped_ptr(
907 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
908 arraysize(kT0ResponseDatagram), 0)),
909 ASYNC,
910 static_cast<uint16>(kT0QuerySize - 1));
911 AddSocketData(data.Pass());
913 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE);
914 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
917 TEST_F(DnsTransactionTest, TCPTimeout) {
918 config_.timeout = TestTimeouts::tiny_timeout();
919 ConfigureFactory();
920 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
921 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
922 AddSocketData(make_scoped_ptr(
923 new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true)));
925 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
926 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
929 TEST_F(DnsTransactionTest, InvalidQuery) {
930 config_.timeout = TestTimeouts::tiny_timeout();
931 ConfigureFactory();
933 TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT);
934 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
937 } // namespace
939 } // namespace net