1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171 |
- // Copyright (C) 2017 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.com/MPL/2.0/.
- #include <config.h>
- #include <gtest/gtest.h>
- #include <d2/d2_simple_parser.h>
- #include <d2/tests/parser_unittest.h>
- #include <cc/data.h>
- #include <testutils/test_to_element.h>
- #include <boost/lexical_cast.hpp>
- using namespace isc;
- using namespace isc::data;
- using namespace isc::d2;
- using namespace isc::test;
- namespace {
- /// @brief Checks if specified element matches the given integer default
- ///
- /// @param element defaulted element to check
- /// @param deflt SimpleDefault which supplied the default value
- void checkIntegerValue(const ConstElementPtr& element,
- const SimpleDefault& deflt) {
- ASSERT_TRUE(element);
- // Verify it is an integer.
- ASSERT_EQ(Element::integer, element->getType());
- // Turn default value string into an int.
- int64_t default_value = 0;
- ASSERT_NO_THROW(default_value = boost::lexical_cast<int64_t>(deflt.value_));
- // Verify it has the expected value.
- EXPECT_EQ(default_value, element->intValue());
- }
- /// @brief Checks if specified element matches the given boolean default
- ///
- /// @param element defaulted element to check
- /// @param deflt SimpleDefault which supplied the default valaue
- void checkBooleanValue(const ConstElementPtr& element,
- const SimpleDefault& deflt) {
- ASSERT_TRUE(element);
- // Verify it is a bool.
- ASSERT_EQ(Element::boolean, element->getType());
- // Turn default value string into a bool.
- bool default_value = false;
- ASSERT_NO_THROW(boost::lexical_cast<bool>(deflt.value_));
- // Verify it has the expected value.
- EXPECT_EQ(default_value, element->boolValue());
- }
- /// @brief Checks if specified element matches the given string default
- ///
- /// @param element defaulted element to check
- /// @param deflt SimpleDefault which supplied the default valaue
- void checkStringValue(const ConstElementPtr& element,
- const SimpleDefault& deflt) {
- ASSERT_TRUE(element);
- // Verify it's a string
- ASSERT_EQ(Element::string, element->getType());
- // Verify it has the expected value
- EXPECT_EQ(deflt.value_, element->stringValue());
- }
- /// TSIGKeyInfo against the given set of values, and that the TSIGKey
- /// member points to a key.
- ///
- /// @param key is a pointer to the TSIGKeyInfo instance to verify
- /// @param name is the value to compare against key's name_.
- /// @param algorithm is the string value to compare against key's algorithm.
- /// @param secret is the value to compare against key's secret.
- ///
- /// @return returns true if there is a match across the board, otherwise it
- /// returns false.
- bool checkKey(TSIGKeyInfoPtr key, const std::string& name,
- const std::string& algorithm, const std::string& secret,
- uint32_t digestbits = 0) {
- // Return value, assume its a match.
- return (((key) &&
- (key->getName() == name) &&
- (key->getAlgorithm() == algorithm) &&
- (key->getDigestbits() == digestbits) &&
- (key->getSecret() == secret) &&
- (key->getTSIGKey())));
- }
- /// @brief Convenience function which compares the contents of the given
- /// DnsServerInfo against the given set of values.
- ///
- /// It is structured in such a way that each value is checked, and output
- /// is generated for all that do not match.
- ///
- /// @param server is a pointer to the server to check against.
- /// @param hostname is the value to compare against server's hostname_.
- /// @param ip_address is the string value to compare against server's
- /// ip_address_.
- /// @param port is the value to compare against server's port.
- ///
- /// @return returns true if there is a match across the board, otherwise it
- /// returns false.
- bool checkServer(DnsServerInfoPtr server, const char* hostname,
- const char *ip_address, uint32_t port)
- {
- // Return value, assume its a match.
- bool result = true;
- if (!server) {
- EXPECT_TRUE(server);
- return false;
- }
- // Check hostname.
- if (server->getHostname() != hostname) {
- EXPECT_EQ(hostname, server->getHostname());
- result = false;
- }
- // Check IP address.
- if (server->getIpAddress().toText() != ip_address) {
- EXPECT_EQ(ip_address, server->getIpAddress().toText());
- result = false;
- }
- // Check port.
- if (server->getPort() != port) {
- EXPECT_EQ (port, server->getPort());
- result = false;
- }
- return (result);
- }
- /// @brief Base class test fixture for testing JSON and element parsing
- /// for D2 configuration elements. It combines the three phases of
- /// configuration parsing normally orchestrated by D2CfgMgr:
- /// 1. Submit the JSON text to the JSON parser
- /// 2. Add defaults to the element tree produced by the JSON parser
- /// 3. Pass the element tree into the appropriate SimpleParser derivation
- /// to parse the element tree into D2 objects.
- class D2SimpleParserTest : public ::testing::Test {
- public:
- /// @brief Constructor
- ///
- /// @param parser_type specifies the parsing starting point at which
- /// the JSON parser should begin. It defaults to PARSER_JSON. See @c
- /// D2ParserContext::ParserType for all possible values.
- D2SimpleParserTest(const D2ParserContext::ParserType&
- parser_type = D2ParserContext::PARSER_JSON)
- : parser_type_(parser_type) {
- reset();
- }
- /// @brief Destructor
- virtual ~D2SimpleParserTest() {
- reset();
- }
- /// @brief Parses JSON text and compares the results against an expected
- /// outcome.
- ///
- /// The JSON text is submitted to the D2ParserContext for parsing. Any
- /// errors emitted here are caught and compared against the expected
- /// error or flagged as unexpected.
- /// Next, the virtual method, setDefaults()is invoked. his method should
- /// be used by derivations to add default values to the element tree
- /// produced by the JSON parser.
- /// Lastly, it passes the element tree into the virtual method,
- /// parseElement(). This method should be used by derivations to create
- /// the appropriate element parser to parse the element tree into the
- /// appropriate D2 object(s).
- ///
- /// @param json JSON text to parse
- /// @param exp_error exact text of the error message expected or ""
- /// if parsing should succeed.
- ::testing::AssertionResult parseOrFail(const std::string& json,
- const std::string& exp_error) {
- try {
- // Free up objects created by previous invocation
- reset();
- // Submit JSON text to JSON parser. We convert the result to
- // a mutable element tree to allow defaults to be added.
- D2ParserContext context;
- data::ElementPtr elem = boost::const_pointer_cast<Element>
- (context.parseString(json, parser_type_));
- // Add any defaults
- setDefaults(elem);
- // Now pares the element tree into object(s).
- parseElement(elem);
- } catch (const std::exception& ex) {
- std::string caught_error = ex.what();
- if (exp_error.empty()) {
- return ::testing::AssertionFailure()
- << "Unexpected error: " << caught_error
- << "\n json: [" << json << "]";
- }
- if (exp_error != caught_error) {
- return ::testing::AssertionFailure()
- << "Wrong error detected, expected: "
- << exp_error << ", got: " << caught_error
- << "\n json: [" << json << "]";
- }
- return ::testing::AssertionSuccess();
- }
- if (!exp_error.empty()) {
- return ::testing::AssertionFailure()
- << "Unexpected parsing success "
- << exp_error << "\n json: [" << json << "]";
- }
- return ::testing::AssertionSuccess();
- }
- protected:
- /// @brief Free up objects created by element parsing
- /// This method is invoked at the beginning of @c parseOrFail() to
- /// ensure any D2 object(s) that were created by a prior invocation are
- /// destroyed. This permits parsing to be conducted more than once
- /// in the same test.
- virtual void reset(){};
- /// @brief Adds default values to the given element tree
- ///
- /// Derivations are expected to use the appropriate methods in
- /// D2SimpleParser to add defaults values.
- ///
- /// @param config element tree in which defaults should be added
- /// @return the number of default items added to the tree
- virtual size_t setDefaults(data::ElementPtr config) {
- static_cast<void>(config);
- return (0);
- }
- /// @brief Parses a given element tree into D2 object(s)
- ///
- /// Derivations are expected to create the appropriate element
- /// parser and pass it the element tree for parsing. Any object(s)
- /// created should likely be saved for content verification
- /// outside of this method.
- ///
- /// @param config element tree to parse
- virtual void parseElement(data::ConstElementPtr config) {
- static_cast<void>(config);
- }
- D2ParserContext::ParserType parser_type_;
- };
- /// @brief Convenience macros for calling parseOrFail
- #define PARSE_OK(a) EXPECT_TRUE((parseOrFail(a, "")))
- #define PARSE_FAIL(a,b) EXPECT_TRUE((parseOrFail(a, b)))
- // This test checks if global defaults are properly set for D2.
- TEST_F(D2SimpleParserTest, globalD2Defaults) {
- ElementPtr empty = isc::d2::test::parseJSON("{ }");
- size_t num = 0;
- EXPECT_NO_THROW(num = D2SimpleParser::setAllDefaults(empty));
- // We expect 5 parameters to be inserted.
- EXPECT_EQ(num, 8);
- // Let's go over all parameters we have defaults for.
- BOOST_FOREACH(SimpleDefault deflt, D2SimpleParser::D2_GLOBAL_DEFAULTS) {
- ConstElementPtr x;
- ASSERT_NO_THROW(x = empty->get(deflt.name_));
- EXPECT_TRUE(x);
- if (x) {
- if (deflt.type_ == Element::integer) {
- checkIntegerValue(x, deflt);
- } else if (deflt.type_ == Element::boolean) {
- checkBooleanValue(x, deflt);
- } else if (deflt.type_ == Element::string) {
- checkStringValue(x, deflt);
- } else {
- // add them if we need to. Like what do you if it's a map?
- ADD_FAILURE() << "default type not supported:" << deflt.name_
- << " ,type: " << deflt.type_;
- }
- }
- }
- }
- /// @brief Test fixture class for testing TSIGKeyInfo parsing.
- class TSIGKeyInfoParserTest : public D2SimpleParserTest {
- public:
- /// @brief Constructor
- TSIGKeyInfoParserTest()
- : D2SimpleParserTest(D2ParserContext::PARSER_TSIG_KEY) {
- }
- /// @brief Free up the keys created by parsing
- virtual void reset() {
- key_.reset();
- };
- /// @brief Destructor
- virtual ~TSIGKeyInfoParserTest() {
- reset();
- };
- /// @brief Adds TSIG Key default values to the given TSIG Key element
- ///
- /// @param config TSIG Key element to which defaults should be added
- ///
- /// @return the number of default items added to the tree
- size_t setDefaults(data::ElementPtr config) {
- return (SimpleParser::setDefaults(config, D2SimpleParser::
- TSIG_KEY_DEFAULTS));
- }
- /// @brief Attempts to parse the given element into a TSIGKeyInfo
- ///
- /// Assumes the given element is a Map containing the attributes for
- /// a TSIG Key. If parsing is successful the new TSIGKeyInfo instance
- /// is retained in the member, key_;
- ///
- /// @param config element to parse
- void parseElement(data::ConstElementPtr config) {
- TSIGKeyInfoParser parser;
- key_ = parser.parse(config);
- }
- /// @brief Retains the TSIGKeyInfo created by a successful parsing
- TSIGKeyInfoPtr key_;
- };
- /// @brief Test fixture class for testing TSIGKeyInfo list parsing.
- class TSIGKeyInfoListParserTest : public D2SimpleParserTest {
- public:
- /// @brief Constructor
- TSIGKeyInfoListParserTest()
- : D2SimpleParserTest(D2ParserContext::PARSER_TSIG_KEYS) {
- }
- /// @brief Destructor
- virtual ~TSIGKeyInfoListParserTest() {
- reset();
- }
- /// @brief Free up the keys created by parsing
- virtual void reset() {
- keys_.reset();
- };
- /// @brief Adds TSIG Key default values to a list of TSIG Key elements
- ///
- /// @param config list of TSIG Key elements to which defaults should be
- /// added
- ///
- /// @return the number of default items added to the tree
- size_t setDefaults(data::ElementPtr config) {
- return (SimpleParser::setListDefaults(config, D2SimpleParser::
- TSIG_KEY_DEFAULTS));
- }
- /// @brief Attempts to parse the given element into a list of TSIGKeyInfos
- ///
- /// Assumes the given element is a list containing one or more TSIG Keys
- /// elements. If parsing is successful the list of TSIGKeyInfo instances
- /// is retained in the member, keys_;
- ///
- /// @param config element to parse
- void parseElement(data::ConstElementPtr config) {
- TSIGKeyInfoListParser parser;
- keys_ = parser.parse(config);
- }
- /// @brief Retains the TSIGKeyInfos created by a successful parsing
- TSIGKeyInfoMapPtr keys_;
- };
- /// @brief Test fixture class for testing DnsServerInfo parsing.
- class DnsServerInfoParserTest : public D2SimpleParserTest {
- public:
- /// @brief Constructor
- DnsServerInfoParserTest()
- : D2SimpleParserTest(D2ParserContext::PARSER_DNS_SERVER) {
- }
- /// @brief Destructor
- virtual ~DnsServerInfoParserTest() {
- reset();
- }
- /// @brief Free up the server created by parsing
- virtual void reset() {
- server_.reset();
- }
- /// @brief Adds DNS Server default values to the given DNS Server element
- ///
- /// @param config DNS Server element to which defaults should be added
- ///
- /// @return the number of default items added to the tree
- virtual size_t setDefaults(data::ElementPtr config) {
- return (SimpleParser::setDefaults(config, D2SimpleParser::
- DNS_SERVER_DEFAULTS));
- }
- /// @brief Attempts to parse the given element into a DnsServerInfo
- ///
- /// Assumes the given element is a map containing the attributes for
- /// a DNS Server. If parsing is successful the new DnsServerInfo instance
- /// is retained in the member, server_;
- ///
- /// @param config element to parse
- virtual void parseElement(data::ConstElementPtr config) {
- DnsServerInfoParser parser;
- server_ = parser.parse(config);
- }
- /// @brief Retains the DnsServerInfo created by a successful parsing
- DnsServerInfoPtr server_;
- };
- /// @brief Test fixture class for testing DnsServerInfoList parsing.
- class DnsServerInfoListParserTest : public D2SimpleParserTest {
- public:
- /// @brief Constructor
- DnsServerInfoListParserTest()
- : D2SimpleParserTest(D2ParserContext::PARSER_DNS_SERVERS) {
- }
- /// @brief Destructor
- virtual ~DnsServerInfoListParserTest() {
- reset();
- }
- /// @brief Free up the servers created by parsing
- virtual void reset() {
- servers_.reset();
- }
- /// @brief Adds DNS Server default values to a list of DNS Server elements
- ///
- /// @param config list of DNS Server elements to which defaults should be
- /// added
- ///
- /// @return the number of default items added to the tree
- virtual size_t setDefaults(data::ElementPtr config) {
- return (SimpleParser::setListDefaults(config, D2SimpleParser::
- DNS_SERVER_DEFAULTS));
- }
- /// @brief Attempts to parse the given element into a list of DnsServerInfos
- ///
- /// Assumes the given element is a list containing one or more DNS Servers
- /// elements. If parsing is successful the list of DnsServerInfo instances
- /// is retained in the member, keys_;
- ///
- /// @param config element to parse
- virtual void parseElement(data::ConstElementPtr config) {
- DnsServerInfoListParser parser;
- servers_ = parser.parse(config);
- }
- /// @brief Retains the DnsServerInfos created by a successful parsing
- DnsServerInfoStoragePtr servers_;
- };
- /// @brief Test fixture class for testing DDnsDomain parsing.
- class DdnsDomainParserTest : public D2SimpleParserTest {
- public:
- /// @brief Constructor
- DdnsDomainParserTest(const D2ParserContext::ParserType& parser_type
- = D2ParserContext::PARSER_DDNS_DOMAIN)
- : D2SimpleParserTest(parser_type), keys_(new TSIGKeyInfoMap()) {
- }
- /// @brief Destructor
- virtual ~DdnsDomainParserTest() {
- reset();
- }
- /// @brief Free up the domain created by parsing
- virtual void reset() {
- domain_.reset();
- }
- /// @brief Add TSIGKeyInfos to the key map
- ///
- /// @param name the name of the key
- /// @param algorithm the algorithm of the key
- /// @param secret the secret value of the key
- void addKey(const std::string& name, const std::string& algorithm,
- const std::string& secret) {
- TSIGKeyInfoPtr key_info(new TSIGKeyInfo(name, algorithm, secret));
- (*keys_)[name]=key_info;
- }
- /// @brief Adds DDNS Domain values to the given DDNS Domain element
- ///
- /// @param config DDNS Domain element to which defaults should be added
- ///
- /// @return the number of default items added to the tree
- virtual size_t setDefaults(data::ElementPtr config) {
- return (D2SimpleParser::setDdnsDomainDefaults(config, D2SimpleParser::
- DDNS_DOMAIN_DEFAULTS));
- }
- /// @brief Attempts to parse the given element into a DdnsDomain
- ///
- /// Assumes the given element is a map containing the attributes for
- /// a DDNS Domain. If parsing is successful the new DdnsDomain instance
- /// is retained in the member, server_;
- ///
- /// @param config element to parse
- virtual void parseElement(data::ConstElementPtr config) {
- DdnsDomainParser parser;
- domain_ = parser.parse(config, keys_);
- }
- /// @brief Retains the DdnsDomain created by a successful parsing
- DdnsDomainPtr domain_;
- /// @brief Storage for TSIGKeys, used by DdnsDomainParser to validate
- /// domain keys
- TSIGKeyInfoMapPtr keys_;
- };
- class DdnsDomainListParserTest : public DdnsDomainParserTest {
- public:
- /// @brief Constructor
- DdnsDomainListParserTest()
- // We need the list context type to parse lists correctly
- : DdnsDomainParserTest(D2ParserContext::PARSER_DDNS_DOMAINS) {
- }
- /// @brief Destructor
- virtual ~DdnsDomainListParserTest() {
- reset();
- }
- /// @brief Free up domains created by parsing
- virtual void reset() {
- domains_.reset();
- }
- /// @brief Adds DDNS Domain default values to a list of DDNS Domain elements
- ///
- /// @param config list of DDNS Domain elements to which defaults should be
- /// added
- ///
- /// @return the number of default items added to the tree
- virtual size_t setDefaults(data::ElementPtr config) {
- size_t cnt = 0;
- // We don't use SimpleParser::setListDefaults() as this does
- // not handle sub-lists or sub-maps
- BOOST_FOREACH(ElementPtr domain, config->listValue()) {
- cnt += D2SimpleParser::
- setDdnsDomainDefaults(domain, D2SimpleParser::
- DDNS_DOMAIN_DEFAULTS);
- }
- return (cnt);
- }
- /// @brief Attempts to parse the given element into a list of DdnsDomains
- ///
- /// Assumes the given element is a list containing one or more DDNS Domains
- /// elements. If parsing is successful the list of DdnsDomain instances
- /// is retained in the member, keys_;
- ///
- /// @param config element to parse
- virtual void parseElement(data::ConstElementPtr config) {
- DdnsDomainListParser parser;
- domains_ = parser.parse(config, keys_);
- }
- /// @brief Retains the DdnsDomains created by a successful parsing
- DdnsDomainMapPtr domains_;
- };
- /// @brief Tests the enforcement of data validation when parsing TSIGKeyInfos.
- /// It verifies that:
- /// 1. Name cannot be blank.
- /// 2. Algorithm cannot be blank.
- /// 3. Secret cannot be blank.
- TEST_F(TSIGKeyInfoParserTest, invalidEntry) {
- // Name cannot be blank.
- std::string config = "{"
- " \"name\": \"\" , "
- " \"algorithm\": \"HMAC-MD5\" , "
- " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
- "}";
- PARSE_FAIL(config, "<string>:1.9: TSIG key name cannot be blank");
- // Algorithm cannot be be blank.
- config = "{"
- " \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"\" , "
- " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
- "}";
- PARSE_FAIL(config, "<string>:1.38: TSIG key algorithm cannot be blank");
- // Algorithm must be a valid algorithm
- config = "{"
- " \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"bogus\" , "
- " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
- "}";
- PARSE_FAIL(config, "tsig-key : Unknown TSIG Key algorithm:"
- " bogus (<string>:1:40)");
- // Secret cannot be blank
- config = "{"
- " \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"HMAC-MD5\" , "
- " \"secret\": \"\" "
- "}";
- PARSE_FAIL(config, "<string>:1.62: TSIG key secret cannot be blank");
- // Secret must be valid for algorithm
- config = "{"
- " \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"HMAC-MD5\" , "
- " \"digest-bits\": 120 , "
- " \"secret\": \"bogus\" "
- "}";
- PARSE_FAIL(config, "Cannot make TSIGKey: Incomplete input for base64:"
- " bogus (<string>:1:1)");
- }
- /// @brief Verifies that TSIGKeyInfo parsing creates a proper TSIGKeyInfo
- /// when given a valid combination of entries.
- TEST_F(TSIGKeyInfoParserTest, validEntry) {
- // Valid entries for TSIG key, all items are required.
- std::string config = "{"
- " \"name\": \"d2_key_one\" , "
- " \"algorithm\": \"HMAC-MD5\" , "
- " \"digest-bits\": 120 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- "}";
- // Verify that it parses.
- PARSE_OK(config);
- ASSERT_TRUE(key_);
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key_, "d2_key_one", "HMAC-MD5",
- "dGhpcyBrZXkgd2lsbCBtYXRjaA==", 120));
- // Verify unparsing.
- runToElementTest<TSIGKeyInfo>(config, *key_);
- }
- /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
- /// entries is detected.
- TEST_F(TSIGKeyInfoListParserTest, invalidTSIGKeyList) {
- // Construct a list of keys with an invalid key entry.
- std::string config = "["
- " { \"name\": \"key1\" , "
- " \"algorithm\": \"HMAC-MD5\" ,"
- " \"digest-bits\": 120 , "
- " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
- " },"
- // this entry has an invalid algorithm
- " { \"name\": \"key2\" , "
- " \"algorithm\": \"\" ,"
- " \"digest-bits\": 120 , "
- " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
- " },"
- " { \"name\": \"key3\" , "
- " \"algorithm\": \"HMAC-MD5\" ,"
- " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
- " }"
- " ]";
- PARSE_FAIL(config, "<string>:1.151: TSIG key algorithm cannot be blank");
- }
- /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
- /// entries is detected.
- TEST_F(TSIGKeyInfoListParserTest, duplicateTSIGKey) {
- // Construct a list of keys with an invalid key entry.
- std::string config = "["
- " { \"name\": \"key1\" , "
- " \"algorithm\": \"HMAC-MD5\" ,"
- " \"digest-bits\": 120 , "
- " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
- " },"
- " { \"name\": \"key2\" , "
- " \"algorithm\": \"HMAC-MD5\" ,"
- " \"digest-bits\": 120 , "
- " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
- " },"
- " { \"name\": \"key1\" , "
- " \"algorithm\": \"HMAC-MD5\" ,"
- " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
- " }"
- " ]";
- PARSE_FAIL(config,
- "Duplicate TSIG key name specified : key1 (<string>:1:239)");
- }
- /// @brief Verifies a valid list of TSIG Keys parses correctly.
- /// Also verifies that all of the supported algorithm names work.
- TEST_F(TSIGKeyInfoListParserTest, validTSIGKeyList) {
- // Construct a valid list of keys.
- std::string config = "["
- " { \"name\": \"key1\" , "
- " \"algorithm\": \"HMAC-MD5\" ,"
- " \"digest-bits\": 80 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- " },"
- " { \"name\": \"key2\" , "
- " \"algorithm\": \"HMAC-SHA1\" ,"
- " \"digest-bits\": 80 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- " },"
- " { \"name\": \"key3\" , "
- " \"algorithm\": \"HMAC-SHA256\" ,"
- " \"digest-bits\": 128 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- " },"
- " { \"name\": \"key4\" , "
- " \"algorithm\": \"HMAC-SHA224\" ,"
- " \"digest-bits\": 112 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- " },"
- " { \"name\": \"key5\" , "
- " \"algorithm\": \"HMAC-SHA384\" ,"
- " \"digest-bits\": 192 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- " },"
- " { \"name\": \"key6\" , "
- " \"algorithm\": \"HMAC-SHA512\" ,"
- " \"digest-bits\": 256 , "
- " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
- " }"
- " ]";
- PARSE_OK(config);
- ASSERT_TRUE(keys_);
- std::string ref_secret = "dGhpcyBrZXkgd2lsbCBtYXRjaA==";
- // Verify the correct number of keys are present
- int count = keys_->size();
- ASSERT_EQ(6, count);
- // Find the 1st key and retrieve it.
- TSIGKeyInfoMap::iterator gotit = keys_->find("key1");
- ASSERT_TRUE(gotit != keys_->end());
- TSIGKeyInfoPtr& key = gotit->second;
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key1", TSIGKeyInfo::HMAC_MD5_STR,
- ref_secret, 80));
- // Find the 2nd key and retrieve it.
- gotit = keys_->find("key2");
- ASSERT_TRUE(gotit != keys_->end());
- key = gotit->second;
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key2", TSIGKeyInfo::HMAC_SHA1_STR,
- ref_secret, 80));
- // Find the 3rd key and retrieve it.
- gotit = keys_->find("key3");
- ASSERT_TRUE(gotit != keys_->end());
- key = gotit->second;
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key3", TSIGKeyInfo::HMAC_SHA256_STR,
- ref_secret, 128));
- // Find the 4th key and retrieve it.
- gotit = keys_->find("key4");
- ASSERT_TRUE(gotit != keys_->end());
- key = gotit->second;
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key4", TSIGKeyInfo::HMAC_SHA224_STR,
- ref_secret, 112));
- // Find the 5th key and retrieve it.
- gotit = keys_->find("key5");
- ASSERT_TRUE(gotit != keys_->end());
- key = gotit->second;
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key5", TSIGKeyInfo::HMAC_SHA384_STR,
- ref_secret, 192));
- // Find the 6th key and retrieve it.
- gotit = keys_->find("key6");
- ASSERT_TRUE(gotit != keys_->end());
- key = gotit->second;
- // Verify the key contents.
- EXPECT_TRUE(checkKey(key, "key6", TSIGKeyInfo::HMAC_SHA512_STR,
- ref_secret, 256));
- }
- /// @brief Tests the enforcement of data validation when parsing DnsServerInfos.
- /// It verifies that:
- /// 1. Specifying both a hostname and an ip address is not allowed.
- /// 2. Specifying both blank a hostname and blank ip address is not allowed.
- /// 3. Specifying a negative port number is not allowed.
- TEST_F(DnsServerInfoParserTest, invalidEntry) {
- // Create a config in which both host and ip address are supplied.
- // Verify that parsing fails.
- std::string config = "{ \"hostname\": \"pegasus.example\", "
- " \"ip-address\": \"127.0.0.1\", "
- " \"port\": 100} ";
- PARSE_FAIL(config, "<string>:1.13: hostname is not yet supported");
- // Neither host nor ip address supplied
- // Verify that builds fails.
- config = "{ \"hostname\": \"\", "
- " \"ip-address\": \"\", "
- " \"port\": 100} ";
- PARSE_FAIL(config, "Dns Server must specify one or the other"
- " of hostname or IP address (<string>:1:1)");
- // Create a config with a negative port number.
- // Verify that build fails.
- config = "{ \"hostname\": \"\", "
- " \"ip-address\": \"192.168.5.6\" ,"
- " \"port\": -100 }";
- PARSE_FAIL(config, "<string>:1.60-63: port must be greater than zero but less than 65536");
- }
- /// @brief Verifies that DnsServerInfo parsing creates a proper DnsServerInfo
- /// when given a valid combination of entries.
- /// It verifies that:
- /// 1. A DnsServerInfo entry is correctly made, when given only a hostname.
- /// 2. A DnsServerInfo entry is correctly made, when given ip address and port.
- /// 3. A DnsServerInfo entry is correctly made, when given only an ip address.
- TEST_F(DnsServerInfoParserTest, validEntry) {
- /// @todo When resolvable hostname is supported you'll need this test.
- /// // Valid entries for dynamic host
- /// std::string config = "{ \"hostname\": \"pegasus.example\" }";
- /// ASSERT_TRUE(fromJSON(config));
- /// // Verify that it builds and commits without throwing.
- /// ASSERT_NO_THROW(parser_->build(config_set_));
- /// ASSERT_NO_THROW(parser_->commit());
- /// //Verify the correct number of servers are present
- /// int count = servers_->size();
- /// EXPECT_EQ(1, count);
- /// Verify the server exists and has the correct values.
- /// DnsServerInfoPtr server = (*servers_)[0];
- /// EXPECT_TRUE(checkServer(server, "pegasus.example",
- /// DnsServerInfo::EMPTY_IP_STR,
- /// DnsServerInfo::STANDARD_DNS_PORT));
- /// // Start over for a new test.
- /// reset();
- // Valid entries for static ip
- std::string config = " { \"hostname\" : \"\", "
- " \"ip-address\": \"127.0.0.1\" , "
- " \"port\": 100 }";
- PARSE_OK(config);
- ASSERT_TRUE(server_);
- EXPECT_TRUE(checkServer(server_, "", "127.0.0.1", 100));
- // Verify unparsing.
- runToElementTest<DnsServerInfo>(config, *server_);
- // Valid entries for static ip, no port
- // This will fail without invoking set defaults
- config = " { \"ip-address\": \"192.168.2.5\" }";
- PARSE_OK(config);
- ASSERT_TRUE(server_);
- EXPECT_TRUE(checkServer(server_, "", "192.168.2.5",
- DnsServerInfo::STANDARD_DNS_PORT));
- }
- /// @brief Verifies that attempting to parse an invalid list of DnsServerInfo
- /// entries is detected.
- TEST_F(DnsServerInfoListParserTest, invalidServerList) {
- // Construct a list of servers with an invalid server entry.
- std::string config = "[ { \"ip-address\": \"127.0.0.1\" }, "
- "{ \"ip-address\": \"\" }, "
- "{ \"ip-address\": \"127.0.0.2\" } ]";
- PARSE_FAIL(config, "Dns Server must specify one or the other"
- " of hostname or IP address (<string>:1:34)");
- ASSERT_FALSE(servers_);
- }
- /// @brief Verifies that a list of DnsServerInfo entries parses correctly given
- /// a valid configuration.
- TEST_F(DnsServerInfoListParserTest, validServerList) {
- // Create a valid list of servers.
- std::string config = "[ { \"ip-address\": \"127.0.0.1\" }, "
- "{ \"ip-address\": \"127.0.0.2\" }, "
- "{ \"ip-address\": \"127.0.0.3\" } ]";
- PARSE_OK(config);
- // Verify that the server storage contains the correct number of servers.
- ASSERT_EQ(3, servers_->size());
- // Verify the first server exists and has the correct values.
- DnsServerInfoPtr server = (*servers_)[0];
- EXPECT_TRUE(checkServer(server, "", "127.0.0.1",
- DnsServerInfo::STANDARD_DNS_PORT));
- // Verify the second server exists and has the correct values.
- server = (*servers_)[1];
- EXPECT_TRUE(checkServer(server, "", "127.0.0.2",
- DnsServerInfo::STANDARD_DNS_PORT));
- // Verify the third server exists and has the correct values.
- server = (*servers_)[2];
- EXPECT_TRUE(checkServer(server, "", "127.0.0.3",
- DnsServerInfo::STANDARD_DNS_PORT));
- }
- /// @brief Tests the enforcement of data validation when parsing DdnsDomains.
- /// It verifies that:
- /// 1. Domain storage cannot be null when constructing a DdnsDomainParser.
- /// 2. The name entry is not optional.
- /// 3. The server list may not be empty.
- /// 4. That a mal-formed server entry is detected.
- /// 5. That an undefined key name is detected.
- TEST_F(DdnsDomainParserTest, invalidDomain) {
- // Create a domain configuration without a name
- std::string config = "{ \"key-name\": \"d2_key.example.com\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.1\" , "
- " \"port\": 100 },"
- " { \"ip-address\": \"127.0.0.2\" , "
- " \"port\": 200 },"
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": 300 } ] } ";
- PARSE_FAIL(config, "missing parameter 'name' (<string>:1:1)");
- // Create a domain configuration with an empty server list.
- config = "{ \"name\": \"example.com\" , "
- " \"key-name\": \"\" , "
- " \"dns-servers\" : [ "
- " ] } ";
- PARSE_FAIL(config, "<string>:1.69: syntax error, unexpected ], expecting {");
- // Create a domain configuration with a mal-formed server entry.
- config = "{ \"name\": \"example.com\" , "
- " \"key-name\": \"\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": -1 } ] } ";
- PARSE_FAIL(config, "<string>:1.111-112: port must be greater than zero but less than 65536");
- // Create a domain configuration without an defined key name
- config = "{ \"name\": \"example.com\" , "
- " \"key-name\": \"d2_key.example.com\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": 300 } ] } ";
- PARSE_FAIL(config, "DdnsDomain : example.com specifies"
- " an undefined key: d2_key.example.com (<string>:1:41)");
- }
- /// @brief Verifies the basics of parsing of a DdnsDomain.
- TEST_F(DdnsDomainParserTest, validDomain) {
- // Add a TSIG key to the test key map, so key validation will pass.
- addKey("d2_key.example.com", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
- // Create a valid domain configuration entry containing three valid
- // servers.
- std::string config =
- "{ \"name\": \"example.com\" , "
- " \"key-name\": \"d2_key.example.com\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.1\" , "
- " \"port\": 100 },"
- " { \"ip-address\": \"127.0.0.2\" , "
- " \"port\": 200 },"
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": 300 } ] } ";
- PARSE_OK(config);
- // Domain should exist
- ASSERT_TRUE(domain_);
- // Verify the name and key_name values.
- EXPECT_EQ("example.com", domain_->getName());
- EXPECT_EQ("d2_key.example.com", domain_->getKeyName());
- ASSERT_TRUE(domain_->getTSIGKeyInfo());
- ASSERT_TRUE(domain_->getTSIGKeyInfo()->getTSIGKey());
- // Verify that the server list exists and contains the correct number of
- // servers.
- const DnsServerInfoStoragePtr& servers = domain_->getServers();
- EXPECT_TRUE(servers);
- EXPECT_EQ(3, servers->size());
- // Fetch each server and verify its contents.
- DnsServerInfoPtr server = (*servers)[0];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
- server = (*servers)[1];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
- server = (*servers)[2];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
- // Verify unparsing.
- ElementPtr json;
- ASSERT_NO_THROW(json = Element::fromJSON(config));
- ConstElementPtr servers_json;
- ASSERT_NO_THROW(servers_json = json->get("dns-servers"));
- ASSERT_TRUE(servers_json);
- ASSERT_EQ(Element::list, servers_json->getType());
- for (size_t i = 0; i < servers_json->size(); ++i) {
- ElementPtr server_json;
- ASSERT_NO_THROW(server_json = servers_json->getNonConst(i));
- ASSERT_NO_THROW(server_json->set("hostname",
- Element::create(std::string())));
- }
- runToElementTest<DdnsDomain>(json, *domain_);
- }
- /// @brief Tests the fundamentals of parsing DdnsDomain lists.
- /// This test verifies that given a valid domain list configuration
- /// it will accurately parse and populate each domain in the list.
- TEST_F(DdnsDomainListParserTest, validList) {
- // Add keys to key map so key validation passes.
- addKey("d2_key.example.com", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
- addKey("d2_key.billcat.net", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
- // Create a valid domain list configuration, with two domains
- // that have three servers each.
- std::string config =
- "[ "
- "{ \"name\": \"example.com\" , "
- " \"key-name\": \"d2_key.example.com\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.1\" , "
- " \"port\": 100 },"
- " { \"ip-address\": \"127.0.0.2\" , "
- " \"port\": 200 },"
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": 300 } ] } "
- ", "
- "{ \"name\": \"billcat.net\" , "
- " \"key-name\": \"d2_key.billcat.net\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.4\" , "
- " \"port\": 400 },"
- " { \"ip-address\": \"127.0.0.5\" , "
- " \"port\": 500 },"
- " { \"ip-address\": \"127.0.0.6\" , "
- " \"port\": 600 } ] } "
- "] ";
- // Verify that the domain list parses without error.
- PARSE_OK(config);
- ASSERT_TRUE(domains_);
- EXPECT_EQ(2, domains_->size());
- // Verify that the first domain exists and can be retrieved.
- DdnsDomainMap::iterator gotit = domains_->find("example.com");
- ASSERT_TRUE(gotit != domains_->end());
- DdnsDomainPtr& domain = gotit->second;
- // Verify the name and key_name values of the first domain.
- EXPECT_EQ("example.com", domain->getName());
- EXPECT_EQ("d2_key.example.com", domain->getKeyName());
- // Verify the TSIGKeyInfo name and that the actual key was created
- ASSERT_TRUE(domain->getTSIGKeyInfo());
- EXPECT_EQ(domain->getKeyName(), domain->getTSIGKeyInfo()->getName());
- EXPECT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
- // Verify the each of the first domain's servers
- DnsServerInfoStoragePtr servers = domain->getServers();
- EXPECT_TRUE(servers);
- EXPECT_EQ(3, servers->size());
- DnsServerInfoPtr server = (*servers)[0];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
- server = (*servers)[1];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
- server = (*servers)[2];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
- // Verify second domain
- gotit = domains_->find("billcat.net");
- ASSERT_TRUE(gotit != domains_->end());
- domain = gotit->second;
- // Verify the name and key_name values of the second domain.
- EXPECT_EQ("billcat.net", domain->getName());
- EXPECT_EQ("d2_key.billcat.net", domain->getKeyName());
- ASSERT_TRUE(domain->getTSIGKeyInfo());
- EXPECT_EQ(domain->getKeyName(), domain->getTSIGKeyInfo()->getName());
- EXPECT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
- // Verify the each of second domain's servers
- servers = domain->getServers();
- EXPECT_TRUE(servers);
- servers->size();
- EXPECT_EQ(3, servers->size());
- server = (*servers)[0];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.4", 400));
- server = (*servers)[1];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.5", 500));
- server = (*servers)[2];
- EXPECT_TRUE(server);
- EXPECT_TRUE(checkServer(server, "", "127.0.0.6", 600));
- }
- /// @brief Tests that a domain list configuration cannot contain duplicates.
- TEST_F(DdnsDomainListParserTest, duplicateDomain) {
- // Create a domain list configuration that contains two domains with
- // the same name.
- std::string config =
- "[ "
- "{ \"name\": \"example.com\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": 300 } ] } "
- ", "
- "{ \"name\": \"example.com\" , "
- " \"dns-servers\" : [ "
- " { \"ip-address\": \"127.0.0.3\" , "
- " \"port\": 300 } ] } "
- "] ";
- // Verify that the parsing fails.
- PARSE_FAIL(config,
- "Duplicate domain specified:example.com (<string>:1:115)");
- }
- };
|