Parcourir la source

catch up to trunk

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac470@4156 e5f2f494-b856-4b98-b285-d166d9295462
Jeremy C. Reed il y a 14 ans
Parent
commit
06cfe32314

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+  143.	[build]		jinmei
+	Fixed build problems with clang++ in unit tests due to recent
+	changes.  No behavior change. (Trac #448, svn r4133)
+
   142.	[func]		jinmei
 	b10-auth: updated query benchmark so that it can test in memory
 	data source.  Also fixed a bug that the output buffer isn't

+ 2 - 0
configure.ac

@@ -597,6 +597,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/Makefile
                  src/lib/asiolink/Makefile
                  src/lib/asiolink/tests/Makefile
+                 src/lib/asiolink/internal/Makefile
+                 src/lib/asiolink/internal/tests/Makefile
                  src/lib/bench/Makefile
                  src/lib/bench/example/Makefile
                  src/lib/bench/tests/Makefile

+ 47 - 1
src/bin/auth/query.cc

@@ -14,6 +14,7 @@
 
 #include <dns/message.h>
 #include <dns/rcode.h>
+#include <dns/rdataclass.h>
 
 #include <datasrc/memory_datasrc.h>
 
@@ -21,11 +22,52 @@
 
 using namespace isc::dns;
 using namespace isc::datasrc;
+using namespace isc::dns::rdata;
 
 namespace isc {
 namespace auth {
 
 void
+Query::getAdditional(const isc::datasrc::Zone& zone,
+                     const isc::dns::RRset& rrset) const
+{
+    if (rrset.getType() == RRType::NS()) {
+        // Need to perform the search in the "GLUE OK" mode.
+        RdataIteratorPtr rdata_iterator = rrset.getRdataIterator();
+        for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
+             const Rdata& rdata(rdata_iterator->getCurrent());
+             const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
+             findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
+        }
+    }
+}
+
+void
+Query::findAddrs(const isc::datasrc::Zone& zone,
+                 const isc::dns::Name& qname,
+                 const isc::datasrc::Zone::FindOptions options) const
+{
+    // Out of zone name
+    NameComparisonResult result = zone.getOrigin().compare(qname);
+    if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
+        (result.getRelation() != NameComparisonResult::EQUAL))
+        return;
+
+    // Find A rrset
+    Zone::FindResult a_result = zone.find(qname, RRType::A(), options);
+    if (a_result.code == Zone::SUCCESS) {
+        response_.addRRset(Message::SECTION_ADDITIONAL,
+                     boost::const_pointer_cast<RRset>(a_result.rrset));
+    }
+    // Find AAAA rrset
+    Zone::FindResult aaaa_result = zone.find(qname, RRType::AAAA(), options);
+    if (aaaa_result.code == Zone::SUCCESS) {
+        response_.addRRset(Message::SECTION_ADDITIONAL,
+                     boost::const_pointer_cast<RRset>(aaaa_result.rrset));
+    }
+}
+
+void
 Query::putSOA(const Zone& zone) const {
     Zone::FindResult soa_result(zone.find(zone.getOrigin(),
         RRType::SOA()));
@@ -74,7 +116,11 @@ Query::process() const {
                 // TODO : fill in authority and addtional sections.
                 break;
             case Zone::DELEGATION:
-                // TODO : add NS to authority section, fill in additional section.
+                response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
+                response_.setRcode(Rcode::NOERROR());
+                response_.addRRset(Message::SECTION_AUTHORITY,
+                            boost::const_pointer_cast<RRset>(db_result.rrset));
+                getAdditional(*result.zone, *db_result.rrset);
                 break;
             case Zone::NXDOMAIN:
                 // Just empty answer with SOA in authority section

+ 44 - 9
src/bin/auth/query.h

@@ -15,17 +15,18 @@
  */
 
 #include <exceptions/exceptions.h>
+#include <datasrc/zone.h>
 
 namespace isc {
 namespace dns {
 class Message;
 class Name;
 class RRType;
+class RRset;
 }
 
 namespace datasrc {
 class MemoryDataSrc;
-class Zone;
 }
 
 namespace auth {
@@ -63,6 +64,48 @@ namespace auth {
 /// accidentally, and since it's considered a temporary development state,
 /// we keep this name at the moment.
 class Query {
+private:
+
+    /// \short Adds a SOA.
+    ///
+    /// Adds a SOA of the zone into the authority zone of response_.
+    /// Can throw NoSOA.
+    ///
+    void putSOA(const isc::datasrc::Zone& zone) const;
+
+    /// Look up additional data (i.e., address records for the names included
+    /// in NS or MX records).
+    ///
+    /// This method may throw a exception because its underlying methods may
+    /// throw exceptions.
+    ///
+    /// \param zone The Zone wherein the additional data to the query is bo be
+    /// found.
+    /// \param rrset The RRset (i.e., NS or MX rrset) which require additional
+    /// processing.
+    void getAdditional(const isc::datasrc::Zone& zone,
+                       const isc::dns::RRset& rrset) const;
+
+    /// Find address records for a specified name.
+    ///
+    /// Search the specified zone for AAAA/A RRs of each of the NS/MX RDATA
+    /// (domain name), and insert the found ones into the additional section
+    /// if address records are available. By default the search will stop
+    /// once it encounters a zone cut.
+    ///
+    /// Note: we need to perform the search in the "GLUE OK" mode for NS RDATA,
+    /// which means that we should include A/AAAA RRs under a zone cut.
+    /// The glue records must exactly match the name in the NS RDATA, without
+    /// CNAME or wildcard processing.
+    ///
+    /// \param zone The Zone wherein the address records is to be found.
+    /// \param qname The name in rrset RDATA.
+    /// \param options The search options.
+    void findAddrs(const isc::datasrc::Zone& zone,
+                   const isc::dns::Name& qname,
+                   const isc::datasrc::Zone::FindOptions options
+                   = isc::datasrc::Zone::FIND_DEFAULT) const;
+
 public:
     /// Constructor from query parameters.
     ///
@@ -135,14 +178,6 @@ private:
     const isc::dns::Name& qname_;
     const isc::dns::RRType& qtype_;
     isc::dns::Message& response_;
-
-    /**
-     * \short Adds a SOA.
-     *
-     * Adds a SOA of the zone into the authority zone of response_.
-     * Can throw NoSOA.
-     */
-    void putSOA(const isc::datasrc::Zone& zone) const;
 };
 
 }

+ 1 - 0
src/bin/auth/tests/Makefile.am

@@ -33,6 +33,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la

+ 22 - 10
src/bin/auth/tests/auth_srv_unittest.cc

@@ -30,15 +30,19 @@
 
 #include <datasrc/memory_datasrc.h>
 #include <auth/auth_srv.h>
-#include <testutils/srv_unittest.h>
 #include <auth/statistics.h>
 
+#include <dns/tests/unittest_util.h>
+#include <testutils/srv_test.h>
+
+using namespace std;
 using namespace isc::cc;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::data;
 using namespace isc::xfr;
 using namespace asiolink;
+using namespace isc::testutils;
 using isc::UnitTestUtil;
 
 namespace {
@@ -55,6 +59,10 @@ protected:
         server.setXfrinSession(&notify_session);
         server.setStatisticsSession(&statistics_session);
     }
+    virtual void processMessage() {
+        server.processMessage(*io_message, parse_message, response_obuffer,
+                              &dnsserv);
+    }
     MockSession statistics_session;
     MockXfroutClient xfrout;
     AuthSrv server;
@@ -159,48 +167,52 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
 
 // Unsupported requests.  Should result in NOTIMP.
 TEST_F(AuthSrvTest, unsupportedRequest) {
-    UNSUPPORTED_REQUEST_TEST;
+    unsupportedRequest();
 }
 
 // Simple API check
 TEST_F(AuthSrvTest, verbose) {
-    VERBOSE_TEST;
+    EXPECT_FALSE(server.getVerbose());
+    server.setVerbose(true);
+    EXPECT_TRUE(server.getVerbose());
+    server.setVerbose(false);
+    EXPECT_FALSE(server.getVerbose());
 }
 
 // Multiple questions.  Should result in FORMERR.
 TEST_F(AuthSrvTest, multiQuestion) {
-    MULTI_QUESTION_TEST;
+    multiQuestion();
 }
 
 // Incoming data doesn't even contain the complete header.  Must be silently
 // dropped.
 TEST_F(AuthSrvTest, shortMessage) {
-    SHORT_MESSAGE_TEST;
+    shortMessage();
 }
 
 // Response messages.  Must be silently dropped, whether it's a valid response
 // or malformed or could otherwise cause a protocol error.
 TEST_F(AuthSrvTest, response) {
-    RESPONSE_TEST;
+    response();
 }
 
 // Query with a broken question
 TEST_F(AuthSrvTest, shortQuestion) {
-    SHORT_QUESTION_TEST;
+    shortQuestion();
 }
 
 // Query with a broken answer section
 TEST_F(AuthSrvTest, shortAnswer) {
-    SHORT_ANSWER_TEST;
+    shortAnswer();
 }
 
 // Query with unsupported version of EDNS.
 TEST_F(AuthSrvTest, ednsBadVers) {
-    EDNS_BADVERS_TEST;
+    ednsBadVers();
 }
 
 TEST_F(AuthSrvTest, AXFROverUDP) {
-    AXFR_OVER_UDP_TEST;
+    axfrOverUDP();
 }
 
 TEST_F(AuthSrvTest, AXFRSuccess) {

+ 81 - 7
src/bin/auth/tests/query_unittest.cc

@@ -17,6 +17,7 @@
 #include <dns/rcode.h>
 #include <dns/rrttl.h>
 #include <dns/rrtype.h>
+#include <dns/rdataclass.h>
 
 #include <datasrc/memory_datasrc.h>
 
@@ -36,19 +37,48 @@ RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
 RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
                                         RRClass::IN(), RRType::SOA(),
                                         RRTTL(3600)));
+RRsetPtr ns_rrset(RRsetPtr(new RRset(Name("ns.example.com"),
+                                     RRClass::IN(), RRType::NS(),
+                                     RRTTL(3600))));
+RRsetPtr glue_a_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
+                                         RRClass::IN(), RRType::A(),
+                                         RRTTL(3600))));
+RRsetPtr glue_aaaa_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
+                                            RRClass::IN(), RRType::AAAA(),
+                                            RRTTL(3600))));
+RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
+                                         RRClass::IN(), RRType::A(),
+                                         RRTTL(3600))));
 // This is a mock Zone class for testing.
 // It is a derived class of Zone, and simply hardcode the results of find()
 // return SUCCESS for "www.example.com",
 // return NXDOMAIN for "nxdomain.example.com",
 // return NXRRSET for "nxrrset.example.com",
 // return CNAME for "cname.example.com",
-// else return DNAME
+// otherwise return DNAME
 class MockZone : public Zone {
 public:
     MockZone(bool has_SOA = true) :
         origin_(Name("example.com")),
-        has_SOA_(has_SOA)
-    {}
+        has_SOA_(has_SOA),
+        delegation_rrset(RRsetPtr(new RRset(Name("delegation.example.com"),
+                                            RRClass::IN(), RRType::NS(),
+                                            RRTTL(3600)))),
+        cname_rrset(RRsetPtr(new RRset(Name("cname.example.com"),
+                                       RRClass::IN(), RRType::CNAME(),
+                                       RRTTL(3600))))
+    {
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("glue.ns.example.com")));
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("noglue.example.com")));
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("cname.example.com")));
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("example.org")));
+        cname_rrset->addRdata(rdata::generic::CNAME(
+                          Name("www.example.com")));
+    }
     virtual const isc::dns::Name& getOrigin() const;
     virtual const isc::dns::RRClass& getClass() const;
 
@@ -59,6 +89,8 @@ public:
 private:
     Name origin_;
     bool has_SOA_;
+    RRsetPtr delegation_rrset;
+    RRsetPtr cname_rrset;
 };
 
 const Name&
@@ -72,22 +104,34 @@ MockZone::getClass() const {
 }
 
 Zone::FindResult
-MockZone::find(const Name& name, const RRType& type, const FindOptions) const {
+MockZone::find(const Name& name, const RRType& type,
+               const FindOptions options) const
+{
     // hardcode the find results
     if (name == Name("www.example.com")) {
         return (FindResult(SUCCESS, a_rrset));
+    } else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
+        options == FIND_GLUE_OK) {
+        return (FindResult(SUCCESS, glue_a_rrset));
+    } else if (name == Name("noglue.example.com") && type == RRType::A()) {
+        return (FindResult(SUCCESS, noglue_a_rrset));
+    } else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
+        options == FIND_GLUE_OK) {
+        return (FindResult(SUCCESS, glue_aaaa_rrset));
     } else if (name == Name("example.com") && type == RRType::SOA() &&
         has_SOA_)
     {
         return (FindResult(SUCCESS, soa_rrset));
     } else if (name == Name("delegation.example.com")) {
-        return (FindResult(DELEGATION, RRsetPtr()));
+        return (FindResult(DELEGATION, delegation_rrset));
+    } else if (name == Name("ns.example.com")) {
+        return (FindResult(DELEGATION, ns_rrset));
     } else if (name == Name("nxdomain.example.com")) {
         return (FindResult(NXDOMAIN, RRsetPtr()));
     } else if (name == Name("nxrrset.example.com")) {
         return (FindResult(NXRRSET, RRsetPtr()));
-    } else if (name == Name("cname.example.com")) {
-        return (FindResult(CNAME, RRsetPtr()));
+    } else if ((name == Name("cname.example.com"))) {
+        return (FindResult(CNAME, cname_rrset));
     } else {
         return (FindResult(DNAME, RRsetPtr()));
     }
@@ -121,11 +165,41 @@ TEST_F(QueryTest, matchZone) {
     // add a matching zone.
     memory_datasrc.addZone(ZonePtr(new MockZone()));
     query.process();
+    EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
     EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
     EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
                                   Name("www.example.com"), RRClass::IN(),
                                   RRType::A()));
 
+    // Delegation
+    const Name delegation_name(Name("delegation.example.com"));
+    Query delegation_query(memory_datasrc, delegation_name, qtype, response);
+    delegation_query.process();
+    EXPECT_FALSE(response.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
+                                  Name("delegation.example.com"),
+                                  RRClass::IN(), RRType::NS()));
+    // glue address records
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
+    // noglue address records
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("noglue.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    // NS name has a CNAME
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("www.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    // NS name is out of zone
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("example.org"),
+                                  RRClass::IN(), RRType::A()));
+
     // NXDOMAIN
     const Name nxdomain_name(Name("nxdomain.example.com"));
     Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);

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

@@ -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)

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

@@ -0,0 +1 @@
+SUBDIRS = tests

+ 37 - 0
src/lib/asiolink/internal/tests/Makefile.am

@@ -0,0 +1,37 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+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)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+run_unittests_CXXFLAGS += -Wno-unused-parameter
+endif
+if USE_CLANGPP
+# We need to disable -Werror for any test that uses internal definitions of
+# ASIO when using clang++
+run_unittests_CXXFLAGS += -Wno-error
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)

+ 21 - 0
src/lib/asiolink/internal/tests/run_unittests.cc

@@ -0,0 +1,21 @@
+// Copyright (C) 2010  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
+// 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>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return (RUN_ALL_TESTS());
+}

src/lib/asiolink/tests/udpdns_unittest.cc → src/lib/asiolink/internal/tests/udpdns_unittest.cc


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

@@ -18,7 +18,6 @@ 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)

+ 72 - 40
src/lib/asiolink/tests/asiolink_unittest.cc

@@ -17,6 +17,9 @@
 
 #include <config.h>
 
+#include <sys/socket.h>
+#include <sys/time.h>
+
 #include <string.h>
 
 #include <boost/lexical_cast.hpp>
@@ -32,19 +35,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";
@@ -330,10 +335,30 @@ protected:
         // ... 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 };
+        int recv_options = 0;
+        if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
+                       sizeof(timeo))) {
+            if (errno == ENOPROTOOPT) {
+                // Workaround for Solaris: it doesn't accept SO_RCVTIMEO
+                // with the error of ENOPROTOOPT.  Since this is a workaround
+                // for rare error cases anyway, we simply switch to the
+                // "don't wait" mode.  If we still find an error in recv()
+                // can happen often we'll consider a more complete solution.
+                recv_options = MSG_DONTWAIT;
+            } else {
+                isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
+            }
+        }
+        const int ret = recv(sock_, buffer, size, recv_options);
         if (ret < 0) {
-            isc_throw(IOError, "recvfrom failed");
+            isc_throw(IOError, "recvfrom failed: " << strerror(errno));
         }
         
         // Pass the message size back via the size parameter
@@ -411,8 +436,7 @@ protected:
     // 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) :
@@ -426,9 +450,7 @@ protected:
                         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() {
@@ -443,7 +465,7 @@ protected:
         }
 
     protected:
-        asio::io_service& io_;
+        IOService& io_;
         bool done_;
 
     private:
@@ -462,8 +484,8 @@ protected:
     // 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)
             {}
 
@@ -511,7 +533,6 @@ protected:
     string callback_address_;
     vector<uint8_t> callback_data_;
     int sock_;
-private:
     struct addrinfo* res_;
 };
 
@@ -640,14 +661,12 @@ TEST_F(ASIOLinkTest, recursiveSetupV6) {
 // 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());
@@ -656,7 +675,7 @@ TEST_F(ASIOLinkTest, recursiveSend) {
 
     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);
@@ -672,34 +691,27 @@ TEST_F(ASIOLinkTest, recursiveSend) {
     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());
@@ -707,7 +719,27 @@ TEST_F(ASIOLinkTest, recursiveTimeout) {
     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 };
+    int recv_options = 0;
+    if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
+        if (errno == ENOPROTOOPT) { // see ASIOLinkTest::recvUDP()
+            recv_options = MSG_DONTWAIT;
+        } else {
+            isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
+        }
+    }
+    int num = 0;
+    do {
+        char inbuff[512];
+        if (recv(sock_, inbuff, sizeof(inbuff), recv_options) < 0) {
+            num = -1;
+            break;
+        }
+    } while (++num < 3);
 
     // The query should fail
     EXPECT_FALSE(done);

+ 2 - 2
src/lib/datasrc/cache.h

@@ -81,7 +81,7 @@ class HotCacheImpl;
 /// from the tail of the list.  This operation is not locked.  BIND 10
 /// does not currently use threads, but if it ever does (or if libdatasrc
 /// is ever used by a threaded application), this will need to be
-//revisited.
+/// revisited.
 class HotCache {
 private:
     /// \name Static definitions
@@ -164,7 +164,7 @@ public:
     ///
     /// Retrieves a record from the cache matching the given 
     /// query-tuple.  Returns true if one is found.  If it is a
-    /// posiitve cache entry, then 'rrset' is set to the cached
+    /// positive cache entry, then 'rrset' is set to the cached
     /// RRset.  For both positive and negative cache entries, 'flags'
     /// is set to the query response flags.  The cache entry is 
     /// then promoted to the head of the LRU queue.  (NOTE: Because

+ 2 - 2
src/lib/datasrc/data_source.cc

@@ -103,14 +103,14 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
                                new QueryTask(q, ns.getNSName(),
                                              Message::SECTION_ADDITIONAL,
                                              QueryTask::GLUE_QUERY,
-                                             QueryTask::GETADDITIONAL))); 
+                                             QueryTask::GETADDITIONAL)));
         } else if (rrset->getType() == RRType::MX()) {
             const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
             q.tasks().push(QueryTaskPtr(
                                new QueryTask(q, mx.getMXName(),
                                              Message::SECTION_ADDITIONAL,
                                              QueryTask::NOGLUE_QUERY,
-                                             QueryTask::GETADDITIONAL))); 
+                                             QueryTask::GETADDITIONAL)));
         }
     }
 }

+ 2 - 2
src/lib/datasrc/rbtree.h

@@ -672,7 +672,7 @@ void
 RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
     using namespace helper;
     const isc::dns::Name sub_name = node.name_ - base_name;
-    // using auto_ptr here is to avoid memory leak in case of exceptoin raised
+    // using auto_ptr here is to avoid memory leak in case of exception raised
     // after the RBNode creation
     std::auto_ptr<RBNode<T> > down_node(new RBNode<T>(sub_name));
     std::swap(node.data_, down_node->data_);
@@ -680,7 +680,7 @@ RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
     down_node->down_ = node.down_;
     node.name_ = base_name;
     node.down_ = down_node.get();
-    //root node of sub tree, the initial color is BLACK
+    // root node of sub tree, the initial color is BLACK
     down_node->color_ = RBNode<T>::BLACK;
     ++node_count_;
     down_node.release();

+ 12 - 4
src/lib/testutils/Makefile.am

@@ -1,5 +1,13 @@
-SUBDIRS = testdata
+SUBDIRS = . testdata
 
-EXTRA_DIST = srv_test.h
-EXTRA_DIST += srv_unittest.h
-EXTRA_DIST += mockups.h
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS=$(B10_CXXFLAGS)
+
+if HAVE_GTEST
+lib_LTLIBRARIES = libtestutils.la
+
+libtestutils_la_SOURCES = srv_test.h srv_test.cc
+libtestutils_la_SOURCES += mockups.h
+libtestutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+endif

+ 0 - 2
src/lib/testutils/README

@@ -1,4 +1,2 @@
 Here is some code used by more than one test. No code is used for bind10
 itself, only for testing.
-
-As it contains headers only currently, it does not compile here.

+ 272 - 0
src/lib/testutils/srv_test.cc

@@ -0,0 +1,272 @@
+// Copyright (C) 2010  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
+// 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 <netinet/in.h>
+
+#include <dns/message.h>
+#include <dns/rcode.h>
+
+#include <asiolink/asiolink.h>
+
+#include <dns/tests/unittest_util.h>
+
+#include <testutils/srv_test.h>
+
+using namespace isc::dns;
+using namespace asiolink;
+
+namespace isc {
+namespace testutils {
+const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
+
+const unsigned int QR_FLAG = 0x1;
+const unsigned int AA_FLAG = 0x2;
+const unsigned int TC_FLAG = 0x4;
+const unsigned int RD_FLAG = 0x8;
+const unsigned int RA_FLAG = 0x10;
+const unsigned int AD_FLAG = 0x20;
+const unsigned int CD_FLAG = 0x40;
+
+SrvTestBase::SrvTestBase() : request_message(Message::RENDER),
+                             parse_message(new Message(Message::PARSE)),
+                             default_qid(0x1035),
+                             opcode(Opcode(Opcode::QUERY())),
+                             qname("www.example.com"),
+                             qclass(RRClass::IN()),
+                             qtype(RRType::A()), io_sock(NULL),
+                             io_message(NULL), endpoint(NULL),
+                             request_obuffer(0),
+                             request_renderer(request_obuffer),
+                             response_obuffer(new OutputBuffer(0))
+{}
+
+SrvTestBase::~SrvTestBase() {
+    delete io_message;
+    delete endpoint;
+}
+
+void
+SrvTestBase::createDataFromFile(const char* const datafile,
+                                const int protocol)
+{
+    delete io_message;
+    data.clear();
+
+    delete endpoint;
+
+    endpoint = IOEndpoint::create(protocol,
+                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+    UnitTestUtil::readWireData(datafile, data);
+    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
+        &IOSocket::getDummyTCPSocket();
+    io_message = new IOMessage(&data[0], data.size(), *io_sock, *endpoint);
+}
+
+void
+SrvTestBase::createRequestPacket(Message& message,
+                                 const int protocol)
+{
+    message.toWire(request_renderer);
+
+    delete io_message;
+
+    endpoint = IOEndpoint::create(protocol,
+                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
+        &IOSocket::getDummyTCPSocket();
+    io_message = new IOMessage(request_renderer.getData(),
+                               request_renderer.getLength(),
+                               *io_sock, *endpoint);
+}
+
+// Unsupported requests.  Should result in NOTIMP.
+void
+SrvTestBase::unsupportedRequest() {
+    for (unsigned int i = 0; i < 16; ++i) {
+        // set Opcode to 'i', which iterators over all possible codes except
+        // the standard query and notify 
+        if (i == isc::dns::Opcode::QUERY().getCode() ||
+            i == isc::dns::Opcode::NOTIFY().getCode()) {
+            continue;
+        }
+        createDataFromFile("simplequery_fromWire.wire");
+        data[2] = ((i << 3) & 0xff);
+
+        parse_message->clear(isc::dns::Message::PARSE);
+        processMessage();
+        EXPECT_TRUE(dnsserv.hasAnswer());
+        headerCheck(*parse_message, default_qid, isc::dns::Rcode::NOTIMP(), i,
+                    QR_FLAG, 0, 0, 0, 0);
+    }
+}
+
+// Multiple questions.  Should result in FORMERR.
+void
+SrvTestBase::multiQuestion() {
+    createDataFromFile("multiquestion_fromWire.wire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 2, 0, 0, 0);
+
+    isc::dns::QuestionIterator qit = parse_message->beginQuestion();
+    EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
+    EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
+    EXPECT_EQ(isc::dns::RRType::A(), (*qit)->getType());
+    ++qit;
+    EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
+    EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
+    EXPECT_EQ(isc::dns::RRType::AAAA(), (*qit)->getType());
+    ++qit;
+    EXPECT_TRUE(qit == parse_message->endQuestion());
+}
+
+// Incoming data doesn't even contain the complete header.  Must be silently
+// dropped.
+void
+SrvTestBase::shortMessage() {
+    createDataFromFile("shortmessage_fromWire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+}
+
+// Response messages.  Must be silently dropped, whether it's a valid response
+// or malformed or could otherwise cause a protocol error.
+void
+SrvTestBase::response() {
+    // A valid (although unusual) response 
+    createDataFromFile("simpleresponse_fromWire.wire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+
+    // A response with a broken question section.  must be dropped rather than
+    //returning FORMERR.
+    createDataFromFile("shortresponse_fromWire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+
+    // A response to iquery.  must be dropped rather than returning NOTIMP.
+    createDataFromFile("iqueryresponse_fromWire.wire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+}
+
+// Query with a broken question
+void
+SrvTestBase::shortQuestion() {
+    createDataFromFile("shortquestion_fromWire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    // Since the query's question is broken, the question section of the
+    // response should be empty.
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 0, 0, 0, 0);
+}
+
+// Query with a broken answer section
+void
+SrvTestBase::shortAnswer() {
+    createDataFromFile("shortanswer_fromWire.wire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+
+    // This is a bogus query, but question section is valid.  So the response
+    // should copy the question section.
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+
+    isc::dns::QuestionIterator qit = parse_message->beginQuestion();
+    EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
+    EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
+    EXPECT_EQ(isc::dns::RRType::A(), (*qit)->getType());
+    ++qit;
+    EXPECT_TRUE(qit == parse_message->endQuestion());
+}
+
+// Query with unsupported version of EDNS.
+void
+SrvTestBase::ednsBadVers() {
+    createDataFromFile("queryBadEDNS_fromWire.wire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+
+    // The response must have an EDNS OPT RR in the additional section,
+    // it will be added automatically at the render time.
+    // Note that the DNSSEC DO bit is cleared even if this bit in the query
+    // is set.  This is a limitation of the current implementation.
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::BADVERS(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 1);
+    EXPECT_FALSE(parse_message->getEDNS()); // EDNS isn't added at this point
+
+    isc::dns::InputBuffer ib(response_obuffer->getData(),
+                             response_obuffer->getLength());
+    isc::dns::Message parsed(isc::dns::Message::PARSE);
+    parsed.fromWire(ib);
+    EXPECT_EQ(isc::dns::Rcode::BADVERS(), parsed.getRcode());
+    isc::dns::ConstEDNSPtr edns(parsed.getEDNS());
+    ASSERT_TRUE(edns);
+    EXPECT_FALSE(edns->getDNSSECAwareness());
+}
+
+void
+SrvTestBase::axfrOverUDP() {
+    // AXFR over UDP is invalid and should result in FORMERR.
+    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+                                       isc::dns::Name("example.com"),
+                                       isc::dns::RRClass::IN(),
+                                       isc::dns::RRType::AXFR());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+}
+
+void
+headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
+            const uint16_t opcodeval, const unsigned int flags,
+            const unsigned int qdcount,
+            const unsigned int ancount, const unsigned int nscount,
+            const unsigned int arcount)
+{
+    EXPECT_EQ(qid, message.getQid());
+    EXPECT_EQ(rcode, message.getRcode());
+    EXPECT_EQ(opcodeval, message.getOpcode().getCode());
+    EXPECT_EQ((flags & QR_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_QR));
+    EXPECT_EQ((flags & AA_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ((flags & TC_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_TC));
+    EXPECT_EQ((flags & RA_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_RA));
+    EXPECT_EQ((flags & RD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_RD));
+    EXPECT_EQ((flags & AD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_AD));
+    EXPECT_EQ((flags & CD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_CD));
+
+    EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
+    EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
+}
+} // end of namespace testutils
+} // end of namespace isc
+
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 82 - 126
src/lib/testutils/srv_test.h

@@ -12,10 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id: auth_srv_unittest.cc 3310 2010-10-21 23:10:24Z each $
-
-#include <config.h>
-
 #include <gtest/gtest.h>
 
 #include <dns/buffer.h>
@@ -27,139 +23,99 @@
 #include <dns/rrclass.h>
 #include <dns/rrtype.h>
 
-#include <cc/data.h>
-#include <cc/session.h>
-
-#include <xfr/xfrout_client.h>
-
-#include <auth/auth_srv.h>
-#include <asiolink/asiolink.h>
-
-#include <dns/tests/unittest_util.h>
 #include "mockups.h"
 
-using namespace std;
-using namespace isc::cc;
-using namespace isc::dns;
-using namespace isc::data;
-using namespace isc::xfr;
-using namespace asiolink;
-using isc::UnitTestUtil;
-
-namespace {
-const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
-
-// The base class for Auth and Resolver test case
-class SrvTestBase : public ::testing::Test {
-protected:
-    SrvTestBase() : request_message(Message::RENDER),
-                    parse_message(new Message(Message::PARSE)),
-                    default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
-                    qname("www.example.com"), qclass(RRClass::IN()),
-                    qtype(RRType::A()), io_sock(NULL), 
-                    io_message(NULL), endpoint(NULL),
-                    request_obuffer(0), request_renderer(request_obuffer),
-                    response_obuffer(new OutputBuffer(0))
-    {}
-    ~SrvTestBase() {
-        delete io_message;
-        delete endpoint;
-    }
-    MockSession notify_session;
-    MockServer dnsserv;
-    Message request_message;
-    MessagePtr parse_message;
-    const qid_t default_qid;
-    const Opcode opcode;
-    const Name qname;
-    const RRClass qclass;
-    const RRType qtype;
-    IOSocket* io_sock;
-    IOMessage* io_message;
-    const IOEndpoint* endpoint;
-    OutputBuffer request_obuffer;
-    MessageRenderer request_renderer;
-    OutputBufferPtr response_obuffer;
-    vector<uint8_t> data;
-
-    void createDataFromFile(const char* const datafile, int protocol);
-    void createRequestPacket(Message& message, const int protocol);
-};
-
-void
-SrvTestBase::createDataFromFile(const char* const datafile,
-                                const int protocol = IPPROTO_UDP)
-{
-    delete io_message;
-    data.clear();
-
-    delete endpoint;
-
-    endpoint = IOEndpoint::create(protocol,
-                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
-    UnitTestUtil::readWireData(datafile, data);
-    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
-        &IOSocket::getDummyTCPSocket();
-    io_message = new IOMessage(&data[0], data.size(), *io_sock, *endpoint);
+namespace asiolink {
+class IOSocket;
+class IOMessage;
+class IOEndpoint;
 }
 
-void
-SrvTestBase::createRequestPacket(Message& message,
-                                 const int protocol = IPPROTO_UDP)
-{
-    message.toWire(request_renderer);
-
-    delete io_message;
-
-    endpoint = IOEndpoint::create(protocol,
-                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
-    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
-        &IOSocket::getDummyTCPSocket();
-    io_message = new IOMessage(request_renderer.getData(),
-                               request_renderer.getLength(),
-                               *io_sock, *endpoint);
-}
+namespace isc {
+namespace testutils {
+extern const char* const DEFAULT_REMOTE_ADDRESS;
 
 // These are flags to indicate whether the corresponding flag bit of the
-// DNS header is to be set in the test cases.  (Note that the flag values
+// DNS header is to be set in the test cases.  (The flag values
 // is irrelevant to their wire-format values)
-const unsigned int QR_FLAG = 0x1;
-const unsigned int AA_FLAG = 0x2;
-const unsigned int TC_FLAG = 0x4;
-const unsigned int RD_FLAG = 0x8;
-const unsigned int RA_FLAG = 0x10;
-const unsigned int AD_FLAG = 0x20;
-const unsigned int CD_FLAG = 0x40;
+extern const unsigned int QR_FLAG;
+extern const unsigned int AA_FLAG;
+extern const unsigned int TC_FLAG;
+extern const unsigned int RD_FLAG;
+extern const unsigned int RA_FLAG;
+extern const unsigned int AD_FLAG;
+extern const unsigned int CD_FLAG;
 
 void
-headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
+headerCheck(const isc::dns::Message& message, const isc::dns::qid_t qid,
+            const isc::dns::Rcode& rcode,
             const uint16_t opcodeval, const unsigned int flags,
             const unsigned int qdcount,
             const unsigned int ancount, const unsigned int nscount,
-            const unsigned int arcount)
-{
-    EXPECT_EQ(qid, message.getQid());
-    EXPECT_EQ(rcode, message.getRcode());
-    EXPECT_EQ(opcodeval, message.getOpcode().getCode());
-    EXPECT_EQ((flags & QR_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_QR));
-    EXPECT_EQ((flags & AA_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_AA));
-    EXPECT_EQ((flags & TC_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_TC));
-    EXPECT_EQ((flags & RA_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_RA));
-    EXPECT_EQ((flags & RD_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_RD));
-    EXPECT_EQ((flags & AD_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_AD));
-    EXPECT_EQ((flags & CD_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_CD));
+            const unsigned int arcount);
 
-    EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
-    EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
-    EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
-    EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
-}
+// The base class for Auth and Recurse test case
+class SrvTestBase : public ::testing::Test {
+protected:
+    SrvTestBase();
+    virtual ~SrvTestBase();
+
+    /// Let the server process a DNS message.
+    ///
+    /// The derived class implementation is expected to pass \c io_message,
+    /// \c parse_message, \c response_obuffer, and \c dnsserv to the server
+    /// implementation it is testing.
+    virtual void processMessage() = 0;
+
+    /// The following methods implement server independent test logic using
+    /// the template method pattern.  Each test calls \c processMessage()
+    /// to delegate the server-dependent behavior to the actual implementation
+    /// classes.
+    void unsupportedRequest();
+    void multiQuestion();
+    void shortMessage();
+    void response();
+    void shortQuestion();
+    void shortAnswer();
+    void ednsBadVers();
+    void axfrOverUDP();
+
+    /// Create DNS packet data from a file.
+    ///
+    /// It constructs wire-format DNS packet data from \c datafile in the
+    /// form of \c IOMessage in \c io_message.
+    /// The existing content of \c io_message, if any, will be deleted.
+    void createDataFromFile(const char* const datafile,
+                            int protocol = IPPROTO_UDP);
+
+    ///  Create DNS packet data from a message.
+    ///
+    /// It constructs wire-format DNS packet data from \c message in the
+    /// form of \c IOMessage in \c io_message.
+    /// The existing content of \c io_message, if any, will be deleted.
+    void createRequestPacket(isc::dns::Message& message,
+                             const int protocol = IPPROTO_UDP);
 
-}
+    MockSession notify_session;
+    MockServer dnsserv;
+    isc::dns::Message request_message;
+    isc::dns::MessagePtr parse_message;
+    const isc::dns::qid_t default_qid;
+    const isc::dns::Opcode opcode;
+    const isc::dns::Name qname;
+    const isc::dns::RRClass qclass;
+    const isc::dns::RRType qtype;
+    asiolink::IOSocket* io_sock;
+    asiolink::IOMessage* io_message;
+    const asiolink::IOEndpoint* endpoint;
+    isc::dns::OutputBuffer request_obuffer;
+    isc::dns::MessageRenderer request_renderer;
+    isc::dns::OutputBufferPtr response_obuffer;
+    std::vector<uint8_t> data;
+};
+} // end of namespace testutils
+} // end of namespace isc
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 0 - 158
src/lib/testutils/srv_unittest.h

@@ -1,158 +0,0 @@
-// Copyright (C) 2010  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
-// 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.
-
-// $Id: auth_srv_unittest.cc 3310 2010-10-21 23:10:24Z each $
-
-#include "srv_test.h"
-
-namespace {
-
-// Unsupported requests.  Should result in NOTIMP.
-#define UNSUPPORTED_REQUEST_TEST \
-    for (unsigned int i = 0; i < 16; ++i) { \
-        /* set Opcode to 'i', which iterators over all possible codes except \
-           the standard query and notify */ \
-        if (i == Opcode::QUERY().getCode() || \
-            i == Opcode::NOTIFY().getCode()) { \
-            continue; \
-        } \
-        createDataFromFile("simplequery_fromWire.wire"); \
-        data[2] = ((i << 3) & 0xff); \
- \
-        parse_message->clear(Message::PARSE); \
-        server.processMessage(*io_message, parse_message, response_obuffer, \
-                              &dnsserv); \
-        EXPECT_TRUE(dnsserv.hasAnswer()); \
-        headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG, \
-                    0, 0, 0, 0); \
-    }
-
-// Simple API check
-#define VERBOSE_TEST \
-    EXPECT_FALSE(server.getVerbose()); \
-    server.setVerbose(true); \
-    EXPECT_TRUE(server.getVerbose()); \
-    server.setVerbose(false); \
-    EXPECT_FALSE(server.getVerbose()); \
-
-
-// Multiple questions.  Should result in FORMERR.
-#define MULTI_QUESTION_TEST \
-    createDataFromFile("multiquestion_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 2, 0, 0, 0); \
- \
-    QuestionIterator qit = parse_message->beginQuestion(); \
-    EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
-    EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
-    EXPECT_EQ(RRType::A(), (*qit)->getType()); \
-    ++qit; \
-    EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
-    EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
-    EXPECT_EQ(RRType::AAAA(), (*qit)->getType()); \
-    ++qit; \
-    EXPECT_TRUE(qit == parse_message->endQuestion());
-
-// Incoming data doesn't even contain the complete header.  Must be silently
-// dropped.
-#define SHORT_MESSAGE_TEST \
-    createDataFromFile("shortmessage_fromWire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer());
-
-// Response messages.  Must be silently dropped, whether it's a valid response
-// or malformed or could otherwise cause a protocol error.
-#define RESPONSE_TEST \
-    /* A valid (although unusual) response */\
-    createDataFromFile("simpleresponse_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer()); \
- \
-    /* A response with a broken question section.  must be dropped rather than \
-       returning FORMERR. */\
-    createDataFromFile("shortresponse_fromWire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer()); \
- \
-    /* A response to iquery.  must be dropped rather than returning NOTIMP. */\
-    createDataFromFile("iqueryresponse_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer());
-
-// Query with a broken question
-#define SHORT_QUESTION_TEST \
-    createDataFromFile("shortquestion_fromWire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
-    /* Since the query's question is broken, the question section of the \
-       response should be empty. */\
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 0, 0, 0, 0);
-
-// Query with a broken answer section
-#define SHORT_ANSWER_TEST \
-    createDataFromFile("shortanswer_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
- \
-    /* This is a bogus query, but question section is valid.  So the response \
-       should copy the question section. */ \
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 1, 0, 0, 0); \
- \
-    QuestionIterator qit = parse_message->beginQuestion(); \
-    EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
-    EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
-    EXPECT_EQ(RRType::A(), (*qit)->getType()); \
-    ++qit; \
-    EXPECT_TRUE(qit == parse_message->endQuestion());
-
-// Query with unsupported version of EDNS.
-#define EDNS_BADVERS_TEST \
-    createDataFromFile("queryBadEDNS_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
- \
-    /* The response must have an EDNS OPT RR in the additional section, \
-       it will be added automatically at the render time.
-       Note that the DNSSEC DO bit is cleared even if this bit in the query \
-       is set.  This is a limitation of the current implementation. */ \
-    headerCheck(*parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(), \
-                QR_FLAG, 1, 0, 0, 1); \
-    EXPECT_FALSE(parse_message->getEDNS()); /* EDNS isn't added at this point */ \
- \
-    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength()); \
-    Message parsed(Message::PARSE); \
-    parsed.fromWire(ib); \
-    EXPECT_EQ(Rcode::BADVERS(), parsed.getRcode()); \
-    ConstEDNSPtr edns(parsed.getEDNS()); \
-    ASSERT_TRUE(edns); \
-    EXPECT_FALSE(edns->getDNSSECAwareness());
-
-
-#define AXFR_OVER_UDP_TEST \
-    /* AXFR over UDP is invalid and should result in FORMERR. */\
-    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid, \
-                         Name("example.com"), RRClass::IN(), \
-                         RRType::AXFR()); \
-    createRequestPacket(request_message, IPPROTO_UDP); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 1, 0, 0, 0);
-
-}
-