diff options
Diffstat (limited to 'src/lib/dns/tests/rrset_unittest.cc')
-rw-r--r-- | src/lib/dns/tests/rrset_unittest.cc | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc new file mode 100644 index 0000000..0425812 --- /dev/null +++ b/src/lib/dns/tests/rrset_unittest.cc @@ -0,0 +1,442 @@ +// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <util/buffer.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrclass.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rrset.h> + +#include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> + +#include <gtest/gtest.h> + +#include <stdexcept> +#include <sstream> + +using namespace std; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; + +namespace { +class RRsetTest : public ::testing::Test { +protected: + RRsetTest() : buffer(0), + test_name("test.example.com"), + test_domain("example.com"), + test_nsname("ns.example.com"), + rrset_a(test_name, RRClass::IN(), RRType::A(), RRTTL(3600)), + rrset_a_empty(test_name, RRClass::IN(), RRType::A(), + RRTTL(3600)), + rrset_any_a_empty(test_name, RRClass::ANY(), RRType::A(), + RRTTL(3600)), + rrset_none_a_empty(test_name, RRClass::NONE(), RRType::A(), + RRTTL(3600)), + rrset_ns(test_domain, RRClass::IN(), RRType::NS(), + RRTTL(86400)), + rrset_ch_txt(test_domain, RRClass::CH(), RRType::TXT(), + RRTTL(0)) + { + rrset_a.addRdata(in::A("192.0.2.1")); + rrset_a.addRdata(in::A("192.0.2.2")); + } + + OutputBuffer buffer; + MessageRenderer renderer; + Name test_name; + Name test_domain; + Name test_nsname; + RRset rrset_a; + RRset rrset_a_empty; + RRset rrset_any_a_empty; + RRset rrset_none_a_empty; + RRset rrset_ns; + RRset 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(RRsetTest, getRdataCount) { + for (int i = 0; i < MAX_RDATA_COUNT; ++i) { + EXPECT_EQ(i, rrset_a_empty.getRdataCount()); + rrset_a_empty.addRdata(in::A("192.0.2.1")); + } +} + +TEST_F(RRsetTest, getName) { + EXPECT_EQ(test_name, rrset_a.getName()); + EXPECT_EQ(test_domain, rrset_ns.getName()); +} + +TEST_F(RRsetTest, getClass) { + EXPECT_EQ(RRClass("IN"), rrset_a.getClass()); + EXPECT_EQ(RRClass("CH"), rrset_ch_txt.getClass()); +} + +TEST_F(RRsetTest, 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(RRsetTest, 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(RRsetTest, setTTL) { + rrset_a.setTTL(RRTTL(86400)); + EXPECT_EQ(RRTTL(86400), rrset_a.getTTL()); + rrset_a.setTTL(RRTTL(0)); + EXPECT_EQ(RRTTL(0), rrset_a.getTTL()); +} + +TEST_F(RRsetTest, isSameKind) { + RRset rrset_w(test_name, RRClass::IN(), RRType::A(), RRTTL(3600)); + RRset rrset_x(test_name, RRClass::IN(), RRType::A(), RRTTL(3600)); + RRset rrset_y(test_name, RRClass::IN(), RRType::NS(), RRTTL(3600)); + RRset rrset_z(test_name, RRClass::CH(), RRType::A(), RRTTL(3600)); + RRset rrset_p(test_nsname, RRClass::IN(), RRType::A(), RRTTL(3600)); + + EXPECT_TRUE(rrset_w.isSameKind(rrset_w)); + EXPECT_TRUE(rrset_w.isSameKind(rrset_x)); + EXPECT_FALSE(rrset_w.isSameKind(rrset_y)); + EXPECT_FALSE(rrset_w.isSameKind(rrset_z)); + EXPECT_FALSE(rrset_w.isSameKind(rrset_p)); +} + +void +addRdataTestCommon(const RRset& rrset) { + ASSERT_EQ(2, rrset.getRdataCount()); + + RdataIteratorPtr it = rrset.getRdataIterator(); // cursor is set to the 1st + EXPECT_FALSE(it->isLast()); + EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1"))); + it->next(); + EXPECT_FALSE(it->isLast()); + EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.2"))); + it->next(); + EXPECT_TRUE(it->isLast()); +} + +TEST_F(RRsetTest, addRdata) { + addRdataTestCommon(rrset_a); + + // Reference version of addRdata() doesn't allow to add a different + // type of Rdata. + EXPECT_THROW(rrset_a.addRdata(generic::NS(test_nsname)), std::bad_cast); +} + +TEST_F(RRsetTest, addRdataPtr) { + rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(), + rrset_a_empty.getClass(), + "192.0.2.1")); + rrset_a_empty.addRdata(createRdata(rrset_a_empty.getType(), + rrset_a_empty.getClass(), + "192.0.2.2")); + addRdataTestCommon(rrset_a_empty); +} + +TEST_F(RRsetTest, addRdataPtrMismatched) { + // Pointer version of addRdata() doesn't type check and does allow to + //add a different type of Rdata as a result. + + // Type mismatch + rrset_a_empty.addRdata(createRdata(RRType::NS(), RRClass::IN(), + "ns.example.com.")); + EXPECT_EQ(1, rrset_a_empty.getRdataCount()); + + // Class mismatch + rrset_ch_txt.addRdata(createRdata(RRType::TXT(), RRClass::IN(), + "Test String")); + EXPECT_EQ(1, rrset_ch_txt.getRdataCount()); +} + +TEST_F(RRsetTest, addRdataString) { + rrset_a_empty.addRdata("192.0.2.1"); + rrset_a_empty.addRdata("192.0.2.2"); + + addRdataTestCommon(rrset_a_empty); + + // String version of addRdata() will throw for bad RDATA for + // RRType::A(). + EXPECT_THROW(rrset_a_empty.addRdata("ns.example.com."), InvalidRdataText); + addRdataTestCommon(rrset_a_empty); +} + +TEST_F(RRsetTest, iterator) { + // Iterator for an empty RRset. + RdataIteratorPtr it = rrset_a_empty.getRdataIterator(); + EXPECT_TRUE(it->isLast()); + + // Normal case (already tested, but do it again just in case) + rrset_a_empty.addRdata(in::A("192.0.2.1")); + rrset_a_empty.addRdata(in::A("192.0.2.2")); + addRdataTestCommon(rrset_a_empty); + + // Rewind test: should be repeat the iteration by calling first(). + for (int i = 0; i < 2; ++i) { + it = rrset_a_empty.getRdataIterator(); + it->first(); + EXPECT_FALSE(it->isLast()); + it->next(); + EXPECT_FALSE(it->isLast()); + it->next(); + EXPECT_TRUE(it->isLast()); + } +} + +TEST_F(RRsetTest, 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); + + // Unless it is type ANY or NONE + EXPECT_EQ("test.example.com. 3600 ANY A\n", + rrset_any_a_empty.toText()); + EXPECT_EQ("test.example.com. 3600 NONE A\n", + rrset_none_a_empty.toText()); +} + +TEST_F(RRsetTest, getLength) { + // Empty RRset should throw + EXPECT_THROW(rrset_a_empty.getLength(), EmptyRRset); + + // Unless it is type ANY or NONE: + // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + // TYPE field = 2 octets + // CLASS field = 2 octets + // TTL field = 4 octets + // RDLENGTH field = 2 octets + // Total = 18 + 2 + 2 + 4 + 2 = 28 octets + EXPECT_EQ(28, rrset_any_a_empty.getLength()); + EXPECT_EQ(28, rrset_none_a_empty.getLength()); + + // RRset with single RDATA + // 28 (above) + 4 octets (A RDATA) = 32 octets + rrset_a_empty.addRdata(in::A("192.0.2.1")); + EXPECT_EQ(32, rrset_a_empty.getLength()); + + // 2 A RRs + rrset_a_empty.addRdata(in::A("192.0.2.2")); + EXPECT_EQ(32 + 32, rrset_a_empty.getLength()); +} + +TEST_F(RRsetTest, toWireBuffer) { + rrset_a.toWire(buffer); + + UnitTestUtil::readWireData("rrset_toWire1", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + buffer.getData(), buffer.getLength()); + + // toWire() cannot be performed for an empty RRset except when + // class=ANY or class=NONE. + buffer.clear(); + EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset); + + // When class=ANY or class=NONE, toWire() can also be performed for + // an empty RRset. + buffer.clear(); + rrset_any_a_empty.toWire(buffer); + wiredata.clear(); + UnitTestUtil::readWireData("rrset_toWire3", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + buffer.getData(), buffer.getLength()); + + buffer.clear(); + rrset_none_a_empty.toWire(buffer); + wiredata.clear(); + UnitTestUtil::readWireData("rrset_toWire4", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + buffer.getData(), buffer.getLength()); +} + +TEST_F(RRsetTest, toWireRenderer) { + rrset_ns.addRdata(generic::NS(test_nsname)); + + rrset_a.toWire(renderer); + rrset_ns.toWire(renderer); + + UnitTestUtil::readWireData("rrset_toWire2", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + // toWire() cannot be performed for an empty RRset except when + // class=ANY or class=NONE. + renderer.clear(); + EXPECT_THROW(rrset_a_empty.toWire(renderer), EmptyRRset); + + // When class=ANY or class=NONE, toWire() can also be performed for + // an empty RRset. + renderer.clear(); + rrset_any_a_empty.toWire(renderer); + wiredata.clear(); + UnitTestUtil::readWireData("rrset_toWire3", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + renderer.clear(); + rrset_none_a_empty.toWire(renderer); + wiredata.clear(); + UnitTestUtil::readWireData("rrset_toWire4", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); +} + +// test operator<<. We simply confirm it appends the result of toText(). +TEST_F(RRsetTest, LeftShiftOperator) { + ostringstream oss; + oss << rrset_a; + EXPECT_EQ(rrset_a.toText(), oss.str()); +} + +class RRsetRRSIGTest : public ::testing::Test { +protected: + RRsetRRSIGTest() : test_name("test.example.com") + { + rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(), + RRType::A(), RRTTL(3600))); + rrset_a->addRdata(in::A("192.0.2.1")); + rrset_a->addRdata(in::A("192.0.2.2")); + + rrset_aaaa = RRsetPtr(new RRset(test_name, RRClass::IN(), + RRType::AAAA(), RRTTL(3600))); + rrset_aaaa->addRdata(in::AAAA("2001:db8::1234")); + + rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(), + RRType::RRSIG(), RRTTL(3600))); + rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 " + "20100220084538 1 example.com. " + "FAKEFAKEFAKEFAKE")); + rrset_aaaa->addRRsig(rrset_rrsig); + } + + const Name test_name; + RRsetPtr rrset_a; // A RRset with two RDATAs + RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG + RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset +}; + +TEST_F(RRsetRRSIGTest, getRRsig) { + RRsetPtr sp = rrset_a->getRRsig(); + EXPECT_EQ(static_cast<void*>(NULL), sp.get()); + + sp = rrset_aaaa->getRRsig(); + EXPECT_NE(static_cast<void*>(NULL), sp.get()); +} + +TEST_F(RRsetRRSIGTest, addRRsig) { + RRsetPtr sp = rrset_a->getRRsig(); + EXPECT_EQ(static_cast<void*>(NULL), sp.get()); + + rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(), + RRType::RRSIG(), RRTTL(3600))); + // one signature algorithm (5 = RSA/SHA-1) + rrset_rrsig->addRdata(generic::RRSIG("A 5 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + // another signature algorithm (3 = DSA/SHA-1) + rrset_rrsig->addRdata(generic::RRSIG("A 3 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + rrset_a->addRRsig(rrset_rrsig); + + sp = rrset_a->getRRsig(); + EXPECT_NE(static_cast<void*>(NULL), sp.get()); + EXPECT_EQ(2, sp->getRdataCount()); + + // add to existing RRSIG + rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(), + RRType::RRSIG(), RRTTL(3600))); + // another signature algorithm (4 = ECC) + rrset_rrsig->addRdata(generic::RRSIG("A 4 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + rrset_a->addRRsig(rrset_rrsig); + EXPECT_EQ(3, sp->getRdataCount()); +} + +TEST_F(RRsetRRSIGTest, getRRsigDataCount) { + EXPECT_EQ(1, rrset_aaaa->getRRsigDataCount()); + EXPECT_EQ(0, rrset_a->getRRsigDataCount()); + + rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(), + RRType::RRSIG(), RRTTL(3600))); + // one signature algorithm (5 = RSA/SHA-1) + rrset_rrsig->addRdata(generic::RRSIG("A 5 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + // another signature algorithm (3 = DSA/SHA-1) + rrset_rrsig->addRdata(generic::RRSIG("A 3 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + rrset_a->addRRsig(rrset_rrsig); + EXPECT_EQ(2, rrset_a->getRRsigDataCount()); + + rrset_a->removeRRsig(); + EXPECT_EQ(0, rrset_a->getRRsigDataCount()); +} + +TEST_F(RRsetRRSIGTest, toText) { + // toText() should also return the associated RRSIG. + EXPECT_EQ("test.example.com. 3600 IN AAAA 2001:db8::1234\n" + "test.example.com. 3600 IN RRSIG AAAA 5 3 7200 " + "20100322084538 20100220084538 1 example.com. FAKEFAKEFAKEFAKE\n", + rrset_aaaa->toText()); +} + +TEST_F(RRsetRRSIGTest, getLength) { + // A RR + // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + // TYPE field = 2 octets + // CLASS field = 2 octets + // TTL field = 4 octets + // RDLENGTH field = 2 octets + // A RDATA = 4 octets + // Total = 18 + 2 + 2 + 4 + 2 + 4 = 32 octets + + // 2 A RRs + EXPECT_EQ(32 + 32, rrset_a->getLength()); + + // RRSIG + // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets + // TYPE field = 2 octets + // CLASS field = 2 octets + // TTL field = 4 octets + // RDLENGTH field = 2 octets + // RRSIG RDATA = 40 octets + // Total = 18 + 2 + 2 + 4 + 2 + 40 = 68 octets + RRsetPtr my_rrsig(new RRset(test_name, RRClass::IN(), + RRType::RRSIG(), RRTTL(3600))); + my_rrsig->addRdata(generic::RRSIG("A 4 3 3600 " + "20000101000000 20000201000000 " + "12345 example.com. FAKEFAKEFAKE")); + EXPECT_EQ(68, my_rrsig->getLength()); + + // RRset with attached RRSIG + rrset_a->addRRsig(my_rrsig); + + EXPECT_EQ(32 + 32 + 68, rrset_a->getLength()); +} +} |