Parcourir la source

Some tests for the UDPQuery

It does not link, unresolved UDPQuery.stop.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/vorner-recursor-timeouts@3398 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner il y a 14 ans
Parent
commit
de6b350f9a

+ 13 - 9
src/lib/asiolink/asiolink.cc

@@ -231,10 +231,17 @@ namespace {
 
 // This is just temporary so the interface change does not propagate too far
 struct ServerNotify : public UDPQuery::Callback {
-    DNSServer *server;
-    virtual void operator()(UDPQuery::Result result) {
-        server->resume(result == UDPQuery::SUCCESS);
-    }
+        ServerNotify(DNSServer *server) :
+            server_(server)
+        { }
+        virtual void operator()(UDPQuery::Result result) {
+            server_->resume(result == UDPQuery::SUCCESS);
+            delete this;
+        }
+    private:
+        // FIXME This is said it does problems when it is shared pointer, as
+        // it is destroyed too soon. But who deletes it now?
+        DNSServer *server_;
 };
 
 }
@@ -249,11 +256,8 @@ RecursiveQuery::sendQuery(const Question& question, OutputBufferPtr buffer,
     // UDP and then fall back to TCP on failure, but for the moment
     // we're only going to handle UDP.
     asio::io_service& io = dns_service_.get_io_service();
-    boost::shared_ptr<ServerNotify> callback(new ServerNotify);
-    // FIXME This is said it does problems when it is shared pointer, as
-    // it is destroyed too soon. But who deletes it now?
-    callback->server = server->clone();
-    UDPQuery q(io, question, ns_addr_, port_, buffer, callback);
+    UDPQuery q(io, question, ns_addr_, port_, buffer,
+        new ServerNotify(server->clone()));
     io.post(q);
 }
 

+ 11 - 3
src/lib/asiolink/internal/udpdns.h

@@ -198,13 +198,21 @@ public:
             /// This will be called when the UDPQuery is completed
             virtual void operator()(Result result) = 0;
     };
+    /**
+     * \short Constructor.
+     *
+     * It creates the query.
+     * @param callback will be called when we terminate. It is your task to
+     *     delete it if allocated on heap.
+     * @param timeout in ms.
+     */
     explicit UDPQuery(asio::io_service& io_service,
                       const isc::dns::Question& q,
                       const IOAddress& addr, uint16_t port,
                       isc::dns::OutputBufferPtr buffer,
-                      boost::shared_ptr<Callback> callback, int timeout = -1);
+                      Callback *callback, int timeout = -1);
     void operator()(asio::error_code ec = asio::error_code(),
-                    size_t length = 0); 
+                    size_t length = 0);
     /// Terminate the query.
     void stop(Result reason = STOPPED);
 private:
@@ -239,7 +247,7 @@ private:
     boost::shared_array<char> data_;
 
     // This will be called when we are done.
-    boost::shared_ptr<Callback> callback_;
+    Callback *callback_;
 };
 }
 

+ 1 - 0
src/lib/asiolink/tests/Makefile.am

@@ -17,6 +17,7 @@ TESTS += run_unittests
 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)

+ 107 - 0
src/lib/asiolink/tests/udpdns_unittest.cc

@@ -0,0 +1,107 @@
+// Copyright (C) 2010  CZ.NIC
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <asio.hpp>
+#include <boost/bind.hpp>
+#include <cstdlib>
+
+#include <dns/question.h>
+
+#include <asiolink/internal/udpdns.h>
+
+using namespace asio;
+using namespace isc::dns;
+using asio::ip::udp;
+
+namespace {
+
+const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
+const uint16_t TEST_PORT(5301);
+// FIXME Shouldn't we send something that is real message?
+const char TEST_DATA[] = "TEST DATA";
+
+class UDPQuery : public ::testing::Test, public asiolink::UDPQuery::Callback {
+    public:
+        asiolink::UDPQuery::Result expected;
+        bool run;
+        io_service service;
+        Question question;
+        // To keep a reference so noone calls delete this;
+        OutputBufferPtr buffer;
+        asiolink::UDPQuery query;
+
+        UDPQuery() :
+            run(false),
+            question(Name("example.net"), RRClass::IN(), RRType::A()),
+            buffer(new OutputBuffer(512)),
+            query(service, question, asiolink::IOAddress(TEST_HOST), TEST_PORT,
+                buffer, this, 100)
+        { }
+
+        void operator()(asiolink::UDPQuery::Result result) {
+            EXPECT_EQ(expected, result);
+            run = true;
+        }
+        void respond(udp::endpoint& remote, udp::socket* socket) {
+            // Some data came, just send something back.
+            socket->send_to(asio::buffer(TEST_DATA, sizeof TEST_DATA), remote);
+            socket->close();
+        }
+};
+
+TEST_F(UDPQuery, stop) {
+    expected = asiolink::UDPQuery::STOPPED;
+    service.post(query);
+    // Make sure stop is called after executing () of the query
+    // Why doesn't boost::bind support default parameters?
+    service.post(boost::bind(&asiolink::UDPQuery::stop, query,
+        asiolink::UDPQuery::STOPPED));
+    service.run();
+    EXPECT_TRUE(run);
+}
+
+TEST_F(UDPQuery, prematureStop) {
+    expected = asiolink::UDPQuery::STOPPED;
+    // Stop before it is started
+    query.stop();
+    service.post(query);
+    service.run();
+    EXPECT_TRUE(run);
+}
+
+TEST_F(UDPQuery, timeout) {
+    expected = asiolink::UDPQuery::TIME_OUT;
+    service.post(query);
+    service.run();
+    EXPECT_TRUE(run);
+}
+
+TEST_F(UDPQuery, receive) {
+    expected = asiolink::UDPQuery::SUCCESS;
+    udp::socket socket(service, udp::v4());
+    socket.set_option(socket_base::reuse_address(true));
+    socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
+    char inbuff[512];
+    udp::endpoint remote;
+    socket.async_receive_from(asio::buffer(inbuff, 512), remote, boost::bind(
+        &UDPQuery::respond, this, remote, &socket));
+    service.post(query);
+    service.run();
+    EXPECT_TRUE(run);
+    ASSERT_EQ(sizeof TEST_DATA, buffer->getLength());
+    EXPECT_EQ(0, memcmp(TEST_DATA, buffer->getData(), sizeof TEST_DATA));
+}
+
+}

+ 1 - 2
src/lib/asiolink/udpdns.cc

@@ -176,8 +176,7 @@ UDPServer::resume(const bool done) {
 /// The constructor
 UDPQuery::UDPQuery(io_service& io_service,
                    const Question& q, const IOAddress& addr, uint16_t port,
-                   OutputBufferPtr buffer,
-                   boost::shared_ptr<Callback> callback, int timeout) :
+                   OutputBufferPtr buffer, Callback *callback, int timeout) :
     question_(q), buffer_(buffer), callback_(callback)
 {
     udp proto = (addr.getFamily() == AF_INET) ? udp::v4() : udp::v6();