Telemetry: adding memory tests & solving problems on the go.
[chromium-blink-merge.git] / net / dns / dns_transaction_unittest.cc
blob0c5563a2a96352ed9906fbb18b6f62753839aa43
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/big_endian.h"
14 #include "net/base/dns_util.h"
15 #include "net/base/net_log.h"
16 #include "net/dns/dns_protocol.h"
17 #include "net/dns/dns_query.h"
18 #include "net/dns/dns_response.h"
19 #include "net/dns/dns_session.h"
20 #include "net/dns/dns_test_util.h"
21 #include "net/socket/socket_test_util.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace net {
26 namespace {
28 std::string DomainFromDot(const base::StringPiece& dotted) {
29 std::string out;
30 EXPECT_TRUE(DNSDomainFromDot(dotted, &out));
31 return out;
34 // A SocketDataProvider builder for MockUDPClientSocket. Each socket used by a
35 // DnsTransaction expects only one write and zero or more reads.
36 class DnsSocketData {
37 public:
38 // The ctor takes parameters for the DnsQuery.
39 DnsSocketData(uint16 id, const char* dotted_name, uint16 qtype, IoMode mode)
40 : query_(new DnsQuery(id, DomainFromDot(dotted_name), qtype)),
41 write_(mode, query_->io_buffer()->data(), query_->io_buffer()->size()) {
43 ~DnsSocketData() {}
45 // All responses must be added before GetProvider.
47 // Add pre-built DnsResponse.
48 void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) {
49 CHECK(!provider_.get());
50 reads_.push_back(MockRead(mode,
51 response->io_buffer()->data(),
52 response->io_buffer()->size()));
53 responses_.push_back(response.release());
56 // Adds pre-built response from |data| buffer.
57 void AddResponseData(const uint8* data, size_t length, IoMode mode) {
58 CHECK(!provider_.get());
59 AddResponse(make_scoped_ptr(
60 new DnsResponse(reinterpret_cast<const char*>(data), length, 0)), mode);
63 // Add no-answer (RCODE only) response matching the query.
64 void AddRcode(int rcode, IoMode mode) {
65 scoped_ptr<DnsResponse> response(
66 new DnsResponse(query_->io_buffer()->data(),
67 query_->io_buffer()->size(),
68 0));
69 dns_protocol::Header* header =
70 reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data());
71 header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode);
72 AddResponse(response.Pass(), mode);
75 // Build, if needed, and return the SocketDataProvider. No new responses
76 // should be added afterwards.
77 SocketDataProvider* GetProvider() {
78 if (provider_.get())
79 return provider_.get();
80 if (reads_.empty()) {
81 // Timeout.
82 provider_.reset(new DelayedSocketData(2, NULL, 0, &write_, 1));
83 } else {
84 // Terminate the reads with ERR_IO_PENDING to prevent overrun.
85 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
86 provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
87 &write_, 1));
89 return provider_.get();
92 uint16 query_id() const {
93 return query_->id();
96 // Returns true if the expected query was written to the socket.
97 bool was_written() const {
98 CHECK(provider_.get());
99 return provider_->write_index() > 0;
102 private:
103 scoped_ptr<DnsQuery> query_;
104 ScopedVector<DnsResponse> responses_;
105 MockWrite write_;
106 std::vector<MockRead> reads_;
107 scoped_ptr<DelayedSocketData> provider_;
109 DISALLOW_COPY_AND_ASSIGN(DnsSocketData);
112 class TestSocketFactory;
114 // A variant of MockUDPClientSocket which always fails to Connect.
115 class FailingUDPClientSocket : public MockUDPClientSocket {
116 public:
117 FailingUDPClientSocket(SocketDataProvider* data,
118 net::NetLog* net_log)
119 : MockUDPClientSocket(data, net_log) {
121 virtual ~FailingUDPClientSocket() {}
122 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE {
123 return ERR_CONNECTION_REFUSED;
126 private:
127 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket);
130 // A variant of MockUDPClientSocket which notifies the factory OnConnect.
131 class TestUDPClientSocket : public MockUDPClientSocket {
132 public:
133 TestUDPClientSocket(TestSocketFactory* factory,
134 SocketDataProvider* data,
135 net::NetLog* net_log)
136 : MockUDPClientSocket(data, net_log), factory_(factory) {
138 virtual ~TestUDPClientSocket() {}
139 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE;
141 private:
142 TestSocketFactory* factory_;
144 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket);
147 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
148 class TestSocketFactory : public MockClientSocketFactory {
149 public:
150 TestSocketFactory() : create_failing_sockets_(false) {}
151 virtual ~TestSocketFactory() {}
153 virtual DatagramClientSocket* CreateDatagramClientSocket(
154 DatagramSocket::BindType bind_type,
155 const RandIntCallback& rand_int_cb,
156 net::NetLog* net_log,
157 const net::NetLog::Source& source) OVERRIDE {
158 if (create_failing_sockets_)
159 return new FailingUDPClientSocket(&empty_data_, net_log);
160 SocketDataProvider* data_provider = mock_data().GetNext();
161 TestUDPClientSocket* socket = new TestUDPClientSocket(this,
162 data_provider,
163 net_log);
164 data_provider->set_socket(socket);
165 return socket;
168 void OnConnect(const IPEndPoint& endpoint) {
169 remote_endpoints_.push_back(endpoint);
172 std::vector<IPEndPoint> remote_endpoints_;
173 bool create_failing_sockets_;
175 private:
176 StaticSocketDataProvider empty_data_;
178 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory);
181 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
182 factory_->OnConnect(endpoint);
183 return MockUDPClientSocket::Connect(endpoint);
186 // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
187 class TransactionHelper {
188 public:
189 // If |expected_answer_count| < 0 then it is the expected net error.
190 TransactionHelper(const char* hostname,
191 uint16 qtype,
192 int expected_answer_count)
193 : hostname_(hostname),
194 qtype_(qtype),
195 expected_answer_count_(expected_answer_count),
196 cancel_in_callback_(false),
197 quit_in_callback_(false),
198 completed_(false) {
201 // Mark that the transaction shall be destroyed immediately upon callback.
202 void set_cancel_in_callback() {
203 cancel_in_callback_ = true;
206 // Mark to call MessageLoop::Quit() upon callback.
207 void set_quit_in_callback() {
208 quit_in_callback_ = true;
211 void StartTransaction(DnsTransactionFactory* factory) {
212 EXPECT_EQ(NULL, transaction_.get());
213 transaction_ = factory->CreateTransaction(
214 hostname_,
215 qtype_,
216 base::Bind(&TransactionHelper::OnTransactionComplete,
217 base::Unretained(this)),
218 BoundNetLog());
219 EXPECT_EQ(hostname_, transaction_->GetHostname());
220 EXPECT_EQ(qtype_, transaction_->GetType());
221 int rv = transaction_->Start();
222 if (rv != ERR_IO_PENDING) {
223 EXPECT_NE(OK, rv);
224 EXPECT_EQ(expected_answer_count_, rv);
225 completed_ = true;
229 void Cancel() {
230 ASSERT_TRUE(transaction_.get() != NULL);
231 transaction_.reset(NULL);
234 void OnTransactionComplete(DnsTransaction* t,
235 int rv,
236 const DnsResponse* response) {
237 EXPECT_FALSE(completed_);
238 EXPECT_EQ(transaction_.get(), t);
240 completed_ = true;
242 if (cancel_in_callback_) {
243 Cancel();
244 return;
247 // Tell MessageLoop to quit now, in case any ASSERT_* fails.
248 if (quit_in_callback_)
249 MessageLoop::current()->Quit();
251 if (expected_answer_count_ >= 0) {
252 ASSERT_EQ(OK, rv);
253 ASSERT_TRUE(response != NULL);
254 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
255 response->answer_count());
256 EXPECT_EQ(qtype_, response->qtype());
258 DnsRecordParser parser = response->Parser();
259 DnsResourceRecord record;
260 for (int i = 0; i < expected_answer_count_; ++i) {
261 EXPECT_TRUE(parser.ReadRecord(&record));
263 } else {
264 EXPECT_EQ(expected_answer_count_, rv);
268 bool has_completed() const {
269 return completed_;
272 // Shorthands for commonly used commands.
274 bool Run(DnsTransactionFactory* factory) {
275 StartTransaction(factory);
276 MessageLoop::current()->RunUntilIdle();
277 return has_completed();
280 // Use when some of the responses are timeouts.
281 bool RunUntilDone(DnsTransactionFactory* factory) {
282 set_quit_in_callback();
283 StartTransaction(factory);
284 MessageLoop::current()->Run();
285 return has_completed();
288 private:
289 std::string hostname_;
290 uint16 qtype_;
291 scoped_ptr<DnsTransaction> transaction_;
292 int expected_answer_count_;
293 bool cancel_in_callback_;
294 bool quit_in_callback_;
296 bool completed_;
299 class DnsTransactionTest : public testing::Test {
300 public:
301 DnsTransactionTest() : socket_factory_(NULL) {}
303 // Generates |nameservers| for DnsConfig.
304 void ConfigureNumServers(unsigned num_servers) {
305 CHECK_LE(num_servers, 255u);
306 config_.nameservers.clear();
307 IPAddressNumber dns_ip;
309 bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
310 EXPECT_TRUE(rv);
312 for (unsigned i = 0; i < num_servers; ++i) {
313 dns_ip[3] = i;
314 config_.nameservers.push_back(IPEndPoint(dns_ip,
315 dns_protocol::kDefaultPort));
319 // Called after fully configuring |config|.
320 void ConfigureFactory() {
321 socket_factory_.reset(new TestSocketFactory());
322 session_ = new DnsSession(
323 config_,
324 socket_factory_.get(),
325 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
326 NULL /* NetLog */);
327 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
330 void AddSocketData(scoped_ptr<DnsSocketData> data) {
331 transaction_ids_.push_back(data->query_id());
332 socket_factory_->AddSocketDataProvider(data->GetProvider());
333 socket_data_.push_back(data.release());
336 // Add expected query for |dotted_name| and |qtype| with |id| and response
337 // taken verbatim from |data| of |data_length| bytes. The transaction id in
338 // |data| should equal |id|, unless testing mismatched response.
339 void AddQueryAndResponse(uint16 id,
340 const char* dotted_name,
341 uint16 qtype,
342 const uint8* response_data,
343 size_t response_length,
344 IoMode mode) {
345 CHECK(socket_factory_.get());
346 scoped_ptr<DnsSocketData> data(
347 new DnsSocketData(id, dotted_name, qtype, mode));
348 data->AddResponseData(response_data, response_length, mode);
349 AddSocketData(data.Pass());
352 void AddAsyncQueryAndResponse(uint16 id,
353 const char* dotted_name,
354 uint16 qtype,
355 const uint8* data,
356 size_t data_length) {
357 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC);
360 void AddSyncQueryAndResponse(uint16 id,
361 const char* dotted_name,
362 uint16 qtype,
363 const uint8* data,
364 size_t data_length) {
365 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS);
368 // Add expected query of |dotted_name| and |qtype| and no response.
369 void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) {
370 CHECK(socket_factory_.get());
371 uint16 id = base::RandInt(0, kuint16max);
372 scoped_ptr<DnsSocketData> data(
373 new DnsSocketData(id, dotted_name, qtype, ASYNC));
374 AddSocketData(data.Pass());
377 // Add expected query of |dotted_name| and |qtype| and matching response with
378 // no answer and RCODE set to |rcode|. The id will be generated randomly.
379 void AddQueryAndRcode(const char* dotted_name,
380 uint16 qtype,
381 int rcode,
382 IoMode mode) {
383 CHECK(socket_factory_.get());
384 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
385 uint16 id = base::RandInt(0, kuint16max);
386 scoped_ptr<DnsSocketData> data(
387 new DnsSocketData(id, dotted_name, qtype, mode));
388 data->AddRcode(rcode, mode);
389 AddSocketData(data.Pass());
392 void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
393 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC);
396 void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
397 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS);
400 // Checks if the sockets were connected in the order matching the indices in
401 // |servers|.
402 void CheckServerOrder(const unsigned* servers, size_t num_attempts) {
403 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
404 for (size_t i = 0; i < num_attempts; ++i) {
405 EXPECT_EQ(socket_factory_->remote_endpoints_[i],
406 session_->config().nameservers[servers[i]]);
410 void SetUp() OVERRIDE {
411 // By default set one server,
412 ConfigureNumServers(1);
413 // and no retransmissions,
414 config_.attempts = 1;
415 // but long enough timeout for memory tests.
416 config_.timeout = TestTimeouts::action_timeout();
417 ConfigureFactory();
420 void TearDown() OVERRIDE {
421 // Check that all socket data was at least written to.
422 for (size_t i = 0; i < socket_data_.size(); ++i) {
423 EXPECT_TRUE(socket_data_[i]->was_written()) << i;
427 protected:
428 int GetNextId(int min, int max) {
429 EXPECT_FALSE(transaction_ids_.empty());
430 int id = transaction_ids_.front();
431 transaction_ids_.pop_front();
432 EXPECT_GE(id, min);
433 EXPECT_LE(id, max);
434 return id;
437 DnsConfig config_;
439 ScopedVector<DnsSocketData> socket_data_;
441 std::deque<int> transaction_ids_;
442 scoped_ptr<TestSocketFactory> socket_factory_;
443 scoped_refptr<DnsSession> session_;
444 scoped_ptr<DnsTransactionFactory> transaction_factory_;
447 TEST_F(DnsTransactionTest, Lookup) {
448 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
449 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
451 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
452 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
455 // Concurrent lookup tests assume that DnsTransaction::Start immediately
456 // consumes a socket from ClientSocketFactory.
457 TEST_F(DnsTransactionTest, ConcurrentLookup) {
458 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
459 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
460 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
461 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
463 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
464 helper0.StartTransaction(transaction_factory_.get());
465 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
466 helper1.StartTransaction(transaction_factory_.get());
468 MessageLoop::current()->RunUntilIdle();
470 EXPECT_TRUE(helper0.has_completed());
471 EXPECT_TRUE(helper1.has_completed());
474 TEST_F(DnsTransactionTest, CancelLookup) {
475 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
476 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
477 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
478 kT1ResponseDatagram, arraysize(kT1ResponseDatagram));
480 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
481 helper0.StartTransaction(transaction_factory_.get());
482 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount);
483 helper1.StartTransaction(transaction_factory_.get());
485 helper0.Cancel();
487 MessageLoop::current()->RunUntilIdle();
489 EXPECT_FALSE(helper0.has_completed());
490 EXPECT_TRUE(helper1.has_completed());
493 TEST_F(DnsTransactionTest, DestroyFactory) {
494 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
495 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
497 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
498 helper0.StartTransaction(transaction_factory_.get());
500 // Destroying the client does not affect running requests.
501 transaction_factory_.reset(NULL);
503 MessageLoop::current()->RunUntilIdle();
505 EXPECT_TRUE(helper0.has_completed());
508 TEST_F(DnsTransactionTest, CancelFromCallback) {
509 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
510 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
512 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
513 helper0.set_cancel_in_callback();
514 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
517 TEST_F(DnsTransactionTest, MismatchedResponseSync) {
518 config_.attempts = 2;
519 config_.timeout = TestTimeouts::tiny_timeout();
520 ConfigureFactory();
522 // Attempt receives mismatched response followed by valid response.
523 scoped_ptr<DnsSocketData> data(
524 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS));
525 data->AddResponseData(kT1ResponseDatagram,
526 arraysize(kT1ResponseDatagram), SYNCHRONOUS);
527 data->AddResponseData(kT0ResponseDatagram,
528 arraysize(kT0ResponseDatagram), SYNCHRONOUS);
529 AddSocketData(data.Pass());
531 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
532 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
535 TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
536 config_.attempts = 2;
537 config_.timeout = TestTimeouts::tiny_timeout();
538 ConfigureFactory();
540 // First attempt receives mismatched response followed by valid response.
541 // Second attempt times out.
542 scoped_ptr<DnsSocketData> data(
543 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC));
544 data->AddResponseData(kT1ResponseDatagram,
545 arraysize(kT1ResponseDatagram), ASYNC);
546 data->AddResponseData(kT0ResponseDatagram,
547 arraysize(kT0ResponseDatagram), ASYNC);
548 AddSocketData(data.Pass());
549 AddQueryAndTimeout(kT0HostName, kT0Qtype);
551 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
552 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
555 TEST_F(DnsTransactionTest, MismatchedResponseFail) {
556 config_.timeout = TestTimeouts::tiny_timeout();
557 ConfigureFactory();
559 // Attempt receives mismatched response but times out because only one attempt
560 // is allowed.
561 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
562 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
564 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
565 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
568 TEST_F(DnsTransactionTest, ServerFail) {
569 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
571 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
572 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
575 TEST_F(DnsTransactionTest, NoDomain) {
576 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
578 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
579 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
582 TEST_F(DnsTransactionTest, Timeout) {
583 config_.attempts = 3;
584 // Use short timeout to speed up the test.
585 config_.timeout = TestTimeouts::tiny_timeout();
586 ConfigureFactory();
588 AddQueryAndTimeout(kT0HostName, kT0Qtype);
589 AddQueryAndTimeout(kT0HostName, kT0Qtype);
590 AddQueryAndTimeout(kT0HostName, kT0Qtype);
592 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
593 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
594 MessageLoop::current()->AssertIdle();
597 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) {
598 // Test that we fallback on both server failure and timeout.
599 config_.attempts = 2;
600 // The next request should start from the next server.
601 config_.rotate = true;
602 ConfigureNumServers(3);
603 // Use short timeout to speed up the test.
604 config_.timeout = TestTimeouts::tiny_timeout();
605 ConfigureFactory();
607 // Responses for first request.
608 AddQueryAndTimeout(kT0HostName, kT0Qtype);
609 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
610 AddQueryAndTimeout(kT0HostName, kT0Qtype);
611 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
612 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
613 // Responses for second request.
614 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
615 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
617 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED);
618 TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED);
620 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
621 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
623 unsigned kOrder[] = {
624 0, 1, 2, 0, 1, // The first transaction.
625 1, 2, // The second transaction starts from the next server.
627 CheckServerOrder(kOrder, arraysize(kOrder));
630 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
631 config_.ndots = 2;
632 config_.search.push_back("a");
633 config_.search.push_back("b");
634 config_.search.push_back("c");
635 config_.rotate = true;
636 ConfigureNumServers(2);
637 ConfigureFactory();
639 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
640 dns_protocol::kRcodeNXDOMAIN);
641 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
642 dns_protocol::kRcodeNXDOMAIN);
643 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
644 dns_protocol::kRcodeNXDOMAIN);
645 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
646 dns_protocol::kRcodeNXDOMAIN);
648 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
649 ERR_NAME_NOT_RESOLVED);
651 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
653 // Also check if suffix search causes server rotation.
654 unsigned kOrder0[] = { 0, 1, 0, 1 };
655 CheckServerOrder(kOrder0, arraysize(kOrder0));
658 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
659 config_.ndots = 2;
660 config_.search.push_back("a");
661 config_.search.push_back("b");
662 config_.search.push_back("c");
663 ConfigureFactory();
665 // Responses for first transaction.
666 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
667 dns_protocol::kRcodeNXDOMAIN);
668 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
669 dns_protocol::kRcodeNXDOMAIN);
670 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
671 dns_protocol::kRcodeNXDOMAIN);
672 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
673 dns_protocol::kRcodeNXDOMAIN);
674 // Responses for second transaction.
675 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
676 dns_protocol::kRcodeNXDOMAIN);
677 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
678 dns_protocol::kRcodeNXDOMAIN);
679 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
680 dns_protocol::kRcodeNXDOMAIN);
681 // Responses for third transaction.
682 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
683 dns_protocol::kRcodeNXDOMAIN);
685 TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
687 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
689 // A single-label name.
690 TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
692 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
694 // A fully-qualified name.
695 TransactionHelper helper2("x.", dns_protocol::kTypeAAAA,
696 ERR_NAME_NOT_RESOLVED);
698 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
701 TEST_F(DnsTransactionTest, EmptySuffixSearch) {
702 // Responses for first transaction.
703 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
704 dns_protocol::kRcodeNXDOMAIN);
706 // A fully-qualified name.
707 TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
709 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
711 // A single label name is not even attempted.
712 TransactionHelper helper1("singlelabel", dns_protocol::kTypeA,
713 ERR_DNS_SEARCH_EMPTY);
715 helper1.StartTransaction(transaction_factory_.get());
716 EXPECT_TRUE(helper1.has_completed());
719 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
720 config_.search.push_back("a");
721 config_.search.push_back("b");
722 config_.search.push_back("c");
723 config_.append_to_multi_label_name = false;
724 ConfigureFactory();
726 // Responses for first transaction.
727 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
728 dns_protocol::kRcodeNXDOMAIN);
729 // Responses for second transaction.
730 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
731 dns_protocol::kRcodeNXDOMAIN);
732 // Responses for third transaction.
733 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
734 dns_protocol::kRcodeNXDOMAIN);
735 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
736 dns_protocol::kRcodeNXDOMAIN);
737 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
738 dns_protocol::kRcodeNXDOMAIN);
740 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA,
741 ERR_NAME_NOT_RESOLVED);
742 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
744 TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
745 EXPECT_TRUE(helper1.Run(transaction_factory_.get()));
747 TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED);
748 EXPECT_TRUE(helper2.Run(transaction_factory_.get()));
751 const uint8 kResponseNoData[] = {
752 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
753 // Question
754 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
755 // Authority section, SOA record, TTL 0x3E6
756 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
757 // Minimal RDATA, 18 bytes
758 0x00, 0x12,
759 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00,
762 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00,
766 TEST_F(DnsTransactionTest, SuffixSearchStop) {
767 config_.ndots = 2;
768 config_.search.push_back("a");
769 config_.search.push_back("b");
770 config_.search.push_back("c");
771 ConfigureFactory();
773 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
774 dns_protocol::kRcodeNXDOMAIN);
775 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
776 dns_protocol::kRcodeNXDOMAIN);
777 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
778 kResponseNoData, arraysize(kResponseNoData));
780 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */);
782 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
785 TEST_F(DnsTransactionTest, SyncFirstQuery) {
786 config_.search.push_back("lab.ccs.neu.edu");
787 config_.search.push_back("ccs.neu.edu");
788 ConfigureFactory();
790 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
791 kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
793 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
794 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
797 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
798 config_.search.push_back("lab.ccs.neu.edu");
799 config_.search.push_back("ccs.neu.edu");
800 ConfigureFactory();
802 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
803 dns_protocol::kRcodeNXDOMAIN);
804 // "www.ccs.neu.edu"
805 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
806 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
808 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
809 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
812 TEST_F(DnsTransactionTest, SyncSearchQuery) {
813 config_.search.push_back("lab.ccs.neu.edu");
814 config_.search.push_back("ccs.neu.edu");
815 ConfigureFactory();
817 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
818 dns_protocol::kRcodeNXDOMAIN);
819 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
820 kT2ResponseDatagram, arraysize(kT2ResponseDatagram));
822 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount);
823 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
826 TEST_F(DnsTransactionTest, ConnectFailure) {
827 socket_factory_->create_failing_sockets_ = true;
828 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
829 TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA,
830 ERR_CONNECTION_REFUSED);
831 EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
834 } // namespace
836 } // namespace net