|
@@ -1,4 +1,4 @@
|
|
|
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
|
|
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
|
|
|
//
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
@@ -42,7 +42,7 @@
|
|
|
// If we need to test something at the level of underlying ASIO and need
|
|
|
// their definition, that test should go to asiolink/internal/tests.
|
|
|
#include <asiolink/asiolink.h>
|
|
|
-#include <asiolink/iosocket.h>
|
|
|
+#include <asiolink/io_socket.h>
|
|
|
|
|
|
using isc::UnitTestUtil;
|
|
|
using namespace std;
|
|
@@ -58,171 +58,6 @@ const char* const TEST_IPV4_ADDR = "127.0.0.1";
|
|
|
// two octets encode the length of the rest of the data. This is crucial
|
|
|
// for the tests below.
|
|
|
const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
|
|
|
-// TODO: Consider this margin
|
|
|
-const boost::posix_time::time_duration TIMER_MARGIN_MSEC =
|
|
|
- boost::posix_time::milliseconds(50);
|
|
|
-
|
|
|
-TEST(IOAddressTest, fromText) {
|
|
|
- IOAddress io_address_v4("192.0.2.1");
|
|
|
- EXPECT_EQ("192.0.2.1", io_address_v4.toText());
|
|
|
-
|
|
|
- IOAddress io_address_v6("2001:db8::1234");
|
|
|
- EXPECT_EQ("2001:db8::1234", io_address_v6.toText());
|
|
|
-
|
|
|
- // bogus IPv4 address-like input
|
|
|
- EXPECT_THROW(IOAddress("192.0.2.2.1"), IOError);
|
|
|
-
|
|
|
- // bogus IPv4 address-like input: out-of-range octet
|
|
|
- EXPECT_THROW(IOAddress("192.0.2.300"), IOError);
|
|
|
-
|
|
|
- // bogus IPv6 address-like input
|
|
|
- EXPECT_THROW(IOAddress("2001:db8:::1234"), IOError);
|
|
|
-
|
|
|
- // bogus IPv6 address-like input
|
|
|
- EXPECT_THROW(IOAddress("2001:db8::efgh"), IOError);
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOEndpointTest, createUDPv4) {
|
|
|
- const IOEndpoint* ep;
|
|
|
- ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5300);
|
|
|
- EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
|
|
|
- EXPECT_EQ(5300, ep->getPort());
|
|
|
- EXPECT_EQ(AF_INET, ep->getFamily());
|
|
|
- EXPECT_EQ(AF_INET, ep->getAddress().getFamily());
|
|
|
- EXPECT_EQ(IPPROTO_UDP, ep->getProtocol());
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOEndpointTest, createTCPv4) {
|
|
|
- const IOEndpoint* ep;
|
|
|
- ep = IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5301);
|
|
|
- EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
|
|
|
- EXPECT_EQ(5301, ep->getPort());
|
|
|
- EXPECT_EQ(AF_INET, ep->getFamily());
|
|
|
- EXPECT_EQ(AF_INET, ep->getAddress().getFamily());
|
|
|
- EXPECT_EQ(IPPROTO_TCP, ep->getProtocol());
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOEndpointTest, createUDPv6) {
|
|
|
- const IOEndpoint* ep;
|
|
|
- ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5302);
|
|
|
- EXPECT_EQ("2001:db8::1234", ep->getAddress().toText());
|
|
|
- EXPECT_EQ(5302, ep->getPort());
|
|
|
- EXPECT_EQ(AF_INET6, ep->getFamily());
|
|
|
- EXPECT_EQ(AF_INET6, ep->getAddress().getFamily());
|
|
|
- EXPECT_EQ(IPPROTO_UDP, ep->getProtocol());
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOEndpointTest, createTCPv6) {
|
|
|
- const IOEndpoint* ep;
|
|
|
- ep = IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303);
|
|
|
- EXPECT_EQ("2001:db8::1234", ep->getAddress().toText());
|
|
|
- EXPECT_EQ(5303, ep->getPort());
|
|
|
- EXPECT_EQ(AF_INET6, ep->getFamily());
|
|
|
- EXPECT_EQ(AF_INET6, ep->getAddress().getFamily());
|
|
|
- EXPECT_EQ(IPPROTO_TCP, ep->getProtocol());
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOEndpointTest, createIPProto) {
|
|
|
- EXPECT_THROW(IOEndpoint::create(IPPROTO_IP, IOAddress("192.0.2.1"),
|
|
|
- 5300)->getAddress().toText(),
|
|
|
- IOError);
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOSocketTest, dummySockets) {
|
|
|
- EXPECT_EQ(IPPROTO_UDP, IOSocket::getDummyUDPSocket().getProtocol());
|
|
|
- EXPECT_EQ(IPPROTO_TCP, IOSocket::getDummyTCPSocket().getProtocol());
|
|
|
- EXPECT_EQ(-1, IOSocket::getDummyUDPSocket().getNative());
|
|
|
- EXPECT_EQ(-1, IOSocket::getDummyTCPSocket().getNative());
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, badPort) {
|
|
|
- IOService io_service;
|
|
|
- EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
|
|
|
- EXPECT_THROW(DNSService(io_service, *"5300.0", true, false, NULL, NULL, NULL), IOError);
|
|
|
- EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
|
|
|
- EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, badAddress) {
|
|
|
- IOService io_service;
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, unavailableAddress) {
|
|
|
- IOService io_service;
|
|
|
- // These addresses should generally be unavailable as a valid local
|
|
|
- // address, although there's no guarantee in theory.
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.0", NULL, NULL, NULL), IOError);
|
|
|
-
|
|
|
- // Some OSes would simply reject binding attempt for an AF_INET6 socket
|
|
|
- // to an IPv4-mapped IPv6 address. Even if those that allow it, since
|
|
|
- // the corresponding IPv4 address is the same as the one used in the
|
|
|
- // AF_INET socket case above, it should at least show the same result
|
|
|
- // as the previous one.
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:192.0.2.0", NULL, NULL, NULL), IOError);
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, duplicateBind_v6) {
|
|
|
- // In each sub test case, second attempt should fail due to duplicate bind
|
|
|
- IOService io_service;
|
|
|
-
|
|
|
- // IPv6, "any" address
|
|
|
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
|
|
|
- delete dns_service;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, duplicateBind_v6_address) {
|
|
|
- // In each sub test case, second attempt should fail due to duplicate bind
|
|
|
- IOService io_service;
|
|
|
-
|
|
|
- // IPv6, specific address
|
|
|
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
|
|
|
- delete dns_service;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, duplicateBind_v4) {
|
|
|
- // In each sub test case, second attempt should fail due to duplicate bind
|
|
|
- IOService io_service;
|
|
|
-
|
|
|
- // IPv4, "any" address
|
|
|
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
|
|
|
- delete dns_service;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-TEST(IOServiceTest, duplicateBind_v4_address) {
|
|
|
- // In each sub test case, second attempt should fail due to duplicate bind
|
|
|
- IOService io_service;
|
|
|
-
|
|
|
- // IPv4, specific address
|
|
|
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
|
|
|
- delete dns_service;
|
|
|
-}
|
|
|
-
|
|
|
-// Disabled because IPv4-mapped addresses don't seem to be working with
|
|
|
-// the IOService constructor
|
|
|
-TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
|
|
|
- IOService io_service;
|
|
|
- // Duplicate bind on IPv4-mapped IPv6 address
|
|
|
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
|
|
|
- delete dns_service;
|
|
|
-
|
|
|
- // XXX:
|
|
|
- // Currently, this throws an "invalid argument" exception. I have
|
|
|
- // not been able to get IPv4-mapped addresses to work.
|
|
|
- dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
|
|
|
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
|
|
|
- delete dns_service;
|
|
|
-}
|
|
|
|
|
|
// This function returns an addrinfo structure for use by tests, using
|
|
|
// different addresses and ports depending on whether we're testing
|
|
@@ -259,12 +94,12 @@ resolveAddress(const int family, const int protocol, const bool client) {
|
|
|
// expected parameters.
|
|
|
// If initialization parameters of the IOService should be modified, the test
|
|
|
// case can do it using the setDNSService() method.
|
|
|
-// Note: the set of tests in ASIOLinkTest use actual network services and may
|
|
|
+// Note: the set of tests in RecursiveQueryTest use actual network services and may
|
|
|
// involve undesirable side effects such as blocking.
|
|
|
-class ASIOLinkTest : public ::testing::Test {
|
|
|
+class RecursiveQueryTest : public ::testing::Test {
|
|
|
protected:
|
|
|
- ASIOLinkTest();
|
|
|
- ~ASIOLinkTest() {
|
|
|
+ RecursiveQueryTest();
|
|
|
+ ~RecursiveQueryTest() {
|
|
|
if (res_ != NULL) {
|
|
|
freeaddrinfo(res_);
|
|
|
}
|
|
@@ -503,15 +338,48 @@ protected:
|
|
|
bool* done_;
|
|
|
};
|
|
|
|
|
|
+ // This version of mock server just stops the io_service when it is resumed
|
|
|
+ // the second time. (Used in the clientTimeout test, where resume
|
|
|
+ // is called initially with the error answer, and later when the
|
|
|
+ // lookup times out, it is called without an answer to send back)
|
|
|
+ class MockServerStop2 : public MockServer {
|
|
|
+ public:
|
|
|
+ explicit MockServerStop2(IOService& io_service,
|
|
|
+ bool* done1, bool* done2) :
|
|
|
+ MockServer(io_service),
|
|
|
+ done1_(done1),
|
|
|
+ done2_(done2),
|
|
|
+ stopped_once_(false)
|
|
|
+ {}
|
|
|
+
|
|
|
+ void resume(const bool done) {
|
|
|
+ if (stopped_once_) {
|
|
|
+ *done2_ = done;
|
|
|
+ io_.stop();
|
|
|
+ } else {
|
|
|
+ *done1_ = done;
|
|
|
+ stopped_once_ = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DNSServer* clone() {
|
|
|
+ return (new MockServerStop2(*this));
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ bool* done1_;
|
|
|
+ bool* done2_;
|
|
|
+ bool stopped_once_;
|
|
|
+ };
|
|
|
+
|
|
|
private:
|
|
|
class ASIOCallBack : public SimpleCallback {
|
|
|
public:
|
|
|
- ASIOCallBack(ASIOLinkTest* test_obj) : test_obj_(test_obj) {}
|
|
|
+ ASIOCallBack(RecursiveQueryTest* test_obj) : test_obj_(test_obj) {}
|
|
|
void operator()(const IOMessage& io_message) const {
|
|
|
test_obj_->callBack(io_message);
|
|
|
}
|
|
|
private:
|
|
|
- ASIOLinkTest* test_obj_;
|
|
|
+ RecursiveQueryTest* test_obj_;
|
|
|
};
|
|
|
void callBack(const IOMessage& io_message) {
|
|
|
callback_protocol_ = io_message.getSocket().getProtocol();
|
|
@@ -538,30 +406,30 @@ protected:
|
|
|
struct addrinfo* res_;
|
|
|
};
|
|
|
|
|
|
-ASIOLinkTest::ASIOLinkTest() :
|
|
|
+RecursiveQueryTest::RecursiveQueryTest() :
|
|
|
dns_service_(NULL), callback_(NULL), sock_(-1), res_(NULL)
|
|
|
{
|
|
|
io_service_ = new IOService();
|
|
|
setDNSService(true, true);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v6UDPSend) {
|
|
|
+TEST_F(RecursiveQueryTest, v6UDPSend) {
|
|
|
doTest(AF_INET6, IPPROTO_UDP);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v6TCPSend) {
|
|
|
+TEST_F(RecursiveQueryTest, v6TCPSend) {
|
|
|
doTest(AF_INET6, IPPROTO_TCP);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v4UDPSend) {
|
|
|
+TEST_F(RecursiveQueryTest, v4UDPSend) {
|
|
|
doTest(AF_INET, IPPROTO_UDP);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v4TCPSend) {
|
|
|
+TEST_F(RecursiveQueryTest, v4TCPSend) {
|
|
|
doTest(AF_INET, IPPROTO_TCP);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v6UDPSendSpecific) {
|
|
|
+TEST_F(RecursiveQueryTest, v6UDPSendSpecific) {
|
|
|
// Explicitly set a specific address to be bound to the socket.
|
|
|
// The subsequent test does not directly ensures the underlying socket
|
|
|
// is bound to the expected address, but the success of the tests should
|
|
@@ -577,26 +445,26 @@ TEST_F(ASIOLinkTest, v6UDPSendSpecific) {
|
|
|
doTest(AF_INET6, IPPROTO_UDP);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v6TCPSendSpecific) {
|
|
|
+TEST_F(RecursiveQueryTest, v6TCPSendSpecific) {
|
|
|
setDNSService(*TEST_IPV6_ADDR);
|
|
|
doTest(AF_INET6, IPPROTO_TCP);
|
|
|
|
|
|
EXPECT_THROW(sendTCP(AF_INET), IOError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v4UDPSendSpecific) {
|
|
|
+TEST_F(RecursiveQueryTest, v4UDPSendSpecific) {
|
|
|
setDNSService(*TEST_IPV4_ADDR);
|
|
|
doTest(AF_INET, IPPROTO_UDP);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v4TCPSendSpecific) {
|
|
|
+TEST_F(RecursiveQueryTest, v4TCPSendSpecific) {
|
|
|
setDNSService(*TEST_IPV4_ADDR);
|
|
|
doTest(AF_INET, IPPROTO_TCP);
|
|
|
|
|
|
EXPECT_THROW(sendTCP(AF_INET6), IOError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v6AddServer) {
|
|
|
+TEST_F(RecursiveQueryTest, v6AddServer) {
|
|
|
setDNSService();
|
|
|
dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV6_ADDR);
|
|
|
doTest(AF_INET6, IPPROTO_TCP);
|
|
@@ -604,7 +472,7 @@ TEST_F(ASIOLinkTest, v6AddServer) {
|
|
|
EXPECT_THROW(sendTCP(AF_INET), IOError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v4AddServer) {
|
|
|
+TEST_F(RecursiveQueryTest, v4AddServer) {
|
|
|
setDNSService();
|
|
|
dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV4_ADDR);
|
|
|
doTest(AF_INET, IPPROTO_TCP);
|
|
@@ -612,7 +480,7 @@ TEST_F(ASIOLinkTest, v4AddServer) {
|
|
|
EXPECT_THROW(sendTCP(AF_INET6), IOError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, DISABLED_clearServers) {
|
|
|
+TEST_F(RecursiveQueryTest, DISABLED_clearServers) {
|
|
|
// FIXME: Enable when clearServers actually close the sockets
|
|
|
// See #388
|
|
|
setDNSService();
|
|
@@ -622,7 +490,7 @@ TEST_F(ASIOLinkTest, DISABLED_clearServers) {
|
|
|
EXPECT_THROW(sendTCP(AF_INET6), IOError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v6TCPOnly) {
|
|
|
+TEST_F(RecursiveQueryTest, v6TCPOnly) {
|
|
|
// Open only IPv6 TCP socket. A subsequent attempt of establishing an
|
|
|
// IPv4/TCP connection should fail. See above for why we only test this
|
|
|
// for TCP.
|
|
@@ -630,7 +498,7 @@ TEST_F(ASIOLinkTest, v6TCPOnly) {
|
|
|
EXPECT_THROW(sendTCP(AF_INET), IOError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, v4TCPOnly) {
|
|
|
+TEST_F(RecursiveQueryTest, v4TCPOnly) {
|
|
|
setDNSService(true, false);
|
|
|
EXPECT_THROW(sendTCP(AF_INET6), IOError);
|
|
|
}
|
|
@@ -642,7 +510,7 @@ singleAddress(const string &address, uint16_t port) {
|
|
|
return (result);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, recursiveSetupV4) {
|
|
|
+TEST_F(RecursiveQueryTest, recursiveSetupV4) {
|
|
|
setDNSService(true, false);
|
|
|
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
|
|
EXPECT_NO_THROW(RecursiveQuery(*dns_service_,
|
|
@@ -650,7 +518,7 @@ TEST_F(ASIOLinkTest, recursiveSetupV4) {
|
|
|
singleAddress(TEST_IPV4_ADDR, port)));
|
|
|
}
|
|
|
|
|
|
-TEST_F(ASIOLinkTest, recursiveSetupV6) {
|
|
|
+TEST_F(RecursiveQueryTest, recursiveSetupV6) {
|
|
|
setDNSService(false, true);
|
|
|
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
|
|
EXPECT_NO_THROW(RecursiveQuery(*dns_service_,
|
|
@@ -663,7 +531,7 @@ TEST_F(ASIOLinkTest, recursiveSetupV6) {
|
|
|
// a routine that can do this with variable address family, address, and
|
|
|
// port, and with the various callbacks defined in such a way as to ensure
|
|
|
// full code coverage including error cases.
|
|
|
-TEST_F(ASIOLinkTest, forwarderSend) {
|
|
|
+TEST_F(RecursiveQueryTest, forwarderSend) {
|
|
|
setDNSService(true, false);
|
|
|
|
|
|
// Note: We use the test prot plus one to ensure we aren't binding
|
|
@@ -678,7 +546,7 @@ TEST_F(ASIOLinkTest, forwarderSend) {
|
|
|
Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
MessagePtr answer(new Message(Message::RENDER));
|
|
|
- rq.sendQuery(q, answer, buffer, &server);
|
|
|
+ rq.resolve(q, answer, buffer, &server);
|
|
|
|
|
|
char data[4096];
|
|
|
size_t size = sizeof(data);
|
|
@@ -717,7 +585,7 @@ setSocketTimeout(int sock_, size_t tv_sec, size_t tv_usec) {
|
|
|
const struct timeval timeo = { tv_sec, tv_usec };
|
|
|
int recv_options = 0;
|
|
|
if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
|
|
|
- if (errno == ENOPROTOOPT) { // see ASIOLinkTest::recvUDP()
|
|
|
+ if (errno == ENOPROTOOPT) { // see RecursiveQueryTest::recvUDP()
|
|
|
recv_options = MSG_DONTWAIT;
|
|
|
} else {
|
|
|
isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
|
|
@@ -745,7 +613,7 @@ bool tryRead(int sock_, int recv_options, size_t max, int* num) {
|
|
|
|
|
|
|
|
|
// Test it tries the correct amount of times before giving up
|
|
|
-TEST_F(ASIOLinkTest, forwardQueryTimeout) {
|
|
|
+TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
|
|
|
// Prepare the service (we do not use the common setup, we do not answer
|
|
|
setDNSService();
|
|
|
|
|
@@ -765,7 +633,7 @@ TEST_F(ASIOLinkTest, forwardQueryTimeout) {
|
|
|
Question question(Name("example.net"), RRClass::IN(), RRType::A());
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
MessagePtr answer(new Message(Message::RENDER));
|
|
|
- query.sendQuery(question, answer, buffer, &server);
|
|
|
+ query.resolve(question, answer, buffer, &server);
|
|
|
|
|
|
// Run the test
|
|
|
io_service_->run();
|
|
@@ -785,15 +653,16 @@ TEST_F(ASIOLinkTest, forwardQueryTimeout) {
|
|
|
// If we set client timeout to lower than querytimeout, we should
|
|
|
// get a failure answer, but still see retries
|
|
|
// (no actual answer is given here yet)
|
|
|
-TEST_F(ASIOLinkTest, forwardClientTimeout) {
|
|
|
+TEST_F(RecursiveQueryTest, forwardClientTimeout) {
|
|
|
// Prepare the service (we do not use the common setup, we do not answer
|
|
|
setDNSService();
|
|
|
|
|
|
sock_ = createTestSocket();
|
|
|
|
|
|
// Prepare the server
|
|
|
- bool done(true);
|
|
|
- MockServerStop server(*io_service_, &done);
|
|
|
+ bool done1(true);
|
|
|
+ bool done2(true);
|
|
|
+ MockServerStop2 server(*io_service_, &done1, &done2);
|
|
|
|
|
|
MessagePtr answer(new Message(Message::RENDER));
|
|
|
|
|
@@ -801,14 +670,14 @@ TEST_F(ASIOLinkTest, forwardClientTimeout) {
|
|
|
const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
|
|
// Set it up to retry twice before client timeout fires
|
|
|
// Since the lookup timer has not fired, it should retry
|
|
|
- // a third time
|
|
|
+ // four times
|
|
|
RecursiveQuery query(*dns_service_,
|
|
|
singleAddress(TEST_IPV4_ADDR, port),
|
|
|
singleAddress(TEST_IPV4_ADDR, port),
|
|
|
- 50, 120, 1000, 3);
|
|
|
+ 50, 120, 1000, 4);
|
|
|
Question question(Name("example.net"), RRClass::IN(), RRType::A());
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
- query.sendQuery(question, answer, buffer, &server);
|
|
|
+ query.resolve(question, answer, buffer, &server);
|
|
|
|
|
|
// Run the test
|
|
|
io_service_->run();
|
|
@@ -816,22 +685,20 @@ TEST_F(ASIOLinkTest, forwardClientTimeout) {
|
|
|
// we know it'll fail, so make it a shorter timeout
|
|
|
int recv_options = setSocketTimeout(sock_, 1, 0);
|
|
|
|
|
|
- // Try to read 5 times, should stop after 3 reads
|
|
|
+ // Try to read 5 times
|
|
|
int num = 0;
|
|
|
bool read_success = tryRead(sock_, recv_options, 5, &num);
|
|
|
|
|
|
- // The query should fail (for resolver it should send back servfail,
|
|
|
- // but currently, and perhaps for forwarder in general, the effect
|
|
|
- // will be the same as on a lookup timeout, i.e. no answer is sent
|
|
|
- // back)
|
|
|
- EXPECT_FALSE(done);
|
|
|
- EXPECT_EQ(3, num);
|
|
|
- EXPECT_FALSE(read_success);
|
|
|
+ // The query should fail, but we should have kept on trying
|
|
|
+ EXPECT_TRUE(done1);
|
|
|
+ EXPECT_FALSE(done2);
|
|
|
+ EXPECT_EQ(5, num);
|
|
|
+ EXPECT_TRUE(read_success);
|
|
|
}
|
|
|
|
|
|
// If we set lookup timeout to lower than querytimeout*retries, we should
|
|
|
// fail before the full amount of retries
|
|
|
-TEST_F(ASIOLinkTest, forwardLookupTimeout) {
|
|
|
+TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
|
|
|
// Prepare the service (we do not use the common setup, we do not answer
|
|
|
setDNSService();
|
|
|
|
|
@@ -854,7 +721,7 @@ TEST_F(ASIOLinkTest, forwardLookupTimeout) {
|
|
|
50, 4000, 120, 5);
|
|
|
Question question(Name("example.net"), RRClass::IN(), RRType::A());
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
- query.sendQuery(question, answer, buffer, &server);
|
|
|
+ query.resolve(question, answer, buffer, &server);
|
|
|
|
|
|
// Run the test
|
|
|
io_service_->run();
|
|
@@ -877,7 +744,7 @@ TEST_F(ASIOLinkTest, forwardLookupTimeout) {
|
|
|
// for the skeleton code, it shouldn't be too much of a problem
|
|
|
// Ok so even we don't all have access to the DNS world right now,
|
|
|
// so disabling these tests too.
|
|
|
-TEST_F(ASIOLinkTest, DISABLED_recursiveSendOk) {
|
|
|
+TEST_F(RecursiveQueryTest, DISABLED_recursiveSendOk) {
|
|
|
setDNSService(true, false);
|
|
|
bool done;
|
|
|
|
|
@@ -888,7 +755,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendOk) {
|
|
|
Question q(Name("www.isc.org"), RRClass::IN(), RRType::A());
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
MessagePtr answer(new Message(Message::RENDER));
|
|
|
- rq.sendQuery(q, answer, buffer, &server);
|
|
|
+ rq.resolve(q, answer, buffer, &server);
|
|
|
io_service_->run();
|
|
|
|
|
|
// Check that the answer we got matches the one we wanted
|
|
@@ -902,7 +769,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendOk) {
|
|
|
}
|
|
|
|
|
|
// see comments at previous test
|
|
|
-TEST_F(ASIOLinkTest, DISABLED_recursiveSendNXDOMAIN) {
|
|
|
+TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
|
|
|
setDNSService(true, false);
|
|
|
bool done;
|
|
|
|
|
@@ -913,7 +780,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendNXDOMAIN) {
|
|
|
Question q(Name("wwwdoesnotexist.isc.org"), RRClass::IN(), RRType::A());
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
MessagePtr answer(new Message(Message::RENDER));
|
|
|
- rq.sendQuery(q, answer, buffer, &server);
|
|
|
+ rq.resolve(q, answer, buffer, &server);
|
|
|
io_service_->run();
|
|
|
|
|
|
// Check that the answer we got matches the one we wanted
|
|
@@ -921,280 +788,4 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendNXDOMAIN) {
|
|
|
EXPECT_EQ(0, answer->getRRCount(Message::SECTION_ANSWER));
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-// This fixture is for testing IntervalTimer. Some callback functors are
|
|
|
-// registered as callback function of the timer to test if they are called
|
|
|
-// or not.
|
|
|
-class IntervalTimerTest : public ::testing::Test {
|
|
|
-protected:
|
|
|
- IntervalTimerTest() : io_service_() {}
|
|
|
- ~IntervalTimerTest() {}
|
|
|
- class TimerCallBack : public std::unary_function<void, void> {
|
|
|
- public:
|
|
|
- TimerCallBack(IntervalTimerTest* test_obj) : test_obj_(test_obj) {}
|
|
|
- void operator()() const {
|
|
|
- test_obj_->timer_called_ = true;
|
|
|
- test_obj_->io_service_.stop();
|
|
|
- return;
|
|
|
- }
|
|
|
- private:
|
|
|
- IntervalTimerTest* test_obj_;
|
|
|
- };
|
|
|
- class TimerCallBackCounter : public std::unary_function<void, void> {
|
|
|
- public:
|
|
|
- TimerCallBackCounter(IntervalTimerTest* test_obj) : test_obj_(test_obj) {
|
|
|
- counter_ = 0;
|
|
|
- }
|
|
|
- void operator()() {
|
|
|
- ++counter_;
|
|
|
- return;
|
|
|
- }
|
|
|
- int counter_;
|
|
|
- private:
|
|
|
- IntervalTimerTest* test_obj_;
|
|
|
- };
|
|
|
- class TimerCallBackCancelDeleter : public std::unary_function<void, void> {
|
|
|
- public:
|
|
|
- TimerCallBackCancelDeleter(IntervalTimerTest* test_obj,
|
|
|
- IntervalTimer* timer,
|
|
|
- TimerCallBackCounter& counter)
|
|
|
- : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0)
|
|
|
- {}
|
|
|
- void operator()() {
|
|
|
- ++count_;
|
|
|
- if (count_ == 1) {
|
|
|
- // First time of call back.
|
|
|
- // Store the value of counter_.counter_.
|
|
|
- prev_counter_ = counter_.counter_;
|
|
|
- delete timer_;
|
|
|
- } else if (count_ == 2) {
|
|
|
- // Second time of call back.
|
|
|
- // Stop io_service to stop all timers.
|
|
|
- test_obj_->io_service_.stop();
|
|
|
- // Compare the value of counter_.counter_ with stored one.
|
|
|
- // If TimerCallBackCounter was not called (expected behavior),
|
|
|
- // they are same.
|
|
|
- if (counter_.counter_ == prev_counter_) {
|
|
|
- test_obj_->timer_cancel_success_ = true;
|
|
|
- }
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- private:
|
|
|
- IntervalTimerTest* test_obj_;
|
|
|
- IntervalTimer* timer_;
|
|
|
- TimerCallBackCounter& counter_;
|
|
|
- int count_;
|
|
|
- int prev_counter_;
|
|
|
- };
|
|
|
- class TimerCallBackCanceller {
|
|
|
- public:
|
|
|
- TimerCallBackCanceller(unsigned int& counter, IntervalTimer& itimer) :
|
|
|
- counter_(counter), itimer_(itimer)
|
|
|
- {}
|
|
|
- void operator()() {
|
|
|
- ++counter_;
|
|
|
- itimer_.cancel();
|
|
|
- }
|
|
|
- private:
|
|
|
- unsigned int& counter_;
|
|
|
- IntervalTimer& itimer_;
|
|
|
- };
|
|
|
- class TimerCallBackOverwriter : public std::unary_function<void, void> {
|
|
|
- public:
|
|
|
- TimerCallBackOverwriter(IntervalTimerTest* test_obj,
|
|
|
- IntervalTimer& timer)
|
|
|
- : test_obj_(test_obj), timer_(timer), count_(0)
|
|
|
- {}
|
|
|
- void operator()() {
|
|
|
- ++count_;
|
|
|
- if (count_ == 1) {
|
|
|
- // First time of call back.
|
|
|
- // Call setupTimer() to update callback function
|
|
|
- // to TimerCallBack.
|
|
|
- test_obj_->timer_called_ = false;
|
|
|
- timer_.setupTimer(TimerCallBack(test_obj_), 1);
|
|
|
- } else if (count_ == 2) {
|
|
|
- // Second time of call back.
|
|
|
- // If it reaches here, re-setupTimer() is failed (unexpected).
|
|
|
- // We should stop here.
|
|
|
- test_obj_->io_service_.stop();
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- private:
|
|
|
- IntervalTimerTest* test_obj_;
|
|
|
- IntervalTimer& timer_;
|
|
|
- int count_;
|
|
|
- };
|
|
|
-protected:
|
|
|
- IOService io_service_;
|
|
|
- bool timer_called_;
|
|
|
- bool timer_cancel_success_;
|
|
|
-};
|
|
|
-
|
|
|
-TEST_F(IntervalTimerTest, invalidArgumentToIntervalTimer) {
|
|
|
- // Create asio_link::IntervalTimer and setup.
|
|
|
- IntervalTimer itimer(io_service_);
|
|
|
- // expect throw if call back function is empty
|
|
|
- EXPECT_THROW(itimer.setupTimer(IntervalTimer::Callback(), 1),
|
|
|
- isc::InvalidParameter);
|
|
|
- // expect throw if interval is 0
|
|
|
- EXPECT_THROW(itimer.setupTimer(TimerCallBack(this), 0), isc::BadValue);
|
|
|
-}
|
|
|
-
|
|
|
-TEST_F(IntervalTimerTest, startIntervalTimer) {
|
|
|
- // Create asio_link::IntervalTimer and setup.
|
|
|
- // Then run IOService and test if the callback function is called.
|
|
|
- IntervalTimer itimer(io_service_);
|
|
|
- timer_called_ = false;
|
|
|
- // store start time
|
|
|
- boost::posix_time::ptime start;
|
|
|
- start = boost::posix_time::microsec_clock::universal_time();
|
|
|
- // setup timer
|
|
|
- itimer.setupTimer(TimerCallBack(this), 1);
|
|
|
- EXPECT_EQ(1, itimer.getInterval());
|
|
|
- io_service_.run();
|
|
|
- // reaches here after timer expired
|
|
|
- // delta: difference between elapsed time and 1 second
|
|
|
- boost::posix_time::time_duration delta =
|
|
|
- (boost::posix_time::microsec_clock::universal_time() - start)
|
|
|
- - boost::posix_time::seconds(1);
|
|
|
- if (delta.is_negative()) {
|
|
|
- delta.invert_sign();
|
|
|
- }
|
|
|
- // expect TimerCallBack is called; timer_called_ is true
|
|
|
- EXPECT_TRUE(timer_called_);
|
|
|
- // expect interval is 1 second +/- TIMER_MARGIN_MSEC.
|
|
|
- EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
|
|
|
-}
|
|
|
-
|
|
|
-TEST_F(IntervalTimerTest, destructIntervalTimer) {
|
|
|
- // Note: This test currently takes 6 seconds. The timer should have
|
|
|
- // finer granularity and timer periods in this test should be shorter
|
|
|
- // in the future.
|
|
|
- // This code isn't exception safe, but we'd rather keep the code
|
|
|
- // simpler and more readable as this is only for tests and if it throws
|
|
|
- // the program would immediately terminate anyway.
|
|
|
-
|
|
|
- // The call back function will not be called after the timer is
|
|
|
- // destructed.
|
|
|
- //
|
|
|
- // There are two timers:
|
|
|
- // itimer_counter (A)
|
|
|
- // (Calls TimerCallBackCounter)
|
|
|
- // - increments internal counter in callback function
|
|
|
- // itimer_canceller (B)
|
|
|
- // (Calls TimerCallBackCancelDeleter)
|
|
|
- // - first time of callback, it stores the counter value of
|
|
|
- // callback_canceller and destructs itimer_counter
|
|
|
- // - second time of callback, it compares the counter value of
|
|
|
- // callback_canceller with stored value
|
|
|
- // if they are same the timer was not called; expected result
|
|
|
- // if they are different the timer was called after destructed
|
|
|
- //
|
|
|
- // 0 1 2 3 4 5 6 (s)
|
|
|
- // (A) i-----+--x
|
|
|
- // ^
|
|
|
- // |destruct itimer_counter
|
|
|
- // (B) i--------+--------s
|
|
|
- // ^stop io_service
|
|
|
- // and test itimer_counter have been stopped
|
|
|
- //
|
|
|
-
|
|
|
- // itimer_counter will be deleted in TimerCallBackCancelDeleter
|
|
|
- IntervalTimer* itimer_counter = new IntervalTimer(io_service_);
|
|
|
- IntervalTimer itimer_canceller(io_service_);
|
|
|
- timer_cancel_success_ = false;
|
|
|
- TimerCallBackCounter callback_canceller(this);
|
|
|
- itimer_counter->setupTimer(callback_canceller, 2);
|
|
|
- itimer_canceller.setupTimer(
|
|
|
- TimerCallBackCancelDeleter(this, itimer_counter,
|
|
|
- callback_canceller),
|
|
|
- 3);
|
|
|
- io_service_.run();
|
|
|
- EXPECT_TRUE(timer_cancel_success_);
|
|
|
-}
|
|
|
-
|
|
|
-TEST_F(IntervalTimerTest, cancel) {
|
|
|
- // Similar to destructIntervalTimer test, but the first timer explicitly
|
|
|
- // cancels itself on first callback.
|
|
|
- IntervalTimer itimer_counter(io_service_);
|
|
|
- IntervalTimer itimer_watcher(io_service_);
|
|
|
- unsigned int counter = 0;
|
|
|
- itimer_counter.setupTimer(TimerCallBackCanceller(counter, itimer_counter),
|
|
|
- 1);
|
|
|
- itimer_watcher.setupTimer(TimerCallBack(this), 3);
|
|
|
- io_service_.run();
|
|
|
- EXPECT_EQ(1, counter);
|
|
|
- EXPECT_EQ(0, itimer_counter.getInterval());
|
|
|
-
|
|
|
- // canceling an already canceled timer shouldn't cause any surprise.
|
|
|
- EXPECT_NO_THROW(itimer_counter.cancel());
|
|
|
-}
|
|
|
-
|
|
|
-TEST_F(IntervalTimerTest, overwriteIntervalTimer) {
|
|
|
- // Note: This test currently takes 4 seconds. The timer should have
|
|
|
- // finer granularity and timer periods in this test should be shorter
|
|
|
- // in the future.
|
|
|
-
|
|
|
- // Calling setupTimer() multiple times updates call back function
|
|
|
- // and interval.
|
|
|
- //
|
|
|
- // There are two timers:
|
|
|
- // itimer (A)
|
|
|
- // (Calls TimerCallBackCounter / TimerCallBack)
|
|
|
- // - increments internal counter in callback function
|
|
|
- // (TimerCallBackCounter)
|
|
|
- // interval: 2 seconds
|
|
|
- // - io_service_.stop() (TimerCallBack)
|
|
|
- // interval: 1 second
|
|
|
- // itimer_overwriter (B)
|
|
|
- // (Calls TimerCallBackOverwriter)
|
|
|
- // - first time of callback, it calls setupTimer() to change
|
|
|
- // call back function and interval of itimer to
|
|
|
- // TimerCallBack / 1 second
|
|
|
- // after 3 + 1 seconds from the beginning of this test,
|
|
|
- // TimerCallBack() will be called and io_service_ stops.
|
|
|
- // - second time of callback, it means the test fails.
|
|
|
- //
|
|
|
- // 0 1 2 3 4 5 6 (s)
|
|
|
- // (A) i-----+--C--s
|
|
|
- // ^ ^stop io_service
|
|
|
- // |change call back function
|
|
|
- // (B) i--------+--------S
|
|
|
- // ^(stop io_service on fail)
|
|
|
- //
|
|
|
-
|
|
|
- IntervalTimer itimer(io_service_);
|
|
|
- IntervalTimer itimer_overwriter(io_service_);
|
|
|
- // store start time
|
|
|
- boost::posix_time::ptime start;
|
|
|
- start = boost::posix_time::microsec_clock::universal_time();
|
|
|
- itimer.setupTimer(TimerCallBackCounter(this), 2);
|
|
|
- itimer_overwriter.setupTimer(TimerCallBackOverwriter(this, itimer), 3);
|
|
|
- io_service_.run();
|
|
|
- // reaches here after timer expired
|
|
|
- // if interval is updated, it takes
|
|
|
- // 3 seconds for TimerCallBackOverwriter
|
|
|
- // + 1 second for TimerCallBack (stop)
|
|
|
- // = 4 seconds.
|
|
|
- // otherwise (test fails), it takes
|
|
|
- // 3 seconds for TimerCallBackOverwriter
|
|
|
- // + 3 seconds for TimerCallBackOverwriter (stop)
|
|
|
- // = 6 seconds.
|
|
|
- // delta: difference between elapsed time and 3 + 1 seconds
|
|
|
- boost::posix_time::time_duration delta =
|
|
|
- (boost::posix_time::microsec_clock::universal_time() - start)
|
|
|
- - boost::posix_time::seconds(3 + 1);
|
|
|
- if (delta.is_negative()) {
|
|
|
- delta.invert_sign();
|
|
|
- }
|
|
|
- // expect callback function is updated: TimerCallBack is called
|
|
|
- EXPECT_TRUE(timer_called_);
|
|
|
- // expect interval is updated
|
|
|
- EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
|
|
|
-}
|
|
|
-
|
|
|
}
|