Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(266)

Unified Diff: net/dns/dns_transaction_unittest.cc

Issue 9190031: DnsClient refactoring + features (timeout, suffix search, server rotation). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Renamed dns_client -> dns_transaction. Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/dns/dns_transaction_unittest.cc
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 3e3c2fe7a0f464dfa63082e7f65f2339a38a3fb8..8d15b446b620fe66de07814cde5d75b9cd377824 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -4,259 +4,314 @@
#include "net/dns/dns_transaction.h"
-#include <deque>
-#include <vector>
-
#include "base/bind.h"
-#include "base/test/test_timeouts.h"
-#include "base/time.h"
-#include "net/dns/dns_protocol.h"
-#include "net/dns/dns_query.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/big_endian.h"
+#include "net/base/net_log.h"
+#include "net/base/sys_addrinfo.h"
#include "net/dns/dns_response.h"
#include "net/dns/dns_session.h"
#include "net/dns/dns_test_util.h"
#include "net/socket/socket_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+// TODO(szym): test timeout.
+// TODO(szym): test server fallback.
+// TODO(szym): test suffix search.
+
namespace net {
namespace {
-// A mock for RandIntCallback that always returns 0.
-int ReturnZero(int min, int max) {
- return 0;
-}
-
class DnsTransactionTest : public testing::Test {
- protected:
+ public:
+ class TestHelper {
+ public:
+ // If |answer_count| < 0, it is the expected error code.
+ TestHelper(const char* name,
+ uint16 type,
+ const MockWrite& write,
+ const MockRead& read,
+ int answer_count)
+ : qname(name),
+ qtype(type),
+ expected_answer_count(answer_count),
+ completed(false) {
+ writes.push_back(write);
+ reads.push_back(read);
+ ReadBigEndian<uint16>(write.data, &transaction_id);
+ data.reset(new StaticSocketDataProvider(&reads[0], reads.size(),
+ &writes[0], writes.size()));
+ }
+
+ void MakeRequest(DnsTransactionFactory* client) {
+ EXPECT_EQ(NULL, transaction.get());
+ transaction = client->CreateTransaction(
+ qname,
+ qtype,
+ base::Bind(&TestHelper::OnTransactionComplete,
+ base::Unretained(this)),
+ BoundNetLog());
+ EXPECT_EQ(qname, transaction->GetHostname());
+ EXPECT_EQ(qtype, transaction->GetType());
+ int rv = transaction->Start();
+ if (rv != ERR_IO_PENDING) {
+ EXPECT_NE(OK, rv);
+ EXPECT_EQ(expected_answer_count, rv);
+ }
+ }
+
+ void Cancel() {
+ ASSERT_TRUE(transaction.get() != NULL);
+ transaction.reset(NULL);
+ }
+
+ void OnTransactionComplete(DnsTransaction* t,
+ int rv,
+ const DnsResponse* response) {
+ EXPECT_FALSE(completed);
+ EXPECT_EQ(transaction.get(), t);
+
+ if (expected_answer_count >= 0) {
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ(expected_answer_count, response->answer_count());
+
+ DnsRecordParser parser = response->Parser();
+ DnsResourceRecord record;
+ for (int i = 0; i < expected_answer_count; ++i) {
+ EXPECT_TRUE(parser.ParseRecord(&record));
+ }
+ EXPECT_TRUE(parser.AtEnd());
+
+ } else {
+ EXPECT_EQ(expected_answer_count, rv);
+ EXPECT_EQ(NULL, response);
+ }
+
+ completed = true;
+ }
+
+ void CancelOnTransactionComplete(DnsTransaction* req,
+ int rv,
+ const DnsResponse* response) {
+ EXPECT_FALSE(completed);
+ Cancel();
+ }
+
+ std::string qname;
+ uint16 qtype;
+ std::vector<MockWrite> writes;
+ std::vector<MockRead> reads;
+ uint16 transaction_id; // Id from first write.
+ scoped_ptr<StaticSocketDataProvider> data;
+ scoped_ptr<DnsTransaction> transaction;
+ int expected_answer_count;
+
+ bool completed;
+ };
+
virtual void SetUp() OVERRIDE {
- callback_ = base::Bind(&DnsTransactionTest::OnTransactionComplete,
- base::Unretained(this));
- qname_ = std::string(kT0DnsName, arraysize(kT0DnsName));
- // Use long timeout to prevent timing out on slow bots.
- ConfigureSession(base::TimeDelta::FromMilliseconds(
- TestTimeouts::action_timeout_ms()));
+ helpers_.push_back(new TestHelper(
+ kT0HostName,
+ kT0Qtype,
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram)),
+ MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram)),
+ arraysize(kT0IpAddresses) + 1)); // +1 for CNAME RR
+
+ helpers_.push_back(new TestHelper(
+ kT1HostName,
+ kT1Qtype,
+ MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
+ arraysize(kT1QueryDatagram)),
+ MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
+ arraysize(kT1ResponseDatagram)),
+ arraysize(kT1IpAddresses) + 1)); // +1 for CNAME RR
+
+ helpers_.push_back(new TestHelper(
+ kT2HostName,
+ kT2Qtype,
+ MockWrite(true, reinterpret_cast<const char*>(kT2QueryDatagram),
+ arraysize(kT2QueryDatagram)),
+ MockRead(true, reinterpret_cast<const char*>(kT2ResponseDatagram),
+ arraysize(kT2ResponseDatagram)),
+ arraysize(kT2IpAddresses) + 1)); // +1 for CNAME RR
+
+ helpers_.push_back(new TestHelper(
+ kT3HostName,
+ kT3Qtype,
+ MockWrite(true, reinterpret_cast<const char*>(kT3QueryDatagram),
+ arraysize(kT3QueryDatagram)),
+ MockRead(true, reinterpret_cast<const char*>(kT3ResponseDatagram),
+ arraysize(kT3ResponseDatagram)),
+ arraysize(kT3IpAddresses) + 2)); // +2 for CNAME RR
+
+ CreateFactory();
}
- void ConfigureSession(const base::TimeDelta& timeout) {
- IPEndPoint dns_server;
- bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
- ASSERT_TRUE(rv);
+ void CreateFactory() {
+ MockClientSocketFactory* socket_factory = new MockClientSocketFactory();
+
+ transaction_ids_.clear();
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ socket_factory->AddSocketDataProvider(helpers_[i]->data.get());
+ transaction_ids_.push_back(static_cast<int>(helpers_[i]->transaction_id));
+ }
DnsConfig config;
- config.nameservers.push_back(dns_server);
- config.attempts = 3;
- config.timeout = timeout;
- session_ = new DnsSession(config,
- new MockClientSocketFactory(),
- base::Bind(&ReturnZero),
- NULL /* NetLog */);
- }
+ IPEndPoint dns_server;
+ {
+ bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ EXPECT_TRUE(rv);
+ }
+ config.nameservers.push_back(dns_server);
- void StartTransaction() {
- transaction_.reset(new DnsTransaction(session_.get(),
- qname_,
- kT0Qtype,
- callback_,
- BoundNetLog()));
+ DnsSession* session = new DnsSession(
+ config,
+ socket_factory,
+ base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
+ NULL /* NetLog */);
- int rv0 = transaction_->Start();
- EXPECT_EQ(ERR_IO_PENDING, rv0);
+ factory_ = DnsTransactionFactory::CreateFactory(session);
}
- void OnTransactionComplete(DnsTransaction* transaction, int rv) {
- EXPECT_EQ(transaction_.get(), transaction);
- EXPECT_EQ(qname_, transaction->query()->qname().as_string());
- EXPECT_EQ(kT0Qtype, transaction->query()->qtype());
- rv_ = rv;
- MessageLoop::current()->Quit();
+ virtual void TearDown() OVERRIDE {
+ STLDeleteElements(&helpers_);
}
- MockClientSocketFactory& factory() {
- return *static_cast<MockClientSocketFactory*>(session_->socket_factory());
+ int GetNextId(int min, int max) {
+ EXPECT_FALSE(transaction_ids_.empty());
+ int id = transaction_ids_.front();
+ transaction_ids_.pop_front();
+ EXPECT_GE(id, min);
+ EXPECT_LE(id, max);
+ return id;
}
- int rv() const { return rv_; }
-
- private:
- DnsTransaction::ResultCallback callback_;
- std::string qname_;
- scoped_refptr<DnsSession> session_;
- scoped_ptr<DnsTransaction> transaction_;
-
- int rv_;
+ protected:
+ std::vector<TestHelper*> helpers_;
+ std::deque<int> transaction_ids_;
+ scoped_ptr<DnsTransactionFactory> factory_;
};
-TEST_F(DnsTransactionTest, NormalQueryResponseTest) {
- MockWrite writes0[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
- arraysize(kT0QueryDatagram))
- };
+TEST_F(DnsTransactionTest, Lookup) {
+ helpers_[0]->MakeRequest(factory_.get());
- MockRead reads0[] = {
- MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram))
- };
+ // Wait until result.
+ MessageLoop::current()->RunAllPending();
- StaticSocketDataProvider data(reads0, arraysize(reads0),
- writes0, arraysize(writes0));
- factory().AddSocketDataProvider(&data);
+ EXPECT_TRUE(helpers_[0]->completed);
+}
- StartTransaction();
- MessageLoop::current()->Run();
+TEST_F(DnsTransactionTest, ConcurrentLookup) {
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ helpers_[i]->MakeRequest(factory_.get());
+ }
- EXPECT_EQ(OK, rv());
- // TODO(szym): test fields of |transaction_->response()|
+ MessageLoop::current()->RunAllPending();
- EXPECT_TRUE(data.at_read_eof());
- EXPECT_TRUE(data.at_write_eof());
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ EXPECT_TRUE(helpers_[i]->completed);
+ }
}
-TEST_F(DnsTransactionTest, MismatchedQueryResponseTest) {
- MockWrite writes0[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
- arraysize(kT0QueryDatagram))
- };
-
- MockRead reads1[] = {
- MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
- arraysize(kT1ResponseDatagram))
- };
-
- StaticSocketDataProvider data(reads1, arraysize(reads1),
- writes0, arraysize(writes0));
- factory().AddSocketDataProvider(&data);
+TEST_F(DnsTransactionTest, CancelLookup) {
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ helpers_[i]->MakeRequest(factory_.get());
+ }
- StartTransaction();
- MessageLoop::current()->Run();
+ helpers_[0]->Cancel();
+ helpers_[2]->Cancel();
- EXPECT_EQ(ERR_DNS_MALFORMED_RESPONSE, rv());
+ MessageLoop::current()->RunAllPending();
- EXPECT_TRUE(data.at_read_eof());
- EXPECT_TRUE(data.at_write_eof());
+ EXPECT_FALSE(helpers_[0]->completed);
+ EXPECT_TRUE(helpers_[1]->completed);
+ EXPECT_FALSE(helpers_[2]->completed);
+ EXPECT_TRUE(helpers_[3]->completed);
}
-// Test that after the first timeout we do a fresh connection and if we get
-// a response on the new connection, we return it.
-TEST_F(DnsTransactionTest, FirstTimeoutTest) {
- MockWrite writes0[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
- arraysize(kT0QueryDatagram))
- };
-
- MockRead reads0[] = {
- MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram))
- };
+TEST_F(DnsTransactionTest, DestroyClient) {
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ helpers_[i]->MakeRequest(factory_.get());
+ }
- scoped_refptr<DelayedSocketData> socket0_data(
- new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
- scoped_refptr<DelayedSocketData> socket1_data(
- new DelayedSocketData(0, reads0, arraysize(reads0),
- writes0, arraysize(writes0)));
+ // Destroying the client does not affect running requests.
+ factory_.reset(NULL);
- // Use short timeout to speed up the test.
- ConfigureSession(base::TimeDelta::FromMilliseconds(
- TestTimeouts::tiny_timeout_ms()));
- factory().AddSocketDataProvider(socket0_data.get());
- factory().AddSocketDataProvider(socket1_data.get());
+ MessageLoop::current()->RunAllPending();
- StartTransaction();
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ EXPECT_TRUE(helpers_[i]->completed);
+ }
+}
- MessageLoop::current()->Run();
+TEST_F(DnsTransactionTest, DestroyRequestFromCallback) {
+ // Custom callback to cancel the completing request.
+ helpers_[0]->transaction = factory_->CreateTransaction(
+ helpers_[0]->qname,
+ helpers_[0]->qtype,
+ base::Bind(&TestHelper::CancelOnTransactionComplete,
+ base::Unretained(helpers_[0])),
+ BoundNetLog());
- EXPECT_EQ(OK, rv());
+ int rv = helpers_[0]->transaction->Start();
+ EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_TRUE(socket0_data->at_read_eof());
- EXPECT_TRUE(socket0_data->at_write_eof());
- EXPECT_TRUE(socket1_data->at_read_eof());
- EXPECT_TRUE(socket1_data->at_write_eof());
- EXPECT_EQ(2u, factory().udp_client_sockets().size());
-}
+ for (unsigned i = 1; i < helpers_.size(); ++i) {
+ helpers_[i]->MakeRequest(factory_.get());
+ }
-// Test that after the first timeout we do a fresh connection, and after
-// the second timeout we do another fresh connection, and if we get a
-// response on the second connection, we return it.
-TEST_F(DnsTransactionTest, SecondTimeoutTest) {
- MockWrite writes0[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
- arraysize(kT0QueryDatagram))
- };
+ MessageLoop::current()->RunAllPending();
- MockRead reads0[] = {
- MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram))
- };
-
- scoped_refptr<DelayedSocketData> socket0_data(
- new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
- scoped_refptr<DelayedSocketData> socket1_data(
- new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
- scoped_refptr<DelayedSocketData> socket2_data(
- new DelayedSocketData(0, reads0, arraysize(reads0),
- writes0, arraysize(writes0)));
-
- // Use short timeout to speed up the test.
- ConfigureSession(base::TimeDelta::FromMilliseconds(
- TestTimeouts::tiny_timeout_ms()));
- factory().AddSocketDataProvider(socket0_data.get());
- factory().AddSocketDataProvider(socket1_data.get());
- factory().AddSocketDataProvider(socket2_data.get());
-
- StartTransaction();
-
- MessageLoop::current()->Run();
-
- EXPECT_EQ(OK, rv());
-
- EXPECT_TRUE(socket0_data->at_read_eof());
- EXPECT_TRUE(socket0_data->at_write_eof());
- EXPECT_TRUE(socket1_data->at_read_eof());
- EXPECT_TRUE(socket1_data->at_write_eof());
- EXPECT_TRUE(socket2_data->at_read_eof());
- EXPECT_TRUE(socket2_data->at_write_eof());
- EXPECT_EQ(3u, factory().udp_client_sockets().size());
+ EXPECT_FALSE(helpers_[0]->completed);
+ for (unsigned i = 1; i < helpers_.size(); ++i) {
+ EXPECT_TRUE(helpers_[i]->completed);
+ }
}
-// Test that after the first timeout we do a fresh connection, and after
-// the second timeout we do another fresh connection and after the third
-// timeout we give up and return a timeout error.
-TEST_F(DnsTransactionTest, ThirdTimeoutTest) {
- MockWrite writes0[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
- arraysize(kT0QueryDatagram))
- };
+TEST_F(DnsTransactionTest, HandleFailure) {
+ STLDeleteElements(&helpers_);
+ // Wrong question.
+ helpers_.push_back(new TestHelper(
+ kT0HostName,
+ kT0Qtype,
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram)),
+ MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
+ arraysize(kT1ResponseDatagram)),
+ ERR_DNS_MALFORMED_RESPONSE));
+
+ // Response with NXDOMAIN.
+ uint8 nxdomain_response[arraysize(kT0QueryDatagram)];
+ memcpy(nxdomain_response, kT0QueryDatagram, arraysize(nxdomain_response));
+ nxdomain_response[2] &= 0x80; // Response bit.
+ nxdomain_response[3] &= 0x03; // NXDOMAIN bit.
+ helpers_.push_back(new TestHelper(
+ kT0HostName,
+ kT0Qtype,
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram)),
+ MockRead(true, reinterpret_cast<const char*>(nxdomain_response),
+ arraysize(nxdomain_response)),
+ ERR_NAME_NOT_RESOLVED));
+
+ CreateFactory();
+
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ helpers_[i]->MakeRequest(factory_.get());
+ }
+
+ MessageLoop::current()->RunAllPending();
- scoped_refptr<DelayedSocketData> socket0_data(
- new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
- scoped_refptr<DelayedSocketData> socket1_data(
- new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
- scoped_refptr<DelayedSocketData> socket2_data(
- new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
-
- // Use short timeout to speed up the test.
- ConfigureSession(base::TimeDelta::FromMilliseconds(
- TestTimeouts::tiny_timeout_ms()));
- factory().AddSocketDataProvider(socket0_data.get());
- factory().AddSocketDataProvider(socket1_data.get());
- factory().AddSocketDataProvider(socket2_data.get());
-
- StartTransaction();
-
- MessageLoop::current()->Run();
-
- EXPECT_EQ(ERR_DNS_TIMED_OUT, rv());
-
- EXPECT_TRUE(socket0_data->at_read_eof());
- EXPECT_TRUE(socket0_data->at_write_eof());
- EXPECT_TRUE(socket1_data->at_read_eof());
- EXPECT_TRUE(socket1_data->at_write_eof());
- EXPECT_TRUE(socket2_data->at_read_eof());
- EXPECT_TRUE(socket2_data->at_write_eof());
- EXPECT_EQ(3u, factory().udp_client_sockets().size());
+ for (unsigned i = 0; i < helpers_.size(); ++i) {
+ EXPECT_TRUE(helpers_[i]->completed);
+ }
}
} // namespace
} // namespace net
+
« net/dns/dns_transaction.cc ('K') | « net/dns/dns_transaction.cc ('k') | net/net.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698