Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/dns/dns_transaction.h" | 5 #include "net/dns/dns_transaction.h" |
| 6 | 6 |
| 7 #include <deque> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.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/test/test_timeouts.h" | 11 #include "base/test/test_timeouts.h" |
| 12 #include "base/time.h" | 12 #include "net/base/big_endian.h" |
| 13 #include "net/base/net_log.h" | |
| 14 #include "net/base/sys_addrinfo.h" | |
| 15 #include "net/base/dns_util.h" | |
| 16 #include "net/base/net_log.h" | |
| 13 #include "net/dns/dns_protocol.h" | 17 #include "net/dns/dns_protocol.h" |
| 14 #include "net/dns/dns_query.h" | 18 #include "net/dns/dns_query.h" |
| 15 #include "net/dns/dns_response.h" | 19 #include "net/dns/dns_response.h" |
| 16 #include "net/dns/dns_session.h" | 20 #include "net/dns/dns_session.h" |
| 17 #include "net/dns/dns_test_util.h" | 21 #include "net/dns/dns_test_util.h" |
| 18 #include "net/socket/socket_test_util.h" | 22 #include "net/socket/socket_test_util.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 24 |
| 21 namespace net { | 25 namespace net { |
| 22 | 26 |
| 23 namespace { | 27 namespace { |
| 24 | 28 |
| 25 // A mock for RandIntCallback that always returns 0. | 29 std::string DomainFromDot(const base::StringPiece& dotted) { |
| 26 int ReturnZero(int min, int max) { | 30 std::string out; |
| 27 return 0; | 31 EXPECT_TRUE(DNSDomainFromDot(dotted, &out)); |
| 28 } | 32 return out; |
| 33 } | |
| 34 | |
| 35 class TestSocketFactory; | |
| 36 | |
| 37 // A variant of MockUDPClientSocket which notifies the factory OnConnect. | |
| 38 class TestUDPClientSocket : public MockUDPClientSocket { | |
|
cbentzel
2012/01/21 03:41:16
I wonder if it would make more sense to add a peer
szym
2012/01/25 18:04:38
I'll put it on my list. I would actually like to r
| |
| 39 public: | |
| 40 TestUDPClientSocket(TestSocketFactory* factory, | |
| 41 SocketDataProvider* data, | |
| 42 net::NetLog* net_log) | |
| 43 : MockUDPClientSocket(data, net_log), factory_(factory) { | |
| 44 } | |
| 45 virtual ~TestUDPClientSocket() {} | |
| 46 virtual int Connect(const IPEndPoint& endpoint) OVERRIDE; | |
| 47 private: | |
| 48 TestSocketFactory* factory_; | |
| 49 }; | |
| 50 | |
| 51 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect. | |
| 52 class TestSocketFactory : public MockClientSocketFactory { | |
| 53 public: | |
| 54 TestSocketFactory() {} | |
| 55 virtual ~TestSocketFactory() {} | |
| 56 | |
| 57 virtual DatagramClientSocket* CreateDatagramClientSocket( | |
| 58 DatagramSocket::BindType bind_type, | |
| 59 const RandIntCallback& rand_int_cb, | |
| 60 net::NetLog* net_log, | |
| 61 const net::NetLog::Source& source) OVERRIDE { | |
| 62 SocketDataProvider* data_provider = mock_data().GetNext(); | |
| 63 TestUDPClientSocket* socket = new TestUDPClientSocket(this, | |
| 64 data_provider, | |
| 65 net_log); | |
| 66 data_provider->set_socket(socket); | |
| 67 return socket; | |
| 68 } | |
| 69 | |
| 70 void OnConnect(const IPEndPoint& endpoint) { | |
| 71 remote_endpoints.push_back(endpoint); | |
| 72 } | |
| 73 | |
| 74 std::vector<IPEndPoint> remote_endpoints; | |
| 75 }; | |
| 76 | |
| 77 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) { | |
| 78 factory_->OnConnect(endpoint); | |
| 79 return MockUDPClientSocket::Connect(endpoint); | |
| 80 } | |
| 81 | |
| 82 // Helper class that holds a DnsTransaction and handles OnTransactionComplete. | |
| 83 class TransactionHelper { | |
| 84 public: | |
| 85 // If |expected_answer_count| < 0 then it is the expected net error. | |
| 86 TransactionHelper(const char* hostname, | |
| 87 uint16 qtype, | |
| 88 int expected_answer_count) | |
| 89 : hostname_(hostname), | |
| 90 qtype_(qtype), | |
| 91 expected_answer_count_(expected_answer_count), | |
| 92 cancel_in_callback_(false), | |
| 93 quit_in_callback_(false), | |
| 94 completed_(false) { | |
| 95 } | |
| 96 | |
| 97 // Mark that the transaction shall be destroyed immediately upon callback. | |
| 98 void set_cancel_in_callback() { | |
| 99 cancel_in_callback_ = true; | |
| 100 } | |
| 101 | |
| 102 // Mark to call MessageLoop::Quit() upon callback. | |
| 103 void set_quit_in_callback() { | |
| 104 quit_in_callback_ = true; | |
| 105 } | |
| 106 | |
| 107 void StartTransaction(DnsTransactionFactory* factory) { | |
| 108 EXPECT_EQ(NULL, transaction_.get()); | |
| 109 transaction_ = factory->CreateTransaction( | |
| 110 hostname_, | |
| 111 qtype_, | |
| 112 base::Bind(&TransactionHelper::OnTransactionComplete, | |
| 113 base::Unretained(this)), | |
| 114 BoundNetLog()); | |
| 115 EXPECT_EQ(hostname_, transaction_->GetHostname()); | |
| 116 EXPECT_EQ(qtype_, transaction_->GetType()); | |
| 117 int rv = transaction_->Start(); | |
| 118 if (rv != ERR_IO_PENDING) { | |
| 119 EXPECT_NE(OK, rv); | |
| 120 EXPECT_EQ(expected_answer_count_, rv); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 void Cancel() { | |
| 125 ASSERT_TRUE(transaction_.get() != NULL); | |
| 126 transaction_.reset(NULL); | |
| 127 } | |
| 128 | |
| 129 void OnTransactionComplete(DnsTransaction* t, | |
| 130 int rv, | |
| 131 const DnsResponse* response) { | |
| 132 EXPECT_FALSE(completed_); | |
| 133 EXPECT_EQ(transaction_.get(), t); | |
| 134 | |
| 135 completed_ = true; | |
| 136 | |
| 137 if (cancel_in_callback_) { | |
| 138 Cancel(); | |
| 139 return; | |
| 140 } | |
| 141 | |
| 142 if (expected_answer_count_ >= 0) { | |
| 143 EXPECT_EQ(OK, rv); | |
| 144 EXPECT_EQ(expected_answer_count_, response->answer_count()); | |
| 145 EXPECT_EQ(qtype_, response->qtype()); | |
| 146 | |
| 147 DnsRecordParser parser = response->Parser(); | |
| 148 DnsResourceRecord record; | |
| 149 for (int i = 0; i < expected_answer_count_; ++i) { | |
| 150 EXPECT_TRUE(parser.ParseRecord(&record)); | |
| 151 } | |
| 152 EXPECT_TRUE(parser.AtEnd()); | |
| 153 } else { | |
| 154 EXPECT_EQ(expected_answer_count_, rv); | |
| 155 EXPECT_EQ(NULL, response); | |
| 156 } | |
| 157 | |
| 158 if (quit_in_callback_) | |
| 159 MessageLoop::current()->Quit(); | |
| 160 } | |
| 161 | |
| 162 bool has_completed() const { | |
| 163 return completed_; | |
| 164 } | |
| 165 | |
| 166 private: | |
| 167 std::string hostname_; | |
| 168 uint16 qtype_; | |
| 169 scoped_ptr<DnsTransaction> transaction_; | |
| 170 int expected_answer_count_; | |
| 171 bool cancel_in_callback_; | |
| 172 bool quit_in_callback_; | |
| 173 | |
| 174 bool completed_; | |
| 175 }; | |
| 29 | 176 |
| 30 class DnsTransactionTest : public testing::Test { | 177 class DnsTransactionTest : public testing::Test { |
| 178 public: | |
| 179 DnsTransactionTest() : socket_factory_(NULL) {} | |
| 180 | |
| 181 // Generates |nameservers| for DnsConfig. | |
| 182 void ConfigureNumServers(unsigned num_servers) { | |
| 183 DCHECK_LT(num_servers, 255u); | |
| 184 config_.nameservers.clear(); | |
| 185 IPAddressNumber dns_ip; | |
| 186 { | |
| 187 bool rv = ParseIPLiteralToNumber("192.128.1.0", &dns_ip); | |
| 188 EXPECT_TRUE(rv); | |
| 189 } | |
| 190 for (unsigned i = 0; i < num_servers; ++i) { | |
| 191 dns_ip[3] = i; | |
| 192 config_.nameservers.push_back(IPEndPoint(dns_ip, kDnsPort)); | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 // Called after fully configuring |config|. | |
| 197 void ConfigureFactory() { | |
| 198 socket_factory_ = new TestSocketFactory(); | |
| 199 session_ = new DnsSession( | |
| 200 config_, | |
| 201 socket_factory_, | |
| 202 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)), | |
| 203 NULL /* NetLog */); | |
| 204 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get()); | |
| 205 } | |
| 206 | |
| 207 // Each socket used by a DnsTransaction expects only one write and zero or one | |
| 208 // reads. | |
| 209 | |
| 210 // Add expected query for |dotted_name| and |qtype| with |id| and response | |
| 211 // taken verbatim from |data| of |data_length| bytes. The transaction id in | |
| 212 // |data| should equal |id|, unless testing mismatched response. | |
| 213 void AddResponse(const char* dotted_name, | |
|
cbentzel
2012/01/21 03:41:16
Why not std::string instead?
| |
| 214 uint16 qtype, | |
| 215 uint16 id, | |
| 216 const char* data, | |
| 217 size_t data_length) { | |
| 218 DCHECK(socket_factory_); | |
| 219 DnsQuery* query = new DnsQuery(id, DomainFromDot(dotted_name), qtype); | |
| 220 queries_.push_back(query); | |
| 221 | |
| 222 // The response is only used to hold the IOBuffer. | |
| 223 DnsResponse* response = new DnsResponse(data, data_length, 0); | |
| 224 responses_.push_back(response); | |
| 225 | |
| 226 writes_.push_back(MockWrite(true, | |
| 227 query->io_buffer()->data(), | |
| 228 query->io_buffer()->size())); | |
| 229 reads_.push_back(MockRead(true, | |
| 230 response->io_buffer()->data(), | |
| 231 data_length)); | |
| 232 | |
| 233 transaction_ids_.push_back(id); | |
| 234 } | |
| 235 | |
| 236 // Add expected query of |dotted_name| and |qtype| and no response. | |
| 237 void AddTimeout(const char* dotted_name, uint16 qtype) { | |
| 238 DCHECK(socket_factory_); | |
| 239 uint16 id = base::RandInt(0, kuint16max); | |
| 240 DnsQuery* query = new DnsQuery(id, DomainFromDot(dotted_name), qtype); | |
| 241 queries_.push_back(query); | |
| 242 | |
| 243 writes_.push_back(MockWrite(true, | |
| 244 query->io_buffer()->data(), | |
| 245 query->io_buffer()->size())); | |
| 246 // Empty MockRead indicates no data. | |
| 247 reads_.push_back(MockRead()); | |
| 248 transaction_ids_.push_back(id); | |
| 249 } | |
| 250 | |
| 251 // Add expected query of |dotted_name| and |qtype| and response with no answer | |
| 252 // and rcode set to |rcode|. | |
| 253 void AddRcode(const char* dotted_name, uint16 qtype, int rcode) { | |
| 254 DCHECK(socket_factory_); | |
| 255 DCHECK_NE(dns_protocol::kRcodeNOERROR, rcode); | |
| 256 uint16 id = base::RandInt(0, kuint16max); | |
| 257 DnsQuery* query = new DnsQuery(id, DomainFromDot(dotted_name), qtype); | |
| 258 queries_.push_back(query); | |
| 259 | |
| 260 DnsResponse* response = new DnsResponse(query->io_buffer()->data(), | |
| 261 query->io_buffer()->size(), | |
| 262 0); | |
| 263 dns_protocol::Header* header = | |
| 264 reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data()); | |
| 265 header->flags |= htons(dns_protocol::kFlagResponse | rcode); | |
| 266 responses_.push_back(response); | |
| 267 | |
| 268 writes_.push_back(MockWrite(true, | |
| 269 query->io_buffer()->data(), | |
| 270 query->io_buffer()->size())); | |
| 271 reads_.push_back(MockRead(true, | |
| 272 response->io_buffer()->data(), | |
| 273 query->io_buffer()->size())); | |
| 274 transaction_ids_.push_back(id); | |
| 275 } | |
| 276 | |
| 277 // Call after all Add* calls to prepare data for |socket_factory_|. | |
| 278 // This separation is necessary because the |reads_| and |writes_| vectors | |
| 279 // could reallocate their data during those calls. | |
| 280 void PrepareSockets() { | |
| 281 DCHECK_EQ(writes_.size(), reads_.size()); | |
| 282 for (size_t i = 0; i < writes_.size(); ++i) { | |
| 283 SocketDataProvider *data; | |
| 284 if (reads_[i].data) { | |
| 285 data = new DelayedSocketData(1, &reads_[i], 1, &writes_[i], 1); | |
| 286 } else { | |
| 287 data = new DelayedSocketData(2, NULL, 0, &writes_[i], 1); | |
| 288 } | |
| 289 socket_data_.push_back(data); | |
| 290 socket_factory_->AddSocketDataProvider(data); | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 // Checks if the sockets were connected in the order matching the indices in | |
| 295 // |servers|. | |
| 296 void CheckServerOrder(const unsigned* servers, size_t num_attempts) { | |
| 297 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints.size()); | |
| 298 for (size_t i = 0; i < num_attempts; ++i) { | |
| 299 EXPECT_EQ(socket_factory_->remote_endpoints[i], | |
| 300 session_->config().nameservers[servers[i]]); | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 void SetUp() OVERRIDE { | |
| 305 // By default set one server, | |
| 306 ConfigureNumServers(1); | |
| 307 // and no retransmissions, | |
| 308 config_.attempts = 1; | |
| 309 // but long enough timeout for memory tests. | |
| 310 config_.timeout = TestTimeouts::action_timeout(); | |
| 311 ConfigureFactory(); | |
| 312 } | |
| 313 | |
| 31 protected: | 314 protected: |
| 32 virtual void SetUp() OVERRIDE { | 315 int GetNextId(int min, int max) { |
| 33 callback_ = base::Bind(&DnsTransactionTest::OnTransactionComplete, | 316 EXPECT_FALSE(transaction_ids_.empty()); |
| 34 base::Unretained(this)); | 317 int id = transaction_ids_.front(); |
| 35 qname_ = std::string(kT0DnsName, arraysize(kT0DnsName)); | 318 transaction_ids_.pop_front(); |
| 36 // Use long timeout to prevent timing out on slow bots. | 319 EXPECT_GE(id, min); |
| 37 ConfigureSession(base::TimeDelta::FromMilliseconds( | 320 EXPECT_LE(id, max); |
| 38 TestTimeouts::action_timeout_ms())); | 321 return id; |
| 39 } | 322 } |
| 40 | 323 |
| 41 void ConfigureSession(const base::TimeDelta& timeout) { | 324 DnsConfig config_; |
| 42 IPEndPoint dns_server; | 325 |
| 43 bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server); | 326 // Holders for the buffers behind MockRead/MockWrites (they do not own them). |
| 44 ASSERT_TRUE(rv); | 327 ScopedVector<DnsQuery> queries_; |
| 45 | 328 ScopedVector<DnsResponse> responses_; |
| 46 DnsConfig config; | 329 |
| 47 config.nameservers.push_back(dns_server); | 330 // Holders for MockRead/MockWrites (SocketDataProvider does not own it). |
| 48 config.attempts = 3; | 331 std::vector<MockRead> reads_; |
| 49 config.timeout = timeout; | 332 std::vector<MockWrite> writes_; |
| 50 | 333 |
| 51 session_ = new DnsSession(config, | 334 // Holder for the socket data (MockClientSocketFactory does not own it). |
| 52 new MockClientSocketFactory(), | 335 ScopedVector<SocketDataProvider> socket_data_; |
| 53 base::Bind(&ReturnZero), | 336 |
| 54 NULL /* NetLog */); | 337 std::deque<int> transaction_ids_; |
| 55 } | 338 // Owned by |session_|. |
| 56 | 339 TestSocketFactory* socket_factory_; |
| 57 void StartTransaction() { | |
| 58 transaction_.reset(new DnsTransaction(session_.get(), | |
| 59 qname_, | |
| 60 kT0Qtype, | |
| 61 callback_, | |
| 62 BoundNetLog())); | |
| 63 | |
| 64 int rv0 = transaction_->Start(); | |
| 65 EXPECT_EQ(ERR_IO_PENDING, rv0); | |
| 66 } | |
| 67 | |
| 68 void OnTransactionComplete(DnsTransaction* transaction, int rv) { | |
| 69 EXPECT_EQ(transaction_.get(), transaction); | |
| 70 EXPECT_EQ(qname_, transaction->query()->qname().as_string()); | |
| 71 EXPECT_EQ(kT0Qtype, transaction->query()->qtype()); | |
| 72 rv_ = rv; | |
| 73 MessageLoop::current()->Quit(); | |
| 74 } | |
| 75 | |
| 76 MockClientSocketFactory& factory() { | |
| 77 return *static_cast<MockClientSocketFactory*>(session_->socket_factory()); | |
| 78 } | |
| 79 | |
| 80 int rv() const { return rv_; } | |
| 81 | |
| 82 private: | |
| 83 DnsTransaction::ResultCallback callback_; | |
| 84 std::string qname_; | |
| 85 scoped_refptr<DnsSession> session_; | 340 scoped_refptr<DnsSession> session_; |
| 86 scoped_ptr<DnsTransaction> transaction_; | 341 scoped_ptr<DnsTransactionFactory> transaction_factory_; |
| 87 | |
| 88 int rv_; | |
| 89 }; | 342 }; |
| 90 | 343 |
| 91 TEST_F(DnsTransactionTest, NormalQueryResponseTest) { | 344 TEST_F(DnsTransactionTest, Lookup) { |
| 92 MockWrite writes0[] = { | 345 AddResponse(kT0HostName, |
| 93 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | 346 kT0Qtype, |
| 94 arraysize(kT0QueryDatagram)) | 347 0 /* id */, |
| 348 reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 349 arraysize(kT0ResponseDatagram)); | |
| 350 PrepareSockets(); | |
| 351 | |
| 352 TransactionHelper helper0(kT0HostName, | |
| 353 kT0Qtype, | |
| 354 arraysize(kT0IpAddresses) + 1); | |
| 355 helper0.StartTransaction(transaction_factory_.get()); | |
| 356 | |
| 357 // Wait until result. | |
| 358 MessageLoop::current()->RunAllPending(); | |
| 359 | |
| 360 EXPECT_TRUE(helper0.has_completed()); | |
| 361 } | |
| 362 | |
| 363 // Concurrent lookup tests assume that DnsTransaction::Start immediately | |
| 364 // consumes a socket from ClientSocketFactory. | |
| 365 TEST_F(DnsTransactionTest, ConcurrentLookup) { | |
| 366 AddResponse(kT0HostName, | |
| 367 kT0Qtype, | |
| 368 0 /* id */, | |
| 369 reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 370 arraysize(kT0ResponseDatagram)); | |
| 371 AddResponse(kT1HostName, | |
| 372 kT1Qtype, | |
| 373 1 /* id */, | |
| 374 reinterpret_cast<const char*>(kT1ResponseDatagram), | |
| 375 arraysize(kT1ResponseDatagram)); | |
| 376 PrepareSockets(); | |
| 377 | |
| 378 TransactionHelper helper0(kT0HostName, | |
| 379 kT0Qtype, | |
| 380 arraysize(kT0IpAddresses) + 1); | |
| 381 helper0.StartTransaction(transaction_factory_.get()); | |
| 382 TransactionHelper helper1(kT1HostName, | |
| 383 kT1Qtype, | |
| 384 arraysize(kT1IpAddresses) + 1); | |
| 385 helper1.StartTransaction(transaction_factory_.get()); | |
| 386 | |
| 387 MessageLoop::current()->RunAllPending(); | |
| 388 | |
| 389 EXPECT_TRUE(helper0.has_completed()); | |
| 390 EXPECT_TRUE(helper1.has_completed()); | |
| 391 } | |
| 392 | |
| 393 TEST_F(DnsTransactionTest, CancelLookup) { | |
| 394 AddResponse(kT0HostName, | |
| 395 kT0Qtype, | |
| 396 0 /* id */, | |
| 397 reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 398 arraysize(kT0ResponseDatagram)); | |
| 399 AddResponse(kT1HostName, | |
| 400 kT1Qtype, | |
| 401 1 /* id */, | |
| 402 reinterpret_cast<const char*>(kT1ResponseDatagram), | |
| 403 arraysize(kT1ResponseDatagram)); | |
| 404 PrepareSockets(); | |
| 405 | |
| 406 TransactionHelper helper0(kT0HostName, | |
| 407 kT0Qtype, | |
| 408 arraysize(kT0IpAddresses) + 1); | |
| 409 helper0.StartTransaction(transaction_factory_.get()); | |
| 410 TransactionHelper helper1(kT1HostName, | |
| 411 kT1Qtype, | |
| 412 arraysize(kT1IpAddresses) + 1); | |
| 413 helper1.StartTransaction(transaction_factory_.get()); | |
| 414 | |
| 415 helper0.Cancel(); | |
| 416 | |
| 417 MessageLoop::current()->RunAllPending(); | |
| 418 | |
| 419 EXPECT_FALSE(helper0.has_completed()); | |
| 420 EXPECT_TRUE(helper1.has_completed()); | |
| 421 } | |
| 422 | |
| 423 TEST_F(DnsTransactionTest, DestroyFactory) { | |
| 424 AddResponse(kT0HostName, | |
| 425 kT0Qtype, | |
| 426 0 /* id */, | |
| 427 reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 428 arraysize(kT0ResponseDatagram)); | |
| 429 PrepareSockets(); | |
| 430 | |
| 431 TransactionHelper helper0(kT0HostName, | |
| 432 kT0Qtype, | |
| 433 arraysize(kT0IpAddresses) + 1); | |
| 434 helper0.StartTransaction(transaction_factory_.get()); | |
| 435 | |
| 436 // Destroying the client does not affect running requests. | |
| 437 transaction_factory_.reset(NULL); | |
| 438 | |
| 439 MessageLoop::current()->RunAllPending(); | |
| 440 | |
| 441 EXPECT_TRUE(helper0.has_completed()); | |
| 442 } | |
| 443 | |
| 444 TEST_F(DnsTransactionTest, CancelFromCallback) { | |
| 445 AddResponse(kT0HostName, | |
| 446 kT0Qtype, | |
| 447 0 /* id */, | |
| 448 reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 449 arraysize(kT0ResponseDatagram)); | |
| 450 PrepareSockets(); | |
| 451 | |
| 452 TransactionHelper helper0(kT0HostName, | |
| 453 kT0Qtype, | |
| 454 arraysize(kT0IpAddresses) + 1); | |
| 455 helper0.set_cancel_in_callback(); | |
| 456 helper0.StartTransaction(transaction_factory_.get()); | |
| 457 | |
| 458 MessageLoop::current()->RunAllPending(); | |
| 459 | |
| 460 EXPECT_TRUE(helper0.has_completed()); | |
| 461 } | |
| 462 | |
| 463 TEST_F(DnsTransactionTest, ServerFail) { | |
| 464 AddRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 465 PrepareSockets(); | |
| 466 | |
| 467 TransactionHelper helper0(kT0HostName, | |
| 468 kT0Qtype, | |
| 469 ERR_DNS_SERVER_FAILED); | |
| 470 helper0.StartTransaction(transaction_factory_.get()); | |
| 471 | |
| 472 MessageLoop::current()->RunAllPending(); | |
| 473 | |
| 474 EXPECT_TRUE(helper0.has_completed()); | |
| 475 } | |
| 476 | |
| 477 TEST_F(DnsTransactionTest, NoDomain) { | |
| 478 AddRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); | |
| 479 PrepareSockets(); | |
| 480 | |
| 481 TransactionHelper helper0(kT0HostName, | |
| 482 kT0Qtype, | |
| 483 ERR_NAME_NOT_RESOLVED); | |
| 484 helper0.StartTransaction(transaction_factory_.get()); | |
| 485 | |
| 486 MessageLoop::current()->RunAllPending(); | |
| 487 | |
| 488 EXPECT_TRUE(helper0.has_completed()); | |
| 489 } | |
| 490 | |
| 491 TEST_F(DnsTransactionTest, Timeout) { | |
| 492 config_.attempts = 3; | |
| 493 // Use short timeout to speed up the test. | |
| 494 config_.timeout = base::TimeDelta::FromMilliseconds( | |
| 495 TestTimeouts::tiny_timeout_ms()); | |
| 496 ConfigureFactory(); | |
| 497 | |
| 498 AddTimeout(kT0HostName, kT0Qtype); | |
| 499 AddTimeout(kT0HostName, kT0Qtype); | |
| 500 AddTimeout(kT0HostName, kT0Qtype); | |
| 501 PrepareSockets(); | |
| 502 | |
| 503 TransactionHelper helper0(kT0HostName, | |
| 504 kT0Qtype, | |
| 505 ERR_DNS_TIMED_OUT); | |
| 506 helper0.set_quit_in_callback(); | |
| 507 helper0.StartTransaction(transaction_factory_.get()); | |
| 508 | |
| 509 MessageLoop::current()->Run(); | |
| 510 | |
| 511 EXPECT_TRUE(helper0.has_completed()); | |
| 512 MessageLoop::current()->AssertIdle(); | |
| 513 } | |
| 514 | |
| 515 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { | |
| 516 // Test that we fallback on both server failure and timeout. | |
| 517 config_.attempts = 2; | |
| 518 // The next request should start from the next server. | |
| 519 config_.rotate = true; | |
| 520 ConfigureNumServers(3); | |
| 521 // Use short timeout to speed up the test. | |
| 522 config_.timeout = base::TimeDelta::FromMilliseconds( | |
| 523 TestTimeouts::tiny_timeout_ms()); | |
| 524 ConfigureFactory(); | |
| 525 | |
| 526 // Responses for first request. | |
| 527 AddTimeout(kT0HostName, kT0Qtype); | |
| 528 AddRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 529 AddTimeout(kT0HostName, kT0Qtype); | |
| 530 AddRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 531 AddRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); | |
| 532 // Responses for second request. | |
| 533 AddRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 534 AddRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN); | |
| 535 PrepareSockets(); | |
| 536 | |
| 537 TransactionHelper helper0(kT0HostName, | |
| 538 kT0Qtype, | |
| 539 ERR_NAME_NOT_RESOLVED); | |
| 540 TransactionHelper helper1(kT1HostName, | |
| 541 kT1Qtype, | |
| 542 ERR_NAME_NOT_RESOLVED); | |
| 543 helper0.set_quit_in_callback(); | |
| 544 helper0.StartTransaction(transaction_factory_.get()); | |
| 545 | |
| 546 MessageLoop::current()->Run(); | |
| 547 | |
| 548 EXPECT_TRUE(helper0.has_completed()); | |
| 549 | |
| 550 helper1.StartTransaction(transaction_factory_.get()); | |
| 551 | |
| 552 MessageLoop::current()->RunAllPending(); | |
| 553 | |
| 554 EXPECT_TRUE(helper1.has_completed()); | |
| 555 | |
| 556 unsigned kOrder[] = { | |
| 557 0, 1, 2, 0, 1, // The first transaction. | |
| 558 1, 2, // The second transaction starts from the next server. | |
| 95 }; | 559 }; |
| 96 | 560 CheckServerOrder(kOrder, arraysize(kOrder)); |
| 97 MockRead reads0[] = { | 561 } |
| 98 MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram), | 562 |
| 99 arraysize(kT0ResponseDatagram)) | 563 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) { |
| 100 }; | 564 config_.ndots = 2; |
| 101 | 565 config_.search.push_back("a"); |
| 102 StaticSocketDataProvider data(reads0, arraysize(reads0), | 566 config_.search.push_back("b"); |
| 103 writes0, arraysize(writes0)); | 567 config_.search.push_back("c"); |
| 104 factory().AddSocketDataProvider(&data); | 568 config_.rotate = true; |
| 105 | 569 ConfigureNumServers(2); |
| 106 StartTransaction(); | 570 ConfigureFactory(); |
| 107 MessageLoop::current()->Run(); | 571 |
| 108 | 572 AddRcode("x.y.z", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 109 EXPECT_EQ(OK, rv()); | 573 AddRcode("x.y.z.a", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 110 // TODO(szym): test fields of |transaction_->response()| | 574 AddRcode("x.y.z.b", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 111 | 575 AddRcode("x.y.z.c", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 112 EXPECT_TRUE(data.at_read_eof()); | 576 PrepareSockets(); |
| 113 EXPECT_TRUE(data.at_write_eof()); | 577 |
| 114 } | 578 TransactionHelper helper0("x.y.z", |
| 115 | 579 dns_protocol::kTypeA, |
| 116 TEST_F(DnsTransactionTest, MismatchedQueryResponseTest) { | 580 ERR_NAME_NOT_RESOLVED); |
| 117 MockWrite writes0[] = { | 581 |
| 118 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | 582 helper0.StartTransaction(transaction_factory_.get()); |
| 119 arraysize(kT0QueryDatagram)) | 583 |
| 120 }; | 584 MessageLoop::current()->RunAllPending(); |
| 121 | 585 |
| 122 MockRead reads1[] = { | 586 EXPECT_TRUE(helper0.has_completed()); |
| 123 MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram), | 587 |
| 124 arraysize(kT1ResponseDatagram)) | 588 // Also check if suffix search causes server rotation. |
| 125 }; | 589 unsigned kOrder0[] = { 0, 1, 0, 1 }; |
| 126 | 590 CheckServerOrder(kOrder0, arraysize(kOrder0)); |
| 127 StaticSocketDataProvider data(reads1, arraysize(reads1), | 591 } |
| 128 writes0, arraysize(writes0)); | 592 |
| 129 factory().AddSocketDataProvider(&data); | 593 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) { |
| 130 | 594 config_.ndots = 2; |
| 131 StartTransaction(); | 595 config_.search.push_back("a"); |
| 132 MessageLoop::current()->Run(); | 596 config_.search.push_back("b"); |
| 133 | 597 config_.search.push_back("c"); |
| 134 EXPECT_EQ(ERR_DNS_MALFORMED_RESPONSE, rv()); | 598 ConfigureFactory(); |
| 135 | 599 |
| 136 EXPECT_TRUE(data.at_read_eof()); | 600 // Responses for first transaction. |
| 137 EXPECT_TRUE(data.at_write_eof()); | 601 AddRcode("x.y.a", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 138 } | 602 AddRcode("x.y.b", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 139 | 603 AddRcode("x.y.c", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 140 // Test that after the first timeout we do a fresh connection and if we get | 604 AddRcode("x.y", dns_protocol::kTypeA, dns_protocol::kRcodeNXDOMAIN); |
| 141 // a response on the new connection, we return it. | 605 // Responses for second transaction. |
| 142 TEST_F(DnsTransactionTest, FirstTimeoutTest) { | 606 AddRcode("x", dns_protocol::kTypeAAAA, dns_protocol::kRcodeNXDOMAIN); |
| 143 MockWrite writes0[] = { | 607 PrepareSockets(); |
| 144 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | 608 |
| 145 arraysize(kT0QueryDatagram)) | 609 TransactionHelper helper0("x.y", |
| 146 }; | 610 dns_protocol::kTypeA, |
| 147 | 611 ERR_NAME_NOT_RESOLVED); |
| 148 MockRead reads0[] = { | 612 |
| 149 MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram), | 613 helper0.StartTransaction(transaction_factory_.get()); |
| 150 arraysize(kT0ResponseDatagram)) | 614 |
| 151 }; | 615 MessageLoop::current()->RunAllPending(); |
| 152 | 616 |
| 153 scoped_ptr<DelayedSocketData> socket0_data( | 617 EXPECT_TRUE(helper0.has_completed()); |
| 154 new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0))); | 618 |
| 155 scoped_ptr<DelayedSocketData> socket1_data( | 619 // Test fully-qualified name. |
| 156 new DelayedSocketData(0, reads0, arraysize(reads0), | 620 TransactionHelper helper1("x.", |
| 157 writes0, arraysize(writes0))); | 621 dns_protocol::kTypeAAAA, |
| 158 | 622 ERR_NAME_NOT_RESOLVED); |
| 159 // Use short timeout to speed up the test. | 623 |
| 160 ConfigureSession(base::TimeDelta::FromMilliseconds( | 624 helper1.StartTransaction(transaction_factory_.get()); |
| 161 TestTimeouts::tiny_timeout_ms())); | 625 |
| 162 factory().AddSocketDataProvider(socket0_data.get()); | 626 MessageLoop::current()->RunAllPending(); |
| 163 factory().AddSocketDataProvider(socket1_data.get()); | 627 |
| 164 | 628 EXPECT_TRUE(helper1.has_completed()); |
| 165 StartTransaction(); | |
| 166 | |
| 167 MessageLoop::current()->Run(); | |
| 168 | |
| 169 EXPECT_EQ(OK, rv()); | |
| 170 | |
| 171 EXPECT_TRUE(socket0_data->at_read_eof()); | |
| 172 EXPECT_TRUE(socket0_data->at_write_eof()); | |
| 173 EXPECT_TRUE(socket1_data->at_read_eof()); | |
| 174 EXPECT_TRUE(socket1_data->at_write_eof()); | |
| 175 } | |
| 176 | |
| 177 // Test that after the first timeout we do a fresh connection, and after | |
| 178 // the second timeout we do another fresh connection, and if we get a | |
| 179 // response on the second connection, we return it. | |
| 180 TEST_F(DnsTransactionTest, SecondTimeoutTest) { | |
| 181 MockWrite writes0[] = { | |
| 182 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | |
| 183 arraysize(kT0QueryDatagram)) | |
| 184 }; | |
| 185 | |
| 186 MockRead reads0[] = { | |
| 187 MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 188 arraysize(kT0ResponseDatagram)) | |
| 189 }; | |
| 190 | |
| 191 scoped_ptr<DelayedSocketData> socket0_data( | |
| 192 new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0))); | |
| 193 scoped_ptr<DelayedSocketData> socket1_data( | |
| 194 new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0))); | |
| 195 scoped_ptr<DelayedSocketData> socket2_data( | |
| 196 new DelayedSocketData(0, reads0, arraysize(reads0), | |
| 197 writes0, arraysize(writes0))); | |
| 198 | |
| 199 // Use short timeout to speed up the test. | |
| 200 ConfigureSession(base::TimeDelta::FromMilliseconds( | |
| 201 TestTimeouts::tiny_timeout_ms())); | |
| 202 factory().AddSocketDataProvider(socket0_data.get()); | |
| 203 factory().AddSocketDataProvider(socket1_data.get()); | |
| 204 factory().AddSocketDataProvider(socket2_data.get()); | |
| 205 | |
| 206 StartTransaction(); | |
| 207 | |
| 208 MessageLoop::current()->Run(); | |
| 209 | |
| 210 EXPECT_EQ(OK, rv()); | |
| 211 | |
| 212 EXPECT_TRUE(socket0_data->at_read_eof()); | |
| 213 EXPECT_TRUE(socket0_data->at_write_eof()); | |
| 214 EXPECT_TRUE(socket1_data->at_read_eof()); | |
| 215 EXPECT_TRUE(socket1_data->at_write_eof()); | |
| 216 EXPECT_TRUE(socket2_data->at_read_eof()); | |
| 217 EXPECT_TRUE(socket2_data->at_write_eof()); | |
| 218 } | |
| 219 | |
| 220 // Test that after the first timeout we do a fresh connection, and after | |
| 221 // the second timeout we do another fresh connection and after the third | |
| 222 // timeout we give up and return a timeout error. | |
| 223 TEST_F(DnsTransactionTest, ThirdTimeoutTest) { | |
| 224 MockWrite writes0[] = { | |
| 225 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | |
| 226 arraysize(kT0QueryDatagram)) | |
| 227 }; | |
| 228 | |
| 229 scoped_ptr<DelayedSocketData> socket0_data( | |
| 230 new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0))); | |
| 231 scoped_ptr<DelayedSocketData> socket1_data( | |
| 232 new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0))); | |
| 233 scoped_ptr<DelayedSocketData> socket2_data( | |
| 234 new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0))); | |
| 235 | |
| 236 // Use short timeout to speed up the test. | |
| 237 ConfigureSession(base::TimeDelta::FromMilliseconds( | |
| 238 TestTimeouts::tiny_timeout_ms())); | |
| 239 factory().AddSocketDataProvider(socket0_data.get()); | |
| 240 factory().AddSocketDataProvider(socket1_data.get()); | |
| 241 factory().AddSocketDataProvider(socket2_data.get()); | |
| 242 | |
| 243 StartTransaction(); | |
| 244 | |
| 245 MessageLoop::current()->Run(); | |
| 246 | |
| 247 EXPECT_EQ(ERR_DNS_TIMED_OUT, rv()); | |
| 248 | |
| 249 EXPECT_TRUE(socket0_data->at_read_eof()); | |
| 250 EXPECT_TRUE(socket0_data->at_write_eof()); | |
| 251 EXPECT_TRUE(socket1_data->at_read_eof()); | |
| 252 EXPECT_TRUE(socket1_data->at_write_eof()); | |
| 253 EXPECT_TRUE(socket2_data->at_read_eof()); | |
| 254 EXPECT_TRUE(socket2_data->at_write_eof()); | |
| 255 } | 629 } |
| 256 | 630 |
| 257 } // namespace | 631 } // namespace |
| 258 | 632 |
| 259 } // namespace net | 633 } // namespace net |
| 634 | |
| OLD | NEW |