[svn] commit: r4011 - in /branches/trac448/src/lib/asiolink: Makefile.am internal/tests/ internal/tests/run_unittests.cc internal/tests/udpdns_unittest.cc tests/Makefile.am tests/asiolink_unittest.cc tests/udpdns_unittest.cc
BIND 10 source code commits
bind10-changes at lists.isc.org
Sun Dec 26 03:47:58 UTC 2010
Author: jinmei
Date: Sun Dec 26 03:47:58 2010
New Revision: 4011
Log:
made asiolink-tests clang++ friendly:
- avoid relying on ASIO details in the main test (this is good anyway in
terms of the original intent of asio link)
- move internal-dependent tests to internal/tests with a workaround compiler
flag
Also fixed a potentially common bug: use blocking recv() in recvUDP() with a fail safe timeout. When compiled with clang++ this test sometimes failed due to the failure of recv(), and after looking at the code closely I found it possible to happen for other environments.
Added:
branches/trac448/src/lib/asiolink/internal/tests/
branches/trac448/src/lib/asiolink/internal/tests/run_unittests.cc
branches/trac448/src/lib/asiolink/internal/tests/udpdns_unittest.cc
- copied unchanged from r4010, branches/trac448/src/lib/asiolink/tests/udpdns_unittest.cc
Removed:
branches/trac448/src/lib/asiolink/tests/udpdns_unittest.cc
Modified:
branches/trac448/src/lib/asiolink/Makefile.am
branches/trac448/src/lib/asiolink/tests/Makefile.am
branches/trac448/src/lib/asiolink/tests/asiolink_unittest.cc
Modified: branches/trac448/src/lib/asiolink/Makefile.am
==============================================================================
--- branches/trac448/src/lib/asiolink/Makefile.am (original)
+++ branches/trac448/src/lib/asiolink/Makefile.am Sun Dec 26 03:47:58 2010
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests internal
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
Modified: branches/trac448/src/lib/asiolink/tests/Makefile.am
==============================================================================
--- branches/trac448/src/lib/asiolink/tests/Makefile.am (original)
+++ branches/trac448/src/lib/asiolink/tests/Makefile.am Sun Dec 26 03:47:58 2010
@@ -18,7 +18,6 @@
run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
run_unittests_SOURCES += asiolink_unittest.cc
-run_unittests_SOURCES += udpdns_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
Modified: branches/trac448/src/lib/asiolink/tests/asiolink_unittest.cc
==============================================================================
--- branches/trac448/src/lib/asiolink/tests/asiolink_unittest.cc (original)
+++ branches/trac448/src/lib/asiolink/tests/asiolink_unittest.cc Sun Dec 26 03:47:58 2010
@@ -17,6 +17,9 @@
#include <config.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
#include <string.h>
#include <boost/lexical_cast.hpp>
@@ -31,19 +34,21 @@
#include <dns/buffer.h>
#include <dns/message.h>
+// IMPORTANT: We shouldn't directly use ASIO definitions in this test.
+// In particular, we must not include asio.hpp in this file.
+// The asiolink module is primarily intended to be a wrapper that hide the
+// details of the underlying implementations. We need to test the wrapper
+// level behaviors. In addition, some compilers reject to compile this file
+// if we include asio.hpp unless we specify a special compiler option.
+// 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/internal/tcpdns.h>
-#include <asiolink/internal/udpdns.h>
-
-#include <asio.hpp>
using isc::UnitTestUtil;
using namespace std;
using namespace asiolink;
using namespace isc::dns;
-using namespace asio;
-using asio::ip::udp;
namespace {
const char* const TEST_SERVER_PORT = "53535";
@@ -326,10 +331,20 @@
// ... and this one will block until the send has completed
io_service_->run_one();
- // Now we attempt to recv() whatever was sent
- const int ret = recv(sock_, buffer, size, MSG_DONTWAIT);
+ // Now we attempt to recv() whatever was sent.
+ // XXX: there's no guarantee the receiving socket can immediately get
+ // the packet. Normally we can perform blocking recv to wait for it,
+ // but in theory it's even possible that the packet is lost.
+ // In order to prevent the test from hanging in such a worst case
+ // we add an ad hoc timeout.
+ const struct timeval timeo = { 10, 0 };
+ if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
+ sizeof(timeo))) {
+ isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
+ }
+ const int ret = recv(sock_, buffer, size, 0);
if (ret < 0) {
- isc_throw(IOError, "recvfrom failed");
+ isc_throw(IOError, "recvfrom failed: " << strerror(errno));
}
// Pass the message size back via the size parameter
@@ -407,8 +422,7 @@
// has completed.
class MockServer : public DNSServer {
public:
- explicit MockServer(asio::io_service& io_service,
- const asio::ip::address& addr, const uint16_t port,
+ explicit MockServer(IOService& io_service,
SimpleCallback* checkin = NULL,
DNSLookup* lookup = NULL,
DNSAnswer* answer = NULL) :
@@ -422,9 +436,7 @@
size_t length = 0)
{}
- void resume(const bool done) {
- done_ = done;
- io_.post(*this);
+ void resume(const bool) { // in our test this shouldn't be called
}
DNSServer* clone() {
@@ -439,7 +451,7 @@
}
protected:
- asio::io_service& io_;
+ IOService& io_;
bool done_;
private:
@@ -458,8 +470,8 @@
// This version of mock server just stops the io_service when it is resumed
class MockServerStop : public MockServer {
public:
- explicit MockServerStop(asio::io_service& io_service, bool* done) :
- MockServer(io_service, asio::ip::address(), 0),
+ explicit MockServerStop(IOService& io_service, bool* done) :
+ MockServer(io_service),
done_(done)
{}
@@ -507,7 +519,6 @@
string callback_address_;
vector<uint8_t> callback_data_;
int sock_;
-private:
struct addrinfo* res_;
};
@@ -636,14 +647,12 @@
// full code coverage including error cases.
TEST_F(ASIOLinkTest, recursiveSend) {
setDNSService(true, false);
- asio::io_service& io = io_service_->get_io_service();
// Note: We use the test prot plus one to ensure we aren't binding
// to the same port as the actual server
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
- asio::ip::address addr = asio::ip::address::from_string(TEST_IPV4_ADDR);
-
- MockServer server(io, addr, port, NULL, NULL, NULL);
+
+ MockServer server(*io_service_);
RecursiveQuery rq(*dns_service_, singleAddress(TEST_IPV4_ADDR, port));
Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
@@ -652,7 +661,7 @@
char data[4096];
size_t size = sizeof(data);
- EXPECT_NO_THROW(recvUDP(AF_INET, data, size));
+ ASSERT_NO_THROW(recvUDP(AF_INET, data, size));
Message m(Message::PARSE);
InputBuffer ibuf(data, size);
@@ -668,34 +677,27 @@
EXPECT_EQ(q.getClass(), q2->getClass());
}
-void
-receive_and_inc(udp::socket* socket, int* num) {
- (*num) ++;
- static char inbuff[512];
- socket->async_receive(asio::buffer(inbuff, 512),
- boost::bind(receive_and_inc, socket, num));
-}
-
// Test it tries the correct amount of times before giving up
TEST_F(ASIOLinkTest, recursiveTimeout) {
// Prepare the service (we do not use the common setup, we do not answer
setDNSService();
- asio::io_service& service = io_service_->get_io_service();
// Prepare the socket
- uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
- udp::socket socket(service, udp::v4());
- socket.set_option(socket_base::reuse_address(true));
- socket.bind(udp::endpoint(ip::address::from_string(TEST_IPV4_ADDR), port));
- // And count the answers
- int num = -1; // One is counted before the receipt of the first one
- receive_and_inc(&socket, &num);
+ res_ = resolveAddress(AF_INET, IPPROTO_UDP, true);
+ sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+ if (sock_ < 0) {
+ isc_throw(IOError, "failed to open test socket");
+ }
+ if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+ isc_throw(IOError, "failed to bind test socket");
+ }
// Prepare the server
bool done(true);
- MockServerStop server(service, &done);
+ MockServerStop server(*io_service_, &done);
// Do the answer
+ const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
RecursiveQuery query(*dns_service_, singleAddress(TEST_IPV4_ADDR, port),
10, 2);
Question question(Name("example.net"), RRClass::IN(), RRType::A());
@@ -703,7 +705,22 @@
query.sendQuery(question, buffer, &server);
// Run the test
- service.run();
+ io_service_->run();
+
+ // Read up to 3 packets. Use some ad hoc timeout to prevent an infinite
+ // block (see also recvUDP()).
+ const struct timeval timeo = { 10, 0 };
+ if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
+ isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
+ }
+ int num = 0;
+ do {
+ char inbuff[512];
+ if (recv(sock_, inbuff, sizeof(inbuff), 0) < 0) {
+ num = -1;
+ break;
+ }
+ } while (++num < 3);
// The query should fail
EXPECT_FALSE(done);
More information about the bind10-changes
mailing list