OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/dns/dns_transaction.h" | |
6 | |
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" | |
22 | |
23 namespace net { | |
24 | |
25 namespace { | |
26 | |
27 std::string DomainFromDot(const base::StringPiece& dotted) { | |
28 std::string out; | |
29 EXPECT_TRUE(DNSDomainFromDot(dotted, &out)); | |
30 return out; | |
31 } | |
32 | |
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()); | |
51 } | |
52 writes_.push_back(MockWrite(mode, | |
53 query_->io_buffer()->data(), | |
54 query_->io_buffer()->size())); | |
55 } | |
56 ~DnsSocketData() {} | |
57 | |
58 // All responses must be added before GetProvider. | |
59 | |
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()); | |
71 } | |
72 reads_.push_back(MockRead(mode, | |
73 response->io_buffer()->data(), | |
74 response->io_buffer()->size())); | |
75 responses_.push_back(response.release()); | |
76 } | |
77 | |
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); | |
82 } | |
83 | |
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); | |
89 } | |
90 | |
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); | |
101 } | |
102 | |
103 // Add error response. | |
104 void AddReadError(int error, IoMode mode) { | |
105 reads_.push_back(MockRead(mode, error)); | |
106 } | |
107 | |
108 // Build, if needed, and return the SocketDataProvider. No new responses | |
109 // should be added afterwards. | |
110 SocketDataProvider* GetProvider() { | |
111 if (provider_.get()) | |
112 return provider_.get(); | |
113 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to | |
114 // timeout. | |
115 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING)); | |
116 provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(), | |
117 &writes_[0], writes_.size())); | |
118 if (use_tcp_) { | |
119 provider_->set_connect_data(MockConnect(reads_[0].mode, OK)); | |
120 } | |
121 return provider_.get(); | |
122 } | |
123 | |
124 uint16 query_id() const { | |
125 return query_->id(); | |
126 } | |
127 | |
128 // Returns true if the expected query was written to the socket. | |
129 bool was_written() const { | |
130 CHECK(provider_.get()); | |
131 return provider_->write_index() > 0; | |
132 } | |
133 | |
134 private: | |
135 scoped_ptr<DnsQuery> query_; | |
136 bool use_tcp_; | |
137 ScopedVector<uint16> lengths_; | |
138 ScopedVector<DnsResponse> responses_; | |
139 std::vector<MockWrite> writes_; | |
140 std::vector<MockRead> reads_; | |
141 scoped_ptr<DelayedSocketData> provider_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(DnsSocketData); | |
144 }; | |
145 | |
146 class TestSocketFactory; | |
147 | |
148 // A variant of MockUDPClientSocket which always fails to Connect. | |
149 class FailingUDPClientSocket : public MockUDPClientSocket { | |
150 public: | |
151 FailingUDPClientSocket(SocketDataProvider* data, | |
152 net::NetLog* net_log) | |
153 : MockUDPClientSocket(data, net_log) { | |
154 } | |
155 ~FailingUDPClientSocket() override {} | |
156 int Connect(const IPEndPoint& endpoint) override { | |
157 return ERR_CONNECTION_REFUSED; | |
158 } | |
159 | |
160 private: | |
161 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket); | |
162 }; | |
163 | |
164 // A variant of MockUDPClientSocket which notifies the factory OnConnect. | |
165 class TestUDPClientSocket : public MockUDPClientSocket { | |
166 public: | |
167 TestUDPClientSocket(TestSocketFactory* factory, | |
168 SocketDataProvider* data, | |
169 net::NetLog* net_log) | |
170 : MockUDPClientSocket(data, net_log), factory_(factory) { | |
171 } | |
172 ~TestUDPClientSocket() override {} | |
173 int Connect(const IPEndPoint& endpoint) override; | |
174 | |
175 private: | |
176 TestSocketFactory* factory_; | |
177 | |
178 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket); | |
179 }; | |
180 | |
181 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect. | |
182 class TestSocketFactory : public MockClientSocketFactory { | |
183 public: | |
184 TestSocketFactory() : fail_next_socket_(false) {} | |
185 ~TestSocketFactory() override {} | |
186 | |
187 scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket( | |
188 DatagramSocket::BindType bind_type, | |
189 const RandIntCallback& rand_int_cb, | |
190 net::NetLog* net_log, | |
191 const net::NetLog::Source& source) override { | |
192 if (fail_next_socket_) { | |
193 fail_next_socket_ = false; | |
194 return scoped_ptr<DatagramClientSocket>( | |
195 new FailingUDPClientSocket(&empty_data_, net_log)); | |
196 } | |
197 SocketDataProvider* data_provider = mock_data().GetNext(); | |
198 scoped_ptr<TestUDPClientSocket> socket( | |
199 new TestUDPClientSocket(this, data_provider, net_log)); | |
200 data_provider->set_socket(socket.get()); | |
201 return socket.Pass(); | |
202 } | |
203 | |
204 void OnConnect(const IPEndPoint& endpoint) { | |
205 remote_endpoints_.push_back(endpoint); | |
206 } | |
207 | |
208 std::vector<IPEndPoint> remote_endpoints_; | |
209 bool fail_next_socket_; | |
210 | |
211 private: | |
212 StaticSocketDataProvider empty_data_; | |
213 | |
214 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory); | |
215 }; | |
216 | |
217 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) { | |
218 factory_->OnConnect(endpoint); | |
219 return MockUDPClientSocket::Connect(endpoint); | |
220 } | |
221 | |
222 // Helper class that holds a DnsTransaction and handles OnTransactionComplete. | |
223 class TransactionHelper { | |
224 public: | |
225 // If |expected_answer_count| < 0 then it is the expected net error. | |
226 TransactionHelper(const char* hostname, | |
227 uint16 qtype, | |
228 int expected_answer_count) | |
229 : hostname_(hostname), | |
230 qtype_(qtype), | |
231 expected_answer_count_(expected_answer_count), | |
232 cancel_in_callback_(false), | |
233 quit_in_callback_(false), | |
234 completed_(false) { | |
235 } | |
236 | |
237 // Mark that the transaction shall be destroyed immediately upon callback. | |
238 void set_cancel_in_callback() { | |
239 cancel_in_callback_ = true; | |
240 } | |
241 | |
242 // Mark to call MessageLoop::Quit() upon callback. | |
243 void set_quit_in_callback() { | |
244 quit_in_callback_ = true; | |
245 } | |
246 | |
247 void StartTransaction(DnsTransactionFactory* factory) { | |
248 EXPECT_EQ(NULL, transaction_.get()); | |
249 transaction_ = factory->CreateTransaction( | |
250 hostname_, | |
251 qtype_, | |
252 base::Bind(&TransactionHelper::OnTransactionComplete, | |
253 base::Unretained(this)), | |
254 BoundNetLog()); | |
255 EXPECT_EQ(hostname_, transaction_->GetHostname()); | |
256 EXPECT_EQ(qtype_, transaction_->GetType()); | |
257 transaction_->Start(); | |
258 } | |
259 | |
260 void Cancel() { | |
261 ASSERT_TRUE(transaction_.get() != NULL); | |
262 transaction_.reset(NULL); | |
263 } | |
264 | |
265 void OnTransactionComplete(DnsTransaction* t, | |
266 int rv, | |
267 const DnsResponse* response) { | |
268 EXPECT_FALSE(completed_); | |
269 EXPECT_EQ(transaction_.get(), t); | |
270 | |
271 completed_ = true; | |
272 | |
273 if (cancel_in_callback_) { | |
274 Cancel(); | |
275 return; | |
276 } | |
277 | |
278 // Tell MessageLoop to quit now, in case any ASSERT_* fails. | |
279 if (quit_in_callback_) | |
280 base::MessageLoop::current()->Quit(); | |
281 | |
282 if (expected_answer_count_ >= 0) { | |
283 ASSERT_EQ(OK, rv); | |
284 ASSERT_TRUE(response != NULL); | |
285 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_), | |
286 response->answer_count()); | |
287 EXPECT_EQ(qtype_, response->qtype()); | |
288 | |
289 DnsRecordParser parser = response->Parser(); | |
290 DnsResourceRecord record; | |
291 for (int i = 0; i < expected_answer_count_; ++i) { | |
292 EXPECT_TRUE(parser.ReadRecord(&record)); | |
293 } | |
294 } else { | |
295 EXPECT_EQ(expected_answer_count_, rv); | |
296 } | |
297 } | |
298 | |
299 bool has_completed() const { | |
300 return completed_; | |
301 } | |
302 | |
303 // Shorthands for commonly used commands. | |
304 | |
305 bool Run(DnsTransactionFactory* factory) { | |
306 StartTransaction(factory); | |
307 base::MessageLoop::current()->RunUntilIdle(); | |
308 return has_completed(); | |
309 } | |
310 | |
311 // Use when some of the responses are timeouts. | |
312 bool RunUntilDone(DnsTransactionFactory* factory) { | |
313 set_quit_in_callback(); | |
314 StartTransaction(factory); | |
315 base::MessageLoop::current()->Run(); | |
316 return has_completed(); | |
317 } | |
318 | |
319 private: | |
320 std::string hostname_; | |
321 uint16 qtype_; | |
322 scoped_ptr<DnsTransaction> transaction_; | |
323 int expected_answer_count_; | |
324 bool cancel_in_callback_; | |
325 bool quit_in_callback_; | |
326 | |
327 bool completed_; | |
328 }; | |
329 | |
330 class DnsTransactionTest : public testing::Test { | |
331 public: | |
332 DnsTransactionTest() {} | |
333 | |
334 // Generates |nameservers| for DnsConfig. | |
335 void ConfigureNumServers(unsigned num_servers) { | |
336 CHECK_LE(num_servers, 255u); | |
337 config_.nameservers.clear(); | |
338 IPAddressNumber dns_ip; | |
339 { | |
340 bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip); | |
341 EXPECT_TRUE(rv); | |
342 } | |
343 for (unsigned i = 0; i < num_servers; ++i) { | |
344 dns_ip[3] = i; | |
345 config_.nameservers.push_back(IPEndPoint(dns_ip, | |
346 dns_protocol::kDefaultPort)); | |
347 } | |
348 } | |
349 | |
350 // Called after fully configuring |config|. | |
351 void ConfigureFactory() { | |
352 socket_factory_.reset(new TestSocketFactory()); | |
353 session_ = new DnsSession( | |
354 config_, | |
355 DnsSocketPool::CreateNull(socket_factory_.get()), | |
356 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)), | |
357 NULL /* NetLog */); | |
358 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get()); | |
359 } | |
360 | |
361 void AddSocketData(scoped_ptr<DnsSocketData> data) { | |
362 CHECK(socket_factory_.get()); | |
363 transaction_ids_.push_back(data->query_id()); | |
364 socket_factory_->AddSocketDataProvider(data->GetProvider()); | |
365 socket_data_.push_back(data.release()); | |
366 } | |
367 | |
368 // Add expected query for |dotted_name| and |qtype| with |id| and response | |
369 // taken verbatim from |data| of |data_length| bytes. The transaction id in | |
370 // |data| should equal |id|, unless testing mismatched response. | |
371 void AddQueryAndResponse(uint16 id, | |
372 const char* dotted_name, | |
373 uint16 qtype, | |
374 const uint8* response_data, | |
375 size_t response_length, | |
376 IoMode mode, | |
377 bool use_tcp) { | |
378 CHECK(socket_factory_.get()); | |
379 scoped_ptr<DnsSocketData> data( | |
380 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp)); | |
381 data->AddResponseData(response_data, response_length, mode); | |
382 AddSocketData(data.Pass()); | |
383 } | |
384 | |
385 void AddAsyncQueryAndResponse(uint16 id, | |
386 const char* dotted_name, | |
387 uint16 qtype, | |
388 const uint8* data, | |
389 size_t data_length) { | |
390 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC, | |
391 false); | |
392 } | |
393 | |
394 void AddSyncQueryAndResponse(uint16 id, | |
395 const char* dotted_name, | |
396 uint16 qtype, | |
397 const uint8* data, | |
398 size_t data_length) { | |
399 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS, | |
400 false); | |
401 } | |
402 | |
403 // Add expected query of |dotted_name| and |qtype| and no response. | |
404 void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) { | |
405 uint16 id = base::RandInt(0, kuint16max); | |
406 scoped_ptr<DnsSocketData> data( | |
407 new DnsSocketData(id, dotted_name, qtype, ASYNC, false)); | |
408 AddSocketData(data.Pass()); | |
409 } | |
410 | |
411 // Add expected query of |dotted_name| and |qtype| and matching response with | |
412 // no answer and RCODE set to |rcode|. The id will be generated randomly. | |
413 void AddQueryAndRcode(const char* dotted_name, | |
414 uint16 qtype, | |
415 int rcode, | |
416 IoMode mode, | |
417 bool use_tcp) { | |
418 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode); | |
419 uint16 id = base::RandInt(0, kuint16max); | |
420 scoped_ptr<DnsSocketData> data( | |
421 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp)); | |
422 data->AddRcode(rcode, mode); | |
423 AddSocketData(data.Pass()); | |
424 } | |
425 | |
426 void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) { | |
427 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false); | |
428 } | |
429 | |
430 void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) { | |
431 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false); | |
432 } | |
433 | |
434 // Checks if the sockets were connected in the order matching the indices in | |
435 // |servers|. | |
436 void CheckServerOrder(const unsigned* servers, size_t num_attempts) { | |
437 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size()); | |
438 for (size_t i = 0; i < num_attempts; ++i) { | |
439 EXPECT_EQ(socket_factory_->remote_endpoints_[i], | |
440 session_->config().nameservers[servers[i]]); | |
441 } | |
442 } | |
443 | |
444 void SetUp() override { | |
445 // By default set one server, | |
446 ConfigureNumServers(1); | |
447 // and no retransmissions, | |
448 config_.attempts = 1; | |
449 // but long enough timeout for memory tests. | |
450 config_.timeout = TestTimeouts::action_timeout(); | |
451 ConfigureFactory(); | |
452 } | |
453 | |
454 void TearDown() override { | |
455 // Check that all socket data was at least written to. | |
456 for (size_t i = 0; i < socket_data_.size(); ++i) { | |
457 EXPECT_TRUE(socket_data_[i]->was_written()) << i; | |
458 } | |
459 } | |
460 | |
461 protected: | |
462 int GetNextId(int min, int max) { | |
463 EXPECT_FALSE(transaction_ids_.empty()); | |
464 int id = transaction_ids_.front(); | |
465 transaction_ids_.pop_front(); | |
466 EXPECT_GE(id, min); | |
467 EXPECT_LE(id, max); | |
468 return id; | |
469 } | |
470 | |
471 DnsConfig config_; | |
472 | |
473 ScopedVector<DnsSocketData> socket_data_; | |
474 | |
475 std::deque<int> transaction_ids_; | |
476 scoped_ptr<TestSocketFactory> socket_factory_; | |
477 scoped_refptr<DnsSession> session_; | |
478 scoped_ptr<DnsTransactionFactory> transaction_factory_; | |
479 }; | |
480 | |
481 TEST_F(DnsTransactionTest, Lookup) { | |
482 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
483 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
484 | |
485 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
486 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
487 } | |
488 | |
489 // Concurrent lookup tests assume that DnsTransaction::Start immediately | |
490 // consumes a socket from ClientSocketFactory. | |
491 TEST_F(DnsTransactionTest, ConcurrentLookup) { | |
492 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
493 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
494 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype, | |
495 kT1ResponseDatagram, arraysize(kT1ResponseDatagram)); | |
496 | |
497 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
498 helper0.StartTransaction(transaction_factory_.get()); | |
499 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount); | |
500 helper1.StartTransaction(transaction_factory_.get()); | |
501 | |
502 base::MessageLoop::current()->RunUntilIdle(); | |
503 | |
504 EXPECT_TRUE(helper0.has_completed()); | |
505 EXPECT_TRUE(helper1.has_completed()); | |
506 } | |
507 | |
508 TEST_F(DnsTransactionTest, CancelLookup) { | |
509 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
510 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
511 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype, | |
512 kT1ResponseDatagram, arraysize(kT1ResponseDatagram)); | |
513 | |
514 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
515 helper0.StartTransaction(transaction_factory_.get()); | |
516 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount); | |
517 helper1.StartTransaction(transaction_factory_.get()); | |
518 | |
519 helper0.Cancel(); | |
520 | |
521 base::MessageLoop::current()->RunUntilIdle(); | |
522 | |
523 EXPECT_FALSE(helper0.has_completed()); | |
524 EXPECT_TRUE(helper1.has_completed()); | |
525 } | |
526 | |
527 TEST_F(DnsTransactionTest, DestroyFactory) { | |
528 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
529 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
530 | |
531 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
532 helper0.StartTransaction(transaction_factory_.get()); | |
533 | |
534 // Destroying the client does not affect running requests. | |
535 transaction_factory_.reset(NULL); | |
536 | |
537 base::MessageLoop::current()->RunUntilIdle(); | |
538 | |
539 EXPECT_TRUE(helper0.has_completed()); | |
540 } | |
541 | |
542 TEST_F(DnsTransactionTest, CancelFromCallback) { | |
543 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
544 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
545 | |
546 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
547 helper0.set_cancel_in_callback(); | |
548 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
549 } | |
550 | |
551 TEST_F(DnsTransactionTest, MismatchedResponseSync) { | |
552 config_.attempts = 2; | |
553 config_.timeout = TestTimeouts::tiny_timeout(); | |
554 ConfigureFactory(); | |
555 | |
556 // Attempt receives mismatched response followed by valid response. | |
557 scoped_ptr<DnsSocketData> data( | |
558 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false)); | |
559 data->AddResponseData(kT1ResponseDatagram, | |
560 arraysize(kT1ResponseDatagram), SYNCHRONOUS); | |
561 data->AddResponseData(kT0ResponseDatagram, | |
562 arraysize(kT0ResponseDatagram), SYNCHRONOUS); | |
563 AddSocketData(data.Pass()); | |
564 | |
565 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
566 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
567 } | |
568 | |
569 TEST_F(DnsTransactionTest, MismatchedResponseAsync) { | |
570 config_.attempts = 2; | |
571 config_.timeout = TestTimeouts::tiny_timeout(); | |
572 ConfigureFactory(); | |
573 | |
574 // First attempt receives mismatched response followed by valid response. | |
575 // Second attempt times out. | |
576 scoped_ptr<DnsSocketData> data( | |
577 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false)); | |
578 data->AddResponseData(kT1ResponseDatagram, | |
579 arraysize(kT1ResponseDatagram), ASYNC); | |
580 data->AddResponseData(kT0ResponseDatagram, | |
581 arraysize(kT0ResponseDatagram), ASYNC); | |
582 AddSocketData(data.Pass()); | |
583 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
584 | |
585 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
586 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
587 } | |
588 | |
589 TEST_F(DnsTransactionTest, MismatchedResponseFail) { | |
590 config_.timeout = TestTimeouts::tiny_timeout(); | |
591 ConfigureFactory(); | |
592 | |
593 // Attempt receives mismatched response but times out because only one attempt | |
594 // is allowed. | |
595 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype, | |
596 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
597 | |
598 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); | |
599 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
600 } | |
601 | |
602 TEST_F(DnsTransactionTest, ServerFail) { | |
603 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
604 | |
605 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED); | |
606 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
607 } | |
608 | |
609 TEST_F(DnsTransactionTest, NoDomain) { | |
610 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); | |
611 | |
612 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); | |
613 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
614 } | |
615 | |
616 TEST_F(DnsTransactionTest, Timeout) { | |
617 config_.attempts = 3; | |
618 // Use short timeout to speed up the test. | |
619 config_.timeout = TestTimeouts::tiny_timeout(); | |
620 ConfigureFactory(); | |
621 | |
622 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
623 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
624 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
625 | |
626 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); | |
627 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
628 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); | |
629 } | |
630 | |
631 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { | |
632 // Test that we fallback on both server failure and timeout. | |
633 config_.attempts = 2; | |
634 // The next request should start from the next server. | |
635 config_.rotate = true; | |
636 ConfigureNumServers(3); | |
637 // Use short timeout to speed up the test. | |
638 config_.timeout = TestTimeouts::tiny_timeout(); | |
639 ConfigureFactory(); | |
640 | |
641 // Responses for first request. | |
642 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
643 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
644 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
645 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
646 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); | |
647 // Responses for second request. | |
648 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); | |
649 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); | |
650 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN); | |
651 | |
652 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); | |
653 TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED); | |
654 | |
655 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
656 EXPECT_TRUE(helper1.Run(transaction_factory_.get())); | |
657 | |
658 unsigned kOrder[] = { | |
659 0, 1, 2, 0, 1, // The first transaction. | |
660 1, 2, 0, // The second transaction starts from the next server. | |
661 }; | |
662 CheckServerOrder(kOrder, arraysize(kOrder)); | |
663 } | |
664 | |
665 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) { | |
666 config_.ndots = 2; | |
667 config_.search.push_back("a"); | |
668 config_.search.push_back("b"); | |
669 config_.search.push_back("c"); | |
670 config_.rotate = true; | |
671 ConfigureNumServers(2); | |
672 ConfigureFactory(); | |
673 | |
674 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, | |
675 dns_protocol::kRcodeNXDOMAIN); | |
676 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA, | |
677 dns_protocol::kRcodeNXDOMAIN); | |
678 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA, | |
679 dns_protocol::kRcodeNXDOMAIN); | |
680 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA, | |
681 dns_protocol::kRcodeNXDOMAIN); | |
682 | |
683 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, | |
684 ERR_NAME_NOT_RESOLVED); | |
685 | |
686 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
687 | |
688 // Also check if suffix search causes server rotation. | |
689 unsigned kOrder0[] = { 0, 1, 0, 1 }; | |
690 CheckServerOrder(kOrder0, arraysize(kOrder0)); | |
691 } | |
692 | |
693 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) { | |
694 config_.ndots = 2; | |
695 config_.search.push_back("a"); | |
696 config_.search.push_back("b"); | |
697 config_.search.push_back("c"); | |
698 ConfigureFactory(); | |
699 | |
700 // Responses for first transaction. | |
701 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA, | |
702 dns_protocol::kRcodeNXDOMAIN); | |
703 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA, | |
704 dns_protocol::kRcodeNXDOMAIN); | |
705 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA, | |
706 dns_protocol::kRcodeNXDOMAIN); | |
707 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA, | |
708 dns_protocol::kRcodeNXDOMAIN); | |
709 // Responses for second transaction. | |
710 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA, | |
711 dns_protocol::kRcodeNXDOMAIN); | |
712 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA, | |
713 dns_protocol::kRcodeNXDOMAIN); | |
714 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA, | |
715 dns_protocol::kRcodeNXDOMAIN); | |
716 // Responses for third transaction. | |
717 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA, | |
718 dns_protocol::kRcodeNXDOMAIN); | |
719 | |
720 TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
721 | |
722 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
723 | |
724 // A single-label name. | |
725 TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
726 | |
727 EXPECT_TRUE(helper1.Run(transaction_factory_.get())); | |
728 | |
729 // A fully-qualified name. | |
730 TransactionHelper helper2("x.", dns_protocol::kTypeAAAA, | |
731 ERR_NAME_NOT_RESOLVED); | |
732 | |
733 EXPECT_TRUE(helper2.Run(transaction_factory_.get())); | |
734 } | |
735 | |
736 TEST_F(DnsTransactionTest, EmptySuffixSearch) { | |
737 // Responses for first transaction. | |
738 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA, | |
739 dns_protocol::kRcodeNXDOMAIN); | |
740 | |
741 // A fully-qualified name. | |
742 TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
743 | |
744 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
745 | |
746 // A single label name is not even attempted. | |
747 TransactionHelper helper1("singlelabel", dns_protocol::kTypeA, | |
748 ERR_DNS_SEARCH_EMPTY); | |
749 | |
750 helper1.Run(transaction_factory_.get()); | |
751 EXPECT_TRUE(helper1.has_completed()); | |
752 } | |
753 | |
754 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) { | |
755 config_.search.push_back("a"); | |
756 config_.search.push_back("b"); | |
757 config_.search.push_back("c"); | |
758 config_.append_to_multi_label_name = false; | |
759 ConfigureFactory(); | |
760 | |
761 // Responses for first transaction. | |
762 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, | |
763 dns_protocol::kRcodeNXDOMAIN); | |
764 // Responses for second transaction. | |
765 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA, | |
766 dns_protocol::kRcodeNXDOMAIN); | |
767 // Responses for third transaction. | |
768 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA, | |
769 dns_protocol::kRcodeNXDOMAIN); | |
770 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA, | |
771 dns_protocol::kRcodeNXDOMAIN); | |
772 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA, | |
773 dns_protocol::kRcodeNXDOMAIN); | |
774 | |
775 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, | |
776 ERR_NAME_NOT_RESOLVED); | |
777 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
778 | |
779 TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
780 EXPECT_TRUE(helper1.Run(transaction_factory_.get())); | |
781 | |
782 TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
783 EXPECT_TRUE(helper2.Run(transaction_factory_.get())); | |
784 } | |
785 | |
786 const uint8 kResponseNoData[] = { | |
787 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | |
788 // Question | |
789 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, | |
790 // Authority section, SOA record, TTL 0x3E6 | |
791 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6, | |
792 // Minimal RDATA, 18 bytes | |
793 0x00, 0x12, | |
794 0x00, 0x00, | |
795 0x00, 0x00, 0x00, 0x00, | |
796 0x00, 0x00, 0x00, 0x00, | |
797 0x00, 0x00, 0x00, 0x00, | |
798 0x00, 0x00, 0x00, 0x00, | |
799 }; | |
800 | |
801 TEST_F(DnsTransactionTest, SuffixSearchStop) { | |
802 config_.ndots = 2; | |
803 config_.search.push_back("a"); | |
804 config_.search.push_back("b"); | |
805 config_.search.push_back("c"); | |
806 ConfigureFactory(); | |
807 | |
808 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, | |
809 dns_protocol::kRcodeNXDOMAIN); | |
810 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA, | |
811 dns_protocol::kRcodeNXDOMAIN); | |
812 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA, | |
813 kResponseNoData, arraysize(kResponseNoData)); | |
814 | |
815 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */); | |
816 | |
817 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
818 } | |
819 | |
820 TEST_F(DnsTransactionTest, SyncFirstQuery) { | |
821 config_.search.push_back("lab.ccs.neu.edu"); | |
822 config_.search.push_back("ccs.neu.edu"); | |
823 ConfigureFactory(); | |
824 | |
825 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
826 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
827 | |
828 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
829 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
830 } | |
831 | |
832 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) { | |
833 config_.search.push_back("lab.ccs.neu.edu"); | |
834 config_.search.push_back("ccs.neu.edu"); | |
835 ConfigureFactory(); | |
836 | |
837 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype, | |
838 dns_protocol::kRcodeNXDOMAIN); | |
839 // "www.ccs.neu.edu" | |
840 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype, | |
841 kT2ResponseDatagram, arraysize(kT2ResponseDatagram)); | |
842 | |
843 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount); | |
844 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
845 } | |
846 | |
847 TEST_F(DnsTransactionTest, SyncSearchQuery) { | |
848 config_.search.push_back("lab.ccs.neu.edu"); | |
849 config_.search.push_back("ccs.neu.edu"); | |
850 ConfigureFactory(); | |
851 | |
852 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA, | |
853 dns_protocol::kRcodeNXDOMAIN); | |
854 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype, | |
855 kT2ResponseDatagram, arraysize(kT2ResponseDatagram)); | |
856 | |
857 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount); | |
858 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
859 } | |
860 | |
861 TEST_F(DnsTransactionTest, ConnectFailure) { | |
862 socket_factory_->fail_next_socket_ = true; | |
863 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. | |
864 TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA, | |
865 ERR_CONNECTION_REFUSED); | |
866 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
867 } | |
868 | |
869 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) { | |
870 // Retry after server failure. | |
871 config_.attempts = 2; | |
872 ConfigureFactory(); | |
873 // First server connection attempt fails. | |
874 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. | |
875 socket_factory_->fail_next_socket_ = true; | |
876 // Second DNS query succeeds. | |
877 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
878 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
879 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
880 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
881 } | |
882 | |
883 TEST_F(DnsTransactionTest, TCPLookup) { | |
884 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
885 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
886 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
887 kT0ResponseDatagram, arraysize(kT0ResponseDatagram), | |
888 ASYNC, true /* use_tcp */); | |
889 | |
890 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
891 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
892 } | |
893 | |
894 TEST_F(DnsTransactionTest, TCPFailure) { | |
895 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
896 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
897 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, | |
898 ASYNC, true /* use_tcp */); | |
899 | |
900 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED); | |
901 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
902 } | |
903 | |
904 TEST_F(DnsTransactionTest, TCPMalformed) { | |
905 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
906 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
907 scoped_ptr<DnsSocketData> data( | |
908 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
909 // Valid response but length too short. | |
910 // This must be truncated in the question section. The DnsResponse doesn't | |
911 // examine the answer section until asked to parse it, so truncating it in | |
912 // the answer section would result in the DnsTransaction itself succeeding. | |
913 data->AddResponseWithLength( | |
914 make_scoped_ptr( | |
915 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), | |
916 arraysize(kT0ResponseDatagram), 0)), | |
917 ASYNC, | |
918 static_cast<uint16>(kT0QuerySize - 1)); | |
919 AddSocketData(data.Pass()); | |
920 | |
921 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE); | |
922 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
923 } | |
924 | |
925 TEST_F(DnsTransactionTest, TCPTimeout) { | |
926 config_.timeout = TestTimeouts::tiny_timeout(); | |
927 ConfigureFactory(); | |
928 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
929 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
930 AddSocketData(make_scoped_ptr( | |
931 new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true))); | |
932 | |
933 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); | |
934 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
935 } | |
936 | |
937 TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) { | |
938 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
939 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
940 scoped_ptr<DnsSocketData> data( | |
941 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
942 // Return all but the last byte of the response. | |
943 data->AddResponseWithLength( | |
944 make_scoped_ptr( | |
945 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), | |
946 arraysize(kT0ResponseDatagram) - 1, 0)), | |
947 ASYNC, | |
948 static_cast<uint16>(arraysize(kT0ResponseDatagram))); | |
949 // Then return a 0-length read. | |
950 data->AddReadError(0, ASYNC); | |
951 AddSocketData(data.Pass()); | |
952 | |
953 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
954 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
955 } | |
956 | |
957 TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) { | |
958 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
959 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
960 scoped_ptr<DnsSocketData> data( | |
961 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
962 // Return all but the last byte of the response. | |
963 data->AddResponseWithLength( | |
964 make_scoped_ptr( | |
965 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), | |
966 arraysize(kT0ResponseDatagram) - 1, 0)), | |
967 SYNCHRONOUS, | |
968 static_cast<uint16>(arraysize(kT0ResponseDatagram))); | |
969 // Then return a 0-length read. | |
970 data->AddReadError(0, SYNCHRONOUS); | |
971 AddSocketData(data.Pass()); | |
972 | |
973 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
974 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
975 } | |
976 | |
977 TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) { | |
978 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
979 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
980 scoped_ptr<DnsSocketData> data( | |
981 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
982 data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC); | |
983 AddSocketData(data.Pass()); | |
984 | |
985 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
986 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
987 } | |
988 | |
989 TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) { | |
990 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
991 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
992 scoped_ptr<DnsSocketData> data( | |
993 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
994 data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS); | |
995 AddSocketData(data.Pass()); | |
996 | |
997 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
998 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
999 } | |
1000 | |
1001 TEST_F(DnsTransactionTest, InvalidQuery) { | |
1002 config_.timeout = TestTimeouts::tiny_timeout(); | |
1003 ConfigureFactory(); | |
1004 | |
1005 TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT); | |
1006 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
1007 } | |
1008 | |
1009 } // namespace | |
1010 | |
1011 } // namespace net | |
OLD | NEW |