diff options
Diffstat (limited to 'src/lib/dns/tests/rrparamregistry_unittest.cc')
-rw-r--r-- | src/lib/dns/tests/rrparamregistry_unittest.cc | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/src/lib/dns/tests/rrparamregistry_unittest.cc b/src/lib/dns/tests/rrparamregistry_unittest.cc new file mode 100644 index 0000000..90574d0 --- /dev/null +++ b/src/lib/dns/tests/rrparamregistry_unittest.cc @@ -0,0 +1,185 @@ +// Copyright (C) 2010-2020 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 <string> +#include <sstream> + +#include <stdint.h> + +#include <gtest/gtest.h> + +#include <dns/rrclass.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrparamregistry.h> +#include <dns/rrtype.h> +#include <dns/master_loader.h> + +#include <boost/scoped_ptr.hpp> + +using namespace std; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::dns::rdata; + +namespace { +class RRParamRegistryTest : public ::testing::Test { +protected: + RRParamRegistryTest() + { + ostringstream oss1; + oss1 << test_class_code; + // cppcheck-suppress useInitializationList + test_class_unknown_str = "CLASS" + oss1.str(); + + ostringstream oss2; + oss2 << test_type_code; + test_type_unknown_str = "TYPE" + oss2.str(); + } + ~RRParamRegistryTest() + { + // cleanup any non well-known parameters that possibly remain + // as a side effect. + RRParamRegistry::getRegistry().removeType(test_type_code); + RRParamRegistry::getRegistry().removeClass(test_class_code); + RRParamRegistry::getRegistry().removeRdataFactory( + RRType(test_type_code), RRClass(test_class_code)); + RRParamRegistry::getRegistry().removeRdataFactory( + RRType(test_type_code)); + } + + string test_class_unknown_str; + string test_type_unknown_str; + + // we assume class/type numbers are officially unassigned. If not we'll + // need to update the test cases. + static const uint16_t test_class_code = 65533; + static const uint16_t test_type_code = 65534; + static const string test_class_str; + static const string test_type_str; +}; + +const string RRParamRegistryTest::test_class_str("TESTCLASS"); +const string RRParamRegistryTest::test_type_str("TESTTYPE"); + +TEST_F(RRParamRegistryTest, addRemove) { + RRParamRegistry::getRegistry().addType(test_type_str, test_type_code); + RRParamRegistry::getRegistry().addClass(test_class_str, test_class_code); + EXPECT_EQ(65533, RRClass("TESTCLASS").getCode()); + EXPECT_EQ(65534, RRType("TESTTYPE").getCode()); + + // the first removal attempt should succeed + EXPECT_TRUE(RRParamRegistry::getRegistry().removeType(test_type_code)); + // then toText() should treat it as an "unknown" + EXPECT_EQ(test_type_unknown_str, RRType(test_type_code).toText()); + // attempt of removing non-existent mapping should result in 'false' + EXPECT_FALSE(RRParamRegistry::getRegistry().removeType(test_type_code)); + + // same set of tests for RR class. + EXPECT_TRUE(RRParamRegistry::getRegistry().removeClass(test_class_code)); + EXPECT_EQ(test_class_unknown_str, RRClass(test_class_code).toText()); + EXPECT_FALSE(RRParamRegistry::getRegistry().removeClass(test_class_code)); +} + +TEST_F(RRParamRegistryTest, addError) { + // An attempt to override a pre-registered class should fail with an + // exception, and the pre-registered one should remain in the registry. + EXPECT_THROW(RRParamRegistry::getRegistry().addClass(test_class_str, 1), + RRClassExists); + EXPECT_EQ("IN", RRClass(1).toText()); + + // Same for RRType + EXPECT_THROW(RRParamRegistry::getRegistry().addType(test_type_str, 1), + RRTypeExists); + EXPECT_EQ("A", RRType(1).toText()); +} + +class TestRdataFactory : public AbstractRdataFactory { +public: + virtual RdataPtr create(const string& rdata_str) const + { return (RdataPtr(new in::A(rdata_str))); } + virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const + { return (RdataPtr(new in::A(buffer, rdata_len))); } + virtual RdataPtr create(const Rdata& source) const + { return (RdataPtr(new in::A(dynamic_cast<const in::A&>(source)))); } + virtual RdataPtr create(MasterLexer& lexer, const Name* origin, + MasterLoader::Options options, + MasterLoaderCallbacks& callbacks) const + { return (RdataPtr(new in::A(lexer, origin, options, callbacks))); } +}; + +TEST_F(RRParamRegistryTest, addRemoveFactory) { + // By default, the test type/code pair should be considered "unknown", + // so the following should trigger an exception. + EXPECT_THROW(createRdata(RRType(test_type_code), RRClass(test_class_code), + "192.0.2.1"), + InvalidRdataText); + // Add factories so that we can treat this pair just like in::A. + RRParamRegistry::getRegistry().add(test_type_str, test_type_code, + test_class_str, test_class_code, + RdataFactoryPtr(new TestRdataFactory)); + // Now it should be accepted, and should be identical to the same data of + // in::A. + EXPECT_EQ(0, in::A("192.0.2.1").compare( + *createRdata(RRType(test_type_code), RRClass(test_class_code), + "192.0.2.1"))); + // It should still fail with other classes as we specified the factories + // as class-specific. + EXPECT_THROW(createRdata(RRType(test_type_code), RRClass("IN"), + "192.0.2.1"), + InvalidRdataText); + // Add the factories also as a class independent RRtype + RRParamRegistry::getRegistry().add(test_type_str, test_type_code, + RdataFactoryPtr(new TestRdataFactory)); + // Now it should be okay for other classes than the test class. + EXPECT_EQ(0, in::A("192.0.2.1").compare( + *createRdata(RRType(test_type_code), RRClass("IN"), + "192.0.2.1"))); + + // Remove the added factories: first attempt should succeed; the second + // should return false as there's no match + EXPECT_TRUE(RRParamRegistry::getRegistry().removeRdataFactory( + RRType(test_type_code), RRClass(test_class_code))); + EXPECT_FALSE(RRParamRegistry::getRegistry().removeRdataFactory( + RRType(test_type_code), RRClass(test_class_code))); + EXPECT_TRUE(RRParamRegistry::getRegistry().removeRdataFactory( + RRType(test_type_code))); + EXPECT_FALSE(RRParamRegistry::getRegistry().removeRdataFactory( + RRType(test_type_code))); +} + +RdataPtr +createRdataHelper(const std::string& str) { + boost::scoped_ptr<AbstractRdataFactory> rdf(new TestRdataFactory); + + std::stringstream ss(str); + MasterLexer lexer; + lexer.pushSource(ss); + + MasterLoaderCallbacks callbacks(MasterLoaderCallbacks::getNullCallbacks()); + const Name origin("example.org."); + + return (rdf->create(lexer, &origin, + MasterLoader::MANY_ERRORS, + callbacks)); +} + +TEST_F(RRParamRegistryTest, createFromLexer) { + // This test basically checks that the string version of + // AbstractRdataFactory::create() is called by the MasterLexer + // variant of create(). + EXPECT_EQ(0, in::A("192.168.0.1").compare( + *createRdataHelper("192.168.0.1"))); + + // This should parse only up to the end of line. Everything that + // comes afterwards is not parsed. + EXPECT_EQ(0, in::A("192.168.0.42").compare( + *createRdataHelper("192.168.0.42\na b c d e f"))); +} + +} |