Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / dns / dns_transaction_unittest.cc
blobf5a897390a5e640a992a2ce06f04c45983cb8772
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/dns/dns_protocol.h"
15 #include "net/dns/dns_query.h"
16 #include "net/dns/dns_response.h"
17 #include "net/dns/dns_session.h"
18 #include "net/dns/dns_test_util.h"
19 #include "net/log/net_log.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), num_reads_and_writes()));
50 lengths_.push_back(length.Pass());
52 writes_.push_back(MockWrite(mode, query_->io_buffer()->data(),
53 query_->io_buffer()->size(),
54 num_reads_and_writes()));
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), num_reads_and_writes()));
70 lengths_.push_back(length.Pass());
72 reads_.push_back(MockRead(mode, response->io_buffer()->data(),
73 response->io_buffer()->size(),
74 num_reads_and_writes()));
75 responses_.push_back(response.Pass());
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, num_reads_and_writes()));
108 // Build, if needed, and return the SocketDataProvider. No new responses
109 // should be added afterwards.
110 SequencedSocketData* 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(
116 MockRead(ASYNC, ERR_IO_PENDING, writes_.size() + reads_.size()));
117 provider_.reset(new SequencedSocketData(&reads_[0], reads_.size(),
118 &writes_[0], writes_.size()));
119 if (use_tcp_) {
120 provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
122 return provider_.get();
125 uint16 query_id() const {
126 return query_->id();
129 private:
130 size_t num_reads_and_writes() const { return reads_.size() + writes_.size(); }
132 scoped_ptr<DnsQuery> query_;
133 bool use_tcp_;
134 ScopedVector<uint16> lengths_;
135 ScopedVector<DnsResponse> responses_;
136 std::vector<MockWrite> writes_;
137 std::vector<MockRead> reads_;
138 scoped_ptr<SequencedSocketData> provider_;
140 DISALLOW_COPY_AND_ASSIGN(DnsSocketData);
143 class TestSocketFactory;
145 // A variant of MockUDPClientSocket which always fails to Connect.
146 class FailingUDPClientSocket : public MockUDPClientSocket {
147 public:
148 FailingUDPClientSocket(SocketDataProvider* data,
149 net::NetLog* net_log)
150 : MockUDPClientSocket(data, net_log) {
152 ~FailingUDPClientSocket() override {}
153 int Connect(const IPEndPoint& endpoint) override {
154 return ERR_CONNECTION_REFUSED;
157 private:
158 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket);
161 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
162 class TestUDPClientSocket : public MockUDPClientSocket {
163 public:
164 TestUDPClientSocket(TestSocketFactory* factory,
165 SocketDataProvider* data,
166 net::NetLog* net_log)
167 : MockUDPClientSocket(data, net_log), factory_(factory) {
169 ~TestUDPClientSocket() override {}
170 int Connect(const IPEndPoint& endpoint) override;
172 private:
173 TestSocketFactory* factory_;
175 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket);
178 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
179 class TestSocketFactory : public MockClientSocketFactory {
180 public:
181 TestSocketFactory() : fail_next_socket_(false) {}
182 ~TestSocketFactory() override {}
184 scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
185 DatagramSocket::BindType bind_type,
186 const RandIntCallback& rand_int_cb,
187 NetLog* net_log,
188 const NetLog::Source& source) override {
189 if (fail_next_socket_) {
190 fail_next_socket_ = false;
191 return scoped_ptr<DatagramClientSocket>(
192 new FailingUDPClientSocket(&empty_data_, net_log));
194 SocketDataProvider* data_provider = mock_data().GetNext();
195 scoped_ptr<TestUDPClientSocket> socket(
196 new TestUDPClientSocket(this, data_provider, net_log));
197 data_provider->set_socket(socket.get());
198 return socket.Pass();
201 void OnConnect(const IPEndPoint& endpoint) {
202 remote_endpoints_.push_back(endpoint);
205 std::vector<IPEndPoint> remote_endpoints_;
206 bool fail_next_socket_;
208 private:
209 StaticSocketDataProvider empty_data_;
211 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory);
214 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
215 factory_->OnConnect(endpoint);
216 return MockUDPClientSocket::Connect(endpoint);
219 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
220 class TransactionHelper {
221 public:
222 // If |expected_answer_count| < 0 then it is the expected net error.
223 TransactionHelper(const char* hostname,
224 uint16 qtype,
225 int expected_answer_count)
226 : hostname_(hostname),
227 qtype_(qtype),
228 expected_answer_count_(expected_answer_count),
229 cancel_in_callback_(false),
230 quit_in_callback_(false),
231 completed_(false) {
234 // Mark that the transaction shall be destroyed immediately upon callback.
235 void set_cancel_in_callback() {
236 cancel_in_callback_ = true;
239 // Mark to call MessageLoop::Quit() upon callback.
240 void set_quit_in_callback() {
241 quit_in_callback_ = true;
244 void StartTransaction(DnsTransactionFactory* factory) {
245 EXPECT_EQ(NULL, transaction_.get());
246 transaction_ = factory->CreateTransaction(
247 hostname_,
248 qtype_,
249 base::Bind(&TransactionHelper::OnTransactionComplete,
250 base::Unretained(this)),
251 BoundNetLog());
252 EXPECT_EQ(hostname_, transaction_->GetHostname());
253 EXPECT_EQ(qtype_, transaction_->GetType());
254 transaction_->Start();
257 void Cancel() {
258 ASSERT_TRUE(transaction_.get() != NULL);
259 transaction_.reset(NULL);
262 void OnTransactionComplete(DnsTransaction* t,
263 int rv,
264 const DnsResponse* response) {
265 EXPECT_FALSE(completed_);
266 EXPECT_EQ(transaction_.get(), t);
268 completed_ = true;
270 if (cancel_in_callback_) {
271 Cancel();
272 return;
275 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
276 if (quit_in_callback_)
277 base::MessageLoop::current()->Quit();
279 if (expected_answer_count_ >= 0) {
280 ASSERT_EQ(OK, rv);
281 ASSERT_TRUE(response != NULL);
282 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
283 response->answer_count());
284 EXPECT_EQ(qtype_, response->qtype());
286 DnsRecordParser parser = response->Parser();
287 DnsResourceRecord record;
288 for (int i = 0; i < expected_answer_count_; ++i) {
289 EXPECT_TRUE(parser.ReadRecord(&record));
291 } else {
292 EXPECT_EQ(expected_answer_count_, rv);
296 bool has_completed() const {
297 return completed_;
300 // Shorthands for commonly used commands.
302 bool Run(DnsTransactionFactory* factory) {
303 StartTransaction(factory);
304 base::MessageLoop::current()->RunUntilIdle();
305 return has_completed();
308 // Use when some of the responses are timeouts.
309 bool RunUntilDone(DnsTransactionFactory* factory) {
310 set_quit_in_callback();
311 StartTransaction(factory);
312 base::MessageLoop::current()->Run();
313 return has_completed();
316 private:
317 std::string hostname_;
318 uint16 qtype_;
319 scoped_ptr<DnsTransaction> transaction_;
320 int expected_answer_count_;
321 bool cancel_in_callback_;
322 bool quit_in_callback_;
324 bool completed_;
327 class DnsTransactionTest : public testing::Test {
328 public:
329 DnsTransactionTest() {}
331 // Generates |nameservers| for DnsConfig.
332 void ConfigureNumServers(unsigned num_servers) {
333 CHECK_LE(num_servers, 255u);
334 config_.nameservers.clear();
335 IPAddressNumber dns_ip;
337 bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
338 EXPECT_TRUE(rv);
340 for (unsigned i = 0; i < num_servers; ++i) {
341 dns_ip[3] = i;
342 config_.nameservers.push_back(IPEndPoint(dns_ip,
343 dns_protocol::kDefaultPort));
347 // Called after fully configuring |config|.
348 void ConfigureFactory() {
349 socket_factory_.reset(new TestSocketFactory());
350 session_ = new DnsSession(
351 config_,
352 DnsSocketPool::CreateNull(socket_factory_.get()),
353 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
354 NULL /* NetLog */);
355 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
358 void AddSocketData(scoped_ptr<DnsSocketData> data) {
359 CHECK(socket_factory_.get());
360 transaction_ids_.push_back(data->query_id());
361 socket_factory_->AddSocketDataProvider(data->GetProvider());
362 socket_data_.push_back(data.Pass());
365 // Add expected query for |dotted_name| and |qtype| with |id| and response
366 // taken verbatim from |data| of |data_length| bytes. The transaction id in
367 // |data| should equal |id|, unless testing mismatched response.
368 void AddQueryAndResponse(uint16 id,
369 const char* dotted_name,
370 uint16 qtype,
371 const uint8* response_data,
372 size_t response_length,
373 IoMode mode,
374 bool use_tcp) {
375 CHECK(socket_factory_.get());
376 scoped_ptr<DnsSocketData> data(
377 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
378 data->AddResponseData(response_data, response_length, mode);
379 AddSocketData(data.Pass());
382 void AddAsyncQueryAndResponse(uint16 id,
383 const char* dotted_name,
384 uint16 qtype,
385 const uint8* data,
386 size_t data_length) {
387 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
388 false);
391 void AddSyncQueryAndResponse(uint16 id,
392 const char* dotted_name,
393 uint16 qtype,
394 const uint8* data,
395 size_t data_length) {
396 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
397 false);
400 // Add expected query of |dotted_name| and |qtype| and no response.
401 void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) {
402 uint16 id = base::RandInt(0, kuint16max);
403 scoped_ptr<DnsSocketData> data(
404 new DnsSocketData(id, dotted_name, qtype, ASYNC, false));
405 AddSocketData(data.Pass());
408 // Add expected query of |dotted_name| and |qtype| and matching response with
409 // no answer and RCODE set to |rcode|. The id will be generated randomly.
410 void AddQueryAndRcode(const char* dotted_name,
411 uint16 qtype,
412 int rcode,
413 IoMode mode,
414 bool use_tcp) {
415 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
416 uint16 id = base::RandInt(0, kuint16max);
417 scoped_ptr<DnsSocketData> data(
418 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
419 data->AddRcode(rcode, mode);
420 AddSocketData(data.Pass());
423 void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
424 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false);
427 void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
428 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false);
431 // Checks if the sockets were connected in the order matching the indices in
432 // |servers|.
433 void CheckServerOrder(const unsigned* servers, size_t num_attempts) {
434 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
435 for (size_t i = 0; i < num_attempts; ++i) {
436 EXPECT_EQ(socket_factory_->remote_endpoints_[i],
437 session_->config().nameservers[servers[i]]);
441 void SetUp() override {
442 // By default set one server,
443 ConfigureNumServers(1);
444 // and no retransmissions,
445 config_.attempts = 1;
446 // but long enough timeout for memory tests.
447 config_.timeout = TestTimeouts::action_timeout();
448 ConfigureFactory();
451 void TearDown() override {
452 // Check that all socket data was at least written to.
453 for (size_t i = 0; i < socket_data_.size(); ++i) {
454 EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i;
458 protected:
459 int GetNextId(int min, int max) {
460 EXPECT_FALSE(transaction_ids_.empty());
461 int id = transaction_ids_.front();
462 transaction_ids_.pop_front();
463 EXPECT_GE(id, min);
464 EXPECT_LE(id, max);
465 return id;
468 DnsConfig config_;
470 ScopedVector<DnsSocketData> socket_data_;
472 std::deque<int> transaction_ids_;
473 scoped_ptr<TestSocketFactory> socket_factory_;
474 scoped_refptr<DnsSession> session_;
475 scoped_ptr<DnsTransactionFactory> transaction_factory_;
478 TEST_F(DnsTransactionTest, Lookup) {
479 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
480 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
482 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
483 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
486 // Concurrent lookup tests assume that DnsTransaction::Start immediately
487 // consumes a socket from ClientSocketFactory.
488 TEST_F(DnsTransactionTest, ConcurrentLookup) {
489 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
490 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
491 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
492 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
494 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
495 helper0.StartTransaction(transaction_factory_.get());
496 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
497 helper1.StartTransaction(transaction_factory_.get());
499 base::MessageLoop::current()->RunUntilIdle();
501 EXPECT_TRUE(helper0.has_completed());
502 EXPECT_TRUE(helper1.has_completed());
505 TEST_F(DnsTransactionTest, CancelLookup) {
506 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
507 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
508 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
509 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
511 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
512 helper0.StartTransaction(transaction_factory_.get());
513 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
514 helper1.StartTransaction(transaction_factory_.get());
516 helper0.Cancel();
517 // Since the transaction has been cancelled, the assocaited socket has been
518 // destroyed, so make sure the data provide does not attempt to callback
519 // to the socket.
520 // TODO(rch): Make the SocketDataProvider and MockSocket do this by default.
521 socket_data_[0]->GetProvider()->set_socket(nullptr);
523 base::MessageLoop::current()->RunUntilIdle();
525 EXPECT_FALSE(helper0.has_completed());
526 EXPECT_TRUE(helper1.has_completed());
529 TEST_F(DnsTransactionTest, DestroyFactory) {
530 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
531 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
533 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
534 helper0.StartTransaction(transaction_factory_.get());
536 // Destroying the client does not affect running requests.
537 transaction_factory_.reset(NULL);
539 base::MessageLoop::current()->RunUntilIdle();
541 EXPECT_TRUE(helper0.has_completed());
544 TEST_F(DnsTransactionTest, CancelFromCallback) {
545 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
546 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
548 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
549 helper0.set_cancel_in_callback();
550 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
553 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
554 config_.attempts = 2;
555 config_.timeout = TestTimeouts::tiny_timeout();
556 ConfigureFactory();
558 // Attempt receives mismatched response followed by valid response.
559 scoped_ptr<DnsSocketData> data(
560 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false));
561 data->AddResponseData(kT1ResponseDatagram,
562 arraysize(kT1ResponseDatagram), SYNCHRONOUS);
563 data->AddResponseData(kT0ResponseDatagram,
564 arraysize(kT0ResponseDatagram), SYNCHRONOUS);
565 AddSocketData(data.Pass());
567 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
568 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
571 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
572 config_.attempts = 2;
573 config_.timeout = TestTimeouts::tiny_timeout();
574 ConfigureFactory();
576 // First attempt receives mismatched response followed by valid response.
577 // Second attempt times out.
578 scoped_ptr<DnsSocketData> data(
579 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false));
580 data->AddResponseData(kT1ResponseDatagram,
581 arraysize(kT1ResponseDatagram), ASYNC);
582 data->AddResponseData(kT0ResponseDatagram,
583 arraysize(kT0ResponseDatagram), ASYNC);
584 AddSocketData(data.Pass());
585 AddQueryAndTimeout(kT0HostName, kT0Qtype);
587 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
588 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
591 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
592 config_.timeout = TestTimeouts::tiny_timeout();
593 ConfigureFactory();
595 // Attempt receives mismatched response but times out because only one attempt
596 // is allowed.
597 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
598 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
600 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
601 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
604 TEST_F(DnsTransactionTest, ServerFail) {
605 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
607 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
608 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
611 TEST_F(DnsTransactionTest, NoDomain) {
612 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
614 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
615 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
618 TEST_F(DnsTransactionTest, Timeout) {
619 config_.attempts = 3;
620 // Use short timeout to speed up the test.
621 config_.timeout = TestTimeouts::tiny_timeout();
622 ConfigureFactory();
624 AddQueryAndTimeout(kT0HostName, kT0Qtype);
625 AddQueryAndTimeout(kT0HostName, kT0Qtype);
626 AddQueryAndTimeout(kT0HostName, kT0Qtype);
628 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
629 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
630 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
633 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) {
634 // Test that we fallback on both server failure and timeout.
635 config_.attempts = 2;
636 // The next request should start from the next server.
637 config_.rotate = true;
638 ConfigureNumServers(3);
639 // Use short timeout to speed up the test.
640 config_.timeout = TestTimeouts::tiny_timeout();
641 ConfigureFactory();
643 // Responses for first request.
644 AddQueryAndTimeout(kT0HostName, kT0Qtype);
645 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
646 AddQueryAndTimeout(kT0HostName, kT0Qtype);
647 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
648 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
649 // Responses for second request.
650 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
651 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
652 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
654 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
655 TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED);
657 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
658 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
660 unsigned kOrder[] = {
661 0, 1, 2, 0, 1, // The first transaction.
662 1, 2, 0, // The second transaction starts from the next server.
664 CheckServerOrder(kOrder, arraysize(kOrder));
667 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
668 config_.ndots = 2;
669 config_.search.push_back("a");
670 config_.search.push_back("b");
671 config_.search.push_back("c");
672 config_.rotate = true;
673 ConfigureNumServers(2);
674 ConfigureFactory();
676 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
677 dns_protocol::kRcodeNXDOMAIN);
678 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
679 dns_protocol::kRcodeNXDOMAIN);
680 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
681 dns_protocol::kRcodeNXDOMAIN);
682 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
683 dns_protocol::kRcodeNXDOMAIN);
685 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
686 ERR_NAME_NOT_RESOLVED);
688 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
690 // Also check if suffix search causes server rotation.
691 unsigned kOrder0[] = { 0, 1, 0, 1 };
692 CheckServerOrder(kOrder0, arraysize(kOrder0));
695 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
696 config_.ndots = 2;
697 config_.search.push_back("a");
698 config_.search.push_back("b");
699 config_.search.push_back("c");
700 ConfigureFactory();
702 // Responses for first transaction.
703 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
704 dns_protocol::kRcodeNXDOMAIN);
705 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
706 dns_protocol::kRcodeNXDOMAIN);
707 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
708 dns_protocol::kRcodeNXDOMAIN);
709 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
710 dns_protocol::kRcodeNXDOMAIN);
711 // Responses for second transaction.
712 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
713 dns_protocol::kRcodeNXDOMAIN);
714 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
715 dns_protocol::kRcodeNXDOMAIN);
716 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
717 dns_protocol::kRcodeNXDOMAIN);
718 // Responses for third transaction.
719 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
720 dns_protocol::kRcodeNXDOMAIN);
722 TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
724 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
726 // A single-label name.
727 TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
729 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
731 // A fully-qualified name.
732 TransactionHelper helper2("x.", dns_protocol::kTypeAAAA,
733 ERR_NAME_NOT_RESOLVED);
735 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
738 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
739 // Responses for first transaction.
740 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
741 dns_protocol::kRcodeNXDOMAIN);
743 // A fully-qualified name.
744 TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
746 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
748 // A single label name is not even attempted.
749 TransactionHelper helper1("singlelabel", dns_protocol::kTypeA,
750 ERR_DNS_SEARCH_EMPTY);
752 helper1.Run(transaction_factory_.get());
753 EXPECT_TRUE(helper1.has_completed());
756 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
757 config_.search.push_back("a");
758 config_.search.push_back("b");
759 config_.search.push_back("c");
760 config_.append_to_multi_label_name = false;
761 ConfigureFactory();
763 // Responses for first transaction.
764 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
765 dns_protocol::kRcodeNXDOMAIN);
766 // Responses for second transaction.
767 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
768 dns_protocol::kRcodeNXDOMAIN);
769 // Responses for third transaction.
770 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
771 dns_protocol::kRcodeNXDOMAIN);
772 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
773 dns_protocol::kRcodeNXDOMAIN);
774 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
775 dns_protocol::kRcodeNXDOMAIN);
777 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
778 ERR_NAME_NOT_RESOLVED);
779 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
781 TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
782 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
784 TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
785 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
788 const uint8 kResponseNoData[] = {
789 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
790 // Question
791 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
792 // Authority section, SOA record, TTL 0x3E6
793 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
794 // Minimal RDATA, 18 bytes
795 0x00, 0x12,
796 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00,
799 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x00, 0x00,
803 TEST_F(DnsTransactionTest, SuffixSearchStop) {
804 config_.ndots = 2;
805 config_.search.push_back("a");
806 config_.search.push_back("b");
807 config_.search.push_back("c");
808 ConfigureFactory();
810 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
811 dns_protocol::kRcodeNXDOMAIN);
812 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
813 dns_protocol::kRcodeNXDOMAIN);
814 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
815 kResponseNoData, arraysize(kResponseNoData));
817 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */);
819 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
822 TEST_F(DnsTransactionTest, SyncFirstQuery) {
823 config_.search.push_back("lab.ccs.neu.edu");
824 config_.search.push_back("ccs.neu.edu");
825 ConfigureFactory();
827 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
828 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
830 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
831 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
834 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
835 config_.search.push_back("lab.ccs.neu.edu");
836 config_.search.push_back("ccs.neu.edu");
837 ConfigureFactory();
839 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
840 dns_protocol::kRcodeNXDOMAIN);
841 // "www.ccs.neu.edu"
842 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
843 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
845 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
846 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
849 TEST_F(DnsTransactionTest, SyncSearchQuery) {
850 config_.search.push_back("lab.ccs.neu.edu");
851 config_.search.push_back("ccs.neu.edu");
852 ConfigureFactory();
854 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
855 dns_protocol::kRcodeNXDOMAIN);
856 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
857 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
859 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
860 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
863 TEST_F(DnsTransactionTest, ConnectFailure) {
864 socket_factory_->fail_next_socket_ = true;
865 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
866 TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA,
867 ERR_CONNECTION_REFUSED);
868 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
871 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
872 // Retry after server failure.
873 config_.attempts = 2;
874 ConfigureFactory();
875 // First server connection attempt fails.
876 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
877 socket_factory_->fail_next_socket_ = true;
878 // Second DNS query succeeds.
879 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
880 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
881 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
882 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
885 TEST_F(DnsTransactionTest, TCPLookup) {
886 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
887 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
888 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
889 kT0ResponseDatagram, arraysize(kT0ResponseDatagram),
890 ASYNC, true /* use_tcp */);
892 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
893 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
896 TEST_F(DnsTransactionTest, TCPFailure) {
897 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
898 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
899 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
900 ASYNC, true /* use_tcp */);
902 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
903 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
906 TEST_F(DnsTransactionTest, TCPMalformed) {
907 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
908 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
909 scoped_ptr<DnsSocketData> data(
910 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
911 // Valid response but length too short.
912 // This must be truncated in the question section. The DnsResponse doesn't
913 // examine the answer section until asked to parse it, so truncating it in
914 // the answer section would result in the DnsTransaction itself succeeding.
915 data->AddResponseWithLength(
916 make_scoped_ptr(
917 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
918 arraysize(kT0ResponseDatagram), 0)),
919 ASYNC,
920 static_cast<uint16>(kT0QuerySize - 1));
921 AddSocketData(data.Pass());
923 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE);
924 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
927 TEST_F(DnsTransactionTest, TCPTimeout) {
928 config_.timeout = TestTimeouts::tiny_timeout();
929 ConfigureFactory();
930 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
931 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
932 AddSocketData(make_scoped_ptr(
933 new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true)));
935 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
936 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
939 TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) {
940 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
941 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
942 scoped_ptr<DnsSocketData> data(
943 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
944 // Return all but the last byte of the response.
945 data->AddResponseWithLength(
946 make_scoped_ptr(
947 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
948 arraysize(kT0ResponseDatagram) - 1, 0)),
949 ASYNC,
950 static_cast<uint16>(arraysize(kT0ResponseDatagram)));
951 // Then return a 0-length read.
952 data->AddReadError(0, ASYNC);
953 AddSocketData(data.Pass());
955 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
956 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
959 TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) {
960 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
961 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
962 scoped_ptr<DnsSocketData> data(
963 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
964 // Return all but the last byte of the response.
965 data->AddResponseWithLength(
966 make_scoped_ptr(
967 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
968 arraysize(kT0ResponseDatagram) - 1, 0)),
969 SYNCHRONOUS,
970 static_cast<uint16>(arraysize(kT0ResponseDatagram)));
971 // Then return a 0-length read.
972 data->AddReadError(0, SYNCHRONOUS);
973 AddSocketData(data.Pass());
975 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
976 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
979 TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) {
980 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
981 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
982 scoped_ptr<DnsSocketData> data(
983 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
984 data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC);
985 AddSocketData(data.Pass());
987 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
988 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
991 TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) {
992 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
993 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
994 scoped_ptr<DnsSocketData> data(
995 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
996 data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS);
997 AddSocketData(data.Pass());
999 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED);
1000 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
1003 TEST_F(DnsTransactionTest, InvalidQuery) {
1004 config_.timeout = TestTimeouts::tiny_timeout();
1005 ConfigureFactory();
1007 TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT);
1008 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
1011 } // namespace
1013 } // namespace net