Browse Source

[1605] Added basic class and tests (all of which fail)

Currently no RRSIG-related methods added yet.
Stephen Morris 13 years ago
parent
commit
7626330333

+ 1 - 0
src/lib/datasrc/Makefile.am

@@ -21,6 +21,7 @@ libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
 libdatasrc_la_SOURCES += query.h query.cc
 libdatasrc_la_SOURCES += cache.h cache.cc
+libdatasrc_la_SOURCES += rbnode_rrset.h
 libdatasrc_la_SOURCES += rbtree.h
 libdatasrc_la_SOURCES += zonetable.h zonetable.cc
 libdatasrc_la_SOURCES += zone.h

+ 173 - 0
src/lib/datasrc/rbnode_rrset.h

@@ -0,0 +1,173 @@
+// Copyright (C) 2012  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.
+
+#ifndef __RBNODE_RRSET_H
+#define __RBNODE_RRSET_H
+
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <dns/rrttl.h>
+#include <dns/rrtype.h>
+#include <util/buffer.h>
+
+#include <string>
+
+namespace isc {
+namespace datasrc {
+
+/// \brief Special RRset for optimiing memory datasource requirement
+///
+/// To speed up the performance of the in-memory data source, at load time
+/// associate relevant "additional section" data with each RRset in the
+/// data source.
+///
+/// This class, derived from AbstractRRset, holds a "const" pointer to the
+/// underlying RRset object.  All calls to methods on the class are passed to
+/// the underlying object.  However, there are some restrictions:
+///
+/// - Calls to methods that change attributes of the underlying RRset (such as
+///   TTL or Name) cause an exception to be thrown.  The in-memory data source
+///   does not allow modification of these attributes.
+/// - Calls that modify the associated RRSIGs of the RRset are allowed (even
+///   though the pointer is to a "const" object).  The reason here is because
+///   RRSIGs are added to the in-memory data source after the RBNodeRRset
+///   objects have been created.  Thus there has to be the capability of
+///   modifying this information.
+///
+/// The class is not derived from RRset itself to simplify coding: part of the
+/// loading of the memory data source is handled in the BIND 10 "libdns++"
+/// code, which creates RRsets and passes them to the data source code.  This
+/// does not have to be altered if encapsulation, rather than inheritcance, is
+/// used.
+
+// Note: non-Doxygen-documented methods are documented in the base class.
+
+class RBNodeRRset : public isc::dns::AbstractRRset {
+
+private:
+    // Note: The copy constructor and the assignment operator are intentionally
+    // defined as private as we would normally not duplicate a RBNodeRRset.
+    RBNodeRRset(const RBNodeRRset& source);
+    RBNodeRRset& operator=(const RBNodeRRset& source);
+
+public:
+    /// \brief Usual Constructor
+    ///
+    /// Creates an RBNodeRRset from the pointer to the RRset passed to it.
+    RBNodeRRset(const isc::dns::ConstRRsetPtr& rrset) : rrset_(rrset),
+        n("a.com"), c("HS"), t("A"), ttl(0) {}
+
+    /// \brief Destructor
+    virtual ~RBNodeRRset() {}
+
+    // Getter and Setter Methods
+    //
+    // The getter methods pass the call through to the underlying RRset.  The
+    // setter methods thrown an exception - this specialisation of the RRset
+    // object does not expect the underlying RRset to be modified.
+
+    virtual unsigned int getRdataCount() const {
+        return (0);
+    }
+
+    virtual const isc::dns::Name& getName() const {
+        return (n);
+    }
+
+    virtual const isc::dns::RRClass& getClass() const {
+        return (c);
+    }
+
+    virtual const isc::dns::RRType& getType() const {
+        return (t);
+    }
+
+    virtual const isc::dns::RRTTL& getTTL() const {
+        return (ttl);
+    }
+
+    virtual void setName(const isc::dns::Name&) {
+    }
+
+    virtual void setTTL(const isc::dns::RRTTL&) {
+    }
+
+    virtual std::string toText() const {
+        return (std::string());
+    }
+
+    virtual unsigned int toWire(isc::dns::AbstractMessageRenderer& /*renderer*/) const {
+        return (-1);
+    }
+
+    virtual unsigned int toWire(isc::util::OutputBuffer& /*buffer*/) const {
+        return (-1);
+    }
+
+    virtual void addRdata(isc::dns::rdata::ConstRdataPtr) {
+    }
+
+    virtual void addRdata(const isc::dns::rdata::Rdata&) {
+    }
+
+    virtual isc::dns::RdataIteratorPtr getRdataIterator() const {
+        isc::dns::BasicRRset b(isc::dns::Name("example.com"),
+                               isc::dns::RRClass("IN"),
+                               isc::dns::RRType("A"),
+                               isc::dns::RRTTL(1));
+        return (b.getRdataIterator());
+    }
+
+    virtual isc::dns::RRsetPtr getRRsig() const {
+        return (isc::dns::RRsetPtr());
+    }
+
+    virtual void addRRsig(const isc::dns::rdata::ConstRdataPtr& /*rdata*/) {
+    }
+
+    virtual void addRRsig(const isc::dns::rdata::RdataPtr& /*rdata*/) {
+    }
+
+    virtual void addRRsig(const AbstractRRset& /*sigs*/) {
+    }
+
+    virtual void addRRsig(const isc::dns::ConstRRsetPtr& /*sigs*/) {
+    }
+
+    virtual void addRRsig(const isc::dns::RRsetPtr& /*sigs*/) {
+    }
+
+    virtual void removeRRsig() {
+    }
+
+    /// \brief Return underlying RRset pointer
+    virtual isc::dns::ConstRRsetPtr getUnderlyingRRset() const {
+        return rrset_;
+    }
+
+private:
+    isc::dns::ConstRRsetPtr rrset_;     ///< Underlying RRset
+
+    isc::dns::Name n;
+    isc::dns::RRClass c;
+    isc::dns::RRType t;
+    isc::dns::RRTTL ttl;
+};
+
+}   // namespace datasrc
+}   // namespace isc
+
+#endif  // __RBNODE_RRSET_H

+ 7 - 4
src/lib/datasrc/tests/Makefile.am

@@ -79,6 +79,7 @@ run_unittests_sqlite3_LDADD = $(common_ldadd)
 # In-memory datasource tests
 run_unittests_memory_SOURCES = $(common_sources)
 run_unittests_memory_SOURCES += memory_datasrc_unittest.cc
+run_unittests_memory_SOURCES += rbnode_rrset_unittest.cc
 run_unittests_memory_SOURCES += $(top_srcdir)/src/lib/datasrc/memory_datasrc.cc
 
 run_unittests_memory_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
@@ -109,19 +110,21 @@ endif
 endif
 
 EXTRA_DIST =  testdata/brokendb.sqlite3
+EXTRA_DIST += testdata/diffs.sqlite3
+EXTRA_DIST += testdata/example2.com
+EXTRA_DIST += testdata/example2.com.sqlite3
 EXTRA_DIST += testdata/example.com.signed
 EXTRA_DIST += testdata/example.org
 EXTRA_DIST += testdata/example.org.nsec3-signed
 EXTRA_DIST += testdata/example.org.nsec3-signed-noparam
 EXTRA_DIST += testdata/example.org.sqlite3
-EXTRA_DIST += testdata/example2.com
-EXTRA_DIST += testdata/example2.com.sqlite3
 EXTRA_DIST += testdata/mkbrokendb.c
 EXTRA_DIST += testdata/root.zone
+EXTRA_DIST += testdata/rrset_toWire1
+EXTRA_DIST += testdata/rrset_toWire2
+EXTRA_DIST += testdata/rwtest.sqlite3
 EXTRA_DIST += testdata/sql1.example.com.signed
 EXTRA_DIST += testdata/sql2.example.com.signed
 EXTRA_DIST += testdata/test-root.sqlite3
 EXTRA_DIST += testdata/test.sqlite3
 EXTRA_DIST += testdata/test.sqlite3.nodiffs
-EXTRA_DIST += testdata/rwtest.sqlite3
-EXTRA_DIST += testdata/diffs.sqlite3

+ 194 - 0
src/lib/datasrc/tests/rbnode_rrset_unittest.cc

@@ -0,0 +1,194 @@
+// Copyright (C) 2012  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 <stdexcept>
+
+#include <exceptions/exceptions.h>
+#include <dns/rdataclass.h>
+#include <datasrc/rbnode_rrset.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+
+using isc::UnitTestUtil;
+
+using namespace std;
+using namespace isc;
+using namespace isc::datasrc;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::util;
+
+// These tests are very similar to those for RRset - indeed, the files was
+// created from those tests.  However, the significant difference in behaviour
+// between RRset and RBNodeRRset - that the "set" methods in the latter mostly
+// result in exceptions being thrown - preclude use of full type
+// parameterisation of the tests.
+
+namespace {
+class RBNodeRRsetTest : public ::testing::Test {
+protected:
+    RBNodeRRsetTest() :
+        buffer(0), renderer(buffer),
+        test_name("test.example.com"),
+        test_domain("example.com"),
+        test_nsname("ns.example.com"),
+        rrset_a(ConstRRsetPtr(new RRset(
+                test_name, RRClass::IN(), RRType::A(), RRTTL(3600)))),
+        rrset_a_empty(ConstRRsetPtr(new RRset(
+                      test_name, RRClass::IN(), RRType::A(), RRTTL(3600)))),
+        rrset_ns(ConstRRsetPtr(new RRset(
+                 test_domain, RRClass::IN(), RRType::NS(), RRTTL(86400)))),
+        rrset_ch_txt(ConstRRsetPtr(new RRset(
+                     test_domain, RRClass::CH(), RRType::TXT(), RRTTL(0))))
+    {
+        // Add a couple of Rdata elements to an RRset.  The easiest way to
+        // do this is to override the "const" restrictions.  As this is a test,
+        // we don't feel too bad about doing so.
+        AbstractRRset* rrset =
+            const_cast<AbstractRRset*>(rrset_a.getUnderlyingRRset().get());
+        rrset->addRdata(in::A("192.0.2.1"));
+        rrset->addRdata(in::A("192.0.2.2"));
+    }
+
+    OutputBuffer buffer;
+    MessageRenderer renderer;
+    Name test_name;
+    Name test_domain;
+    Name test_nsname;
+    RBNodeRRset rrset_a;
+    RBNodeRRset rrset_a_empty;
+    RBNodeRRset rrset_ns;
+    RBNodeRRset rrset_ch_txt;
+    std::vector<unsigned char> wiredata;
+
+    // max number of Rdata objects added to a test RRset object.
+    // this is an arbitrary chosen limit, but should be sufficiently large
+    // in practice and reasonable even as an extreme test case.
+    static const int MAX_RDATA_COUNT = 100;
+};
+
+TEST_F(RBNodeRRsetTest, getRdataCount) {
+    EXPECT_EQ(0, rrset_a_empty.getRdataCount());
+    EXPECT_EQ(2, rrset_a.getRdataCount());
+}
+
+TEST_F(RBNodeRRsetTest, getName) {
+    EXPECT_EQ(test_name, rrset_a.getName());
+    EXPECT_EQ(test_domain, rrset_ns.getName());
+}
+
+TEST_F(RBNodeRRsetTest, getClass) {
+    EXPECT_EQ(RRClass("IN"), rrset_a.getClass());
+    EXPECT_EQ(RRClass("CH"), rrset_ch_txt.getClass());
+}
+
+TEST_F(RBNodeRRsetTest, getType) {
+    EXPECT_EQ(RRType("A"), rrset_a.getType());
+    EXPECT_EQ(RRType("NS"), rrset_ns.getType());
+    EXPECT_EQ(RRType("TXT"), rrset_ch_txt.getType());
+}
+
+TEST_F(RBNodeRRsetTest, getTTL) {
+    EXPECT_EQ(RRTTL(3600), rrset_a.getTTL());
+    EXPECT_EQ(RRTTL(86400), rrset_ns.getTTL());
+    EXPECT_EQ(RRTTL(0), rrset_ch_txt.getTTL());
+}
+
+TEST_F(RBNodeRRsetTest, setName) {
+    EXPECT_THROW(rrset_a.setName(test_nsname), NotImplemented);
+}
+
+TEST_F(RBNodeRRsetTest, setTTL) {
+    EXPECT_THROW(rrset_a.setTTL(RRTTL(86400)), NotImplemented);
+}
+
+TEST_F(RBNodeRRsetTest, toText) {
+    EXPECT_EQ("test.example.com. 3600 IN A 192.0.2.1\n"
+              "test.example.com. 3600 IN A 192.0.2.2\n",
+              rrset_a.toText());
+
+    // toText() cannot be performed for an empty RRset.
+    EXPECT_THROW(rrset_a_empty.toText(), EmptyRRset);
+}
+
+TEST_F(RBNodeRRsetTest, toWireRenderer) {
+    rrset_ns.addRdata(generic::NS(test_nsname));
+
+    rrset_a.toWire(renderer);
+    rrset_ns.toWire(renderer);
+
+    UnitTestUtil::readWireData("rrset_toWire2", wiredata);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
+                        buffer.getLength(), &wiredata[0], wiredata.size());
+
+    // toWire() cannot be performed for an empty RRset.
+    renderer.clear();
+    EXPECT_THROW(rrset_a_empty.toWire(renderer), EmptyRRset);
+}
+
+TEST_F(RBNodeRRsetTest, toWireBuffer) {
+    rrset_a.toWire(buffer);
+
+    UnitTestUtil::readWireData("rrset_toWire1", wiredata);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
+                        buffer.getLength(), &wiredata[0], wiredata.size());
+
+    // toWire() cannot be performed for an empty RRset.
+    buffer.clear();
+    EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset);
+}
+
+TEST_F(RBNodeRRsetTest, addRdata) {
+    EXPECT_THROW(rrset_a.addRdata(in::A("192.0.2.3")), NotImplemented);
+
+    // Check the same goes for tryin g to add the wrong type of data
+    EXPECT_THROW(rrset_a.addRdata(generic::NS(test_nsname)), NotImplemented);
+}
+
+TEST_F(RBNodeRRsetTest, addRdataPtr) {
+    EXPECT_THROW(rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(),
+                                                    rrset_a_empty.getClass(),
+                                                    "192.0.2.1")),
+                 NotImplemented);
+}
+
+TEST_F(RBNodeRRsetTest, getRDataIterator) {
+    RdataIteratorPtr it = rrset_a.getRdataIterator();
+    for (int i = 0; i < 2; ++i) {
+        ASSERT_FALSE(it->isLast());
+        ASSERT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1")));
+
+        it->next();
+        ASSERT_FALSE(it->isLast());
+        ASSERT_EQ(0, it->getCurrent().compare(in::A("192.0.2.2")));
+
+        it->next();
+        ASSERT_TRUE(it->isLast());
+
+        // Should be able repeat the iteration by calling first().
+        it->first();
+    }
+}
+
+// test operator<<.  We simply confirm it appends the result of toText().
+TEST_F(RBNodeRRsetTest, LeftShiftOperator) {
+    ostringstream oss;
+    oss << rrset_a;
+    EXPECT_EQ("test.example.com. 3600 IN A 192.0.2.1\n"
+              "test.example.com. 3600 IN A 192.0.2.2\n", oss.str());
+}
+
+}   // Anonymous namespace

+ 23 - 0
src/lib/datasrc/tests/testdata/rrset_toWire1

@@ -0,0 +1,23 @@
+#
+# Rendering an IN/A RRset containing 2 RRs:
+# test.example.com. 3600 IN A 192.0.2.1
+# test.example.com. 3600 IN A 192.0.2.2
+#
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# type/class: A = 1, IN = 1
+00 01 00 01
+# TTL: 3600
+00 00 0e 10
+#6  7
+# RDLENGTH: 4
+00 04
+# RDATA: 192.0.2.1
+c0 00 02 01
+#
+# 2nd RR: mostly the same except the RDATA
+04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+00 01 00 01
+00 00 0e 10
+00 04
+c0 00 02 02

+ 38 - 0
src/lib/datasrc/tests/testdata/rrset_toWire2

@@ -0,0 +1,38 @@
+#
+# Rendering an IN/A RRset and NS RRset as follows:
+# test.example.com. 3600 IN A 192.0.2.1
+# test.example.com. 3600 IN A 192.0.2.2
+# example.com. 1D IN NS ns.example.com.
+# Names will be compressed when possible.
+#
+# 0  1  2  3  4  5
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# type/class: A = 1, IN = 1
+00 01 00 01
+# TTL: 3600
+00 00 0e 10
+#6  7
+# RDLENGTH: 4
+00 04
+# RDATA: 192.0.2.1
+c0 00 02 01
+#
+# 2nd RR: the owner name is compresed
+c0 00
+00 01 00 01
+00 00 0e 10
+00 04
+c0 00 02 02
+# 3rd RR: the owner name and NS name are compressed
+# pointing to the 5th octet of the owner name of the 1st RR
+c0 05
+# type/class: NS = 2, IN = 1
+00 02 00 01
+# TTL: 1D = 86400sec = 0x15180
+00 01 51 80
+# RDLENGTH: 5 octets
+00 05
+# NSDNAME: "ns." + compression pointer
+#(2) n  s
+ 02 6e 73 c0 05