From: Marcin Siodelski Date: Tue, 15 Mar 2016 14:41:32 +0000 (+0100) Subject: [4319] Added additional configuration parser tests. X-Git-Tag: trac4248_base~2^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=72f841e8a102e8674c984122597b00d7a4b67f97;p=thirdparty%2Fkea.git [4319] Added additional configuration parser tests. New test check that it is possible to specify a non-standard option within a host declaration. --- diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index e14dfc244a..04de12ffdf 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -465,6 +465,8 @@ public: /// @brief Retrieve an option associated with a host. /// + /// The option is retrieved from the "dhcp4" option space. + /// /// @param host Reference to a host for which an option should be retrieved. /// @param option_code Option code. /// @tparam ReturnType Type of the pointer object returned. @@ -473,10 +475,24 @@ public: template ReturnType retrieveOption(const Host& host, const uint16_t option_code) const { + return (retrieveOption(host, "dhcp4", option_code)); + } + + /// @brief Retrieve an option associated with a host. + /// + /// @param host Reference to a host for which an option should be retrieved. + /// @param space Option space from which option should be retrieved. + /// @param option_code Option code. + /// @tparam ReturnType Type of the pointer object returned. + /// + /// @return Pointer to an option or NULL if not found. + template + ReturnType + retrieveOption(const Host& host, const std::string& space, + const uint16_t option_code) const { ConstCfgOptionPtr cfg_option = host.getCfgOption4(); if (cfg_option) { - OptionDescriptor opt_desc = cfg_option->get(std::string("dhcp4"), - option_code); + OptionDescriptor opt_desc = cfg_option->get(space, option_code); if (opt_desc.option_) { return (boost::dynamic_pointer_cast< typename ReturnType::element_type>(opt_desc.option_)); @@ -3531,7 +3547,82 @@ TEST_F(Dhcp4ParserTest, reservations) { EXPECT_EQ("192.0.4.101", host->getIPv4Reservation().toText()); EXPECT_FALSE(hosts_cfg->get4(123, HWAddrPtr(), duid)); EXPECT_FALSE(hosts_cfg->get4(234, HWAddrPtr(), duid)); + // Check that options are assigned correctly. + opt_dns = retrieveOption(*host, DHO_NAME_SERVERS); + ASSERT_TRUE(opt_dns); + dns_addrs = opt_dns->getAddresses(); + ASSERT_EQ(1, dns_addrs.size()); + EXPECT_EQ("192.0.4.11", dns_addrs[0].toText()); + opt_ttl = retrieveOption(*host, DHO_DEFAULT_IP_TTL); + ASSERT_TRUE(opt_ttl); + EXPECT_EQ(95, static_cast(opt_ttl->getValue())); +} + +// This test checks that it is possible to configure option data for a +// host using a user defined option format. +TEST_F(Dhcp4ParserTest, reservationWithOptionDefinition) { + ConstElementPtr x; + // The following configuration contains host declaration in which + // a non-standard option is used. This option has option definition + // specified in the configuration. + string config = "{ " + genIfaceConfig() + "," + + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"option-def\": [ {" + " \"name\": \"foo\"," + " \"code\": 100," + " \"type\": \"uint32\"," + " \"space\": \"isc\"" + "} ]," + "\"subnet4\": [ " + " {" + " \"reservations\": [" + " {" + " \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + " \"ip-address\": \"192.0.3.112\"," + " \"option-data\": [" + " {" + " \"name\": \"foo\"," + " \"data\": \"123\"," + " \"space\": \"isc\"" + " }" + " ]" + " }," + " ]," + " \"pools\": [ { \"pool\": \"192.0.3.101 - 192.0.3.150\" } ]," + " \"subnet\": \"192.0.3.0/24\", " + " \"id\": 234" + " } ]," + "\"valid-lifetime\": 4000" + "}"; + + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json)); + checkResult(x, 0); + + // Hosts configuration must be available. + CfgHostsPtr hosts_cfg = CfgMgr::instance().getStagingCfg()->getCfgHosts(); + ASSERT_TRUE(hosts_cfg); + // Let's create an object holding DUID of the host. For simplicity the + // address is a collection of numbers from 1 to A. + std::vector duid_vec; + for (int i = 1; i < 0xB; ++i) { + duid_vec.push_back(static_cast(i)); + } + DuidPtr duid(new DUID(duid_vec)); + // Retrieve the reservation and sanity check the address reserved. + ConstHostPtr host = hosts_cfg->get4(234, HWAddrPtr(), duid); + ASSERT_TRUE(host); + EXPECT_EQ("192.0.3.112", host->getIPv4Reservation().toText()); + + // Check if the option has been parsed. + OptionUint32Ptr opt_foo = retrieveOption(*host, "isc", + 100); + ASSERT_TRUE(opt_foo); + EXPECT_EQ(100, opt_foo->getType()); + EXPECT_EQ(123, opt_foo->getValue()); } // This test verifies that the bogus host reservation would trigger a @@ -3616,6 +3707,37 @@ TEST_F(Dhcp4ParserTest, reservationBogus) { EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json)); checkResult(x, 1); + + // Case 4: Broken specification of option data. + config = "{ " + genIfaceConfig() + "," + + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ " + " { " + " \"pools\": [ { \"pool\": \"192.0.4.101 - 192.0.4.150\" } ]," + " \"subnet\": \"192.0.4.0/24\"," + " \"id\": 542," + " \"reservations\": [" + " {" + " \"hw-address\": \"06:05:04:03:02:01\"," + " \"option-data\": [" + " {" + " \"name\": \"name-servers\"," + " \"data\": \"bogus-ip-address\"" + " }" + " ]" + " }" + " ]" + " } ]," + "\"valid-lifetime\": 4000 }"; + + json = Element::fromJSON(config); + + // Remove existing configuration, if any. + CfgMgr::instance().clear(); + + EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json)); + checkResult(x, 1); } /// The goal of this test is to verify that Host Reservation modes can be diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index b81342784e..61b4e4c6db 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 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 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -370,6 +371,45 @@ public: globalContext()->copyContext(ParserContext(Option::V6)); } + /// @brief Retrieve an option associated with a host. + /// + /// The option is retrieved from the "dhcp6" option space. + /// + /// @param host Reference to a host for which an option should be retrieved. + /// @param option_code Option code. + /// @tparam ReturnType Type of the pointer object returned. + /// + /// @return Pointer to an option or NULL if not found. + template + ReturnType + retrieveOption(const Host& host, const uint16_t option_code) const { + return (retrieveOption(host, "dhcp6", option_code)); + } + + /// @brief Retrieve an option associated with a host. + /// + /// @param host Reference to a host for which an option should be retrieved. + /// @param space Option space from which option should be retrieved. + /// @param option_code Option code. + /// @tparam ReturnType Type of the pointer object returned. + /// + /// @return Pointer to an option or NULL if not found. + template + ReturnType + retrieveOption(const Host& host, const std::string& space, + const uint16_t option_code) const { + ConstCfgOptionPtr cfg_option = host.getCfgOption6(); + if (cfg_option) { + OptionDescriptor opt_desc = cfg_option->get(space, option_code); + if (opt_desc.option_) { + return (boost::dynamic_pointer_cast< + typename ReturnType::element_type>(opt_desc.option_)); + } + } + return (ReturnType()); + } + + /// @brief Test invalid option parameter value. /// /// This test function constructs the simple configuration @@ -3491,12 +3531,32 @@ TEST_F(Dhcp6ParserTest, reservations) { " {" " \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," " \"ip-addresses\": [ \"2001:db8:2::1234\" ]," - " \"hostname\": \"\"" + " \"hostname\": \"\"," + " \"option-data\": [" + " {" + " \"name\": \"dns-servers\"," + " \"data\": \"2001:db8:2::1111\"" + " }," + " {" + " \"name\": \"preference\"," + " \"data\": \"11\"" + " }" + " ]" " }," " {" " \"hw-address\": \"01:02:03:04:05:06\"," " \"ip-addresses\": [ \"2001:db8:2::abcd\" ]," - " \"hostname\": \"\"" + " \"hostname\": \"\"," + " \"option-data\": [" + " {" + " \"name\": \"dns-servers\"," + " \"data\": \"2001:db8:2::abbc\"" + " }," + " {" + " \"name\": \"preference\"," + " \"data\": \"25\"" + " }" + " ]" " }" " ]," " \"pools\": [ ]," @@ -3511,7 +3571,17 @@ TEST_F(Dhcp6ParserTest, reservations) { " {" " \"duid\": \"0A:09:08:07:06:05:04:03:02:01\"," " \"prefixes\": [ \"2001:db8:3:2::/96\" ]," - " \"hostname\": \"\"" + " \"hostname\": \"\"," + " \"option-data\": [" + " {" + " \"name\": \"dns-servers\"," + " \"data\": \"2001:db8:3::3333\"" + " }," + " {" + " \"name\": \"preference\"," + " \"data\": \"33\"" + " }" + " ]" " }," " {" " \"hw-address\": \"06:05:04:03:02:01\"," @@ -3561,6 +3631,17 @@ TEST_F(Dhcp6ParserTest, reservations) { // and not to other two. EXPECT_FALSE(hosts_cfg->get6(123, DuidPtr(), hwaddr)); EXPECT_FALSE(hosts_cfg->get6(542, DuidPtr(), hwaddr)); + // Check that options are assigned correctly. + Option6AddrLstPtr opt_dns = + retrieveOption(*host, D6O_NAME_SERVERS); + ASSERT_TRUE(opt_dns); + Option6AddrLst::AddressContainer dns_addrs = opt_dns->getAddresses(); + ASSERT_EQ(1, dns_addrs.size()); + EXPECT_EQ("2001:db8:2::abbc", dns_addrs[0].toText()); + OptionUint8Ptr opt_prf = + retrieveOption(*host, D6O_PREFERENCE); + ASSERT_TRUE(opt_prf); + EXPECT_EQ(25, static_cast(opt_prf->getValue())); // Do the same test for the DUID based reservation. std::vector duid_vec; @@ -3577,6 +3658,16 @@ TEST_F(Dhcp6ParserTest, reservations) { resrv)); EXPECT_FALSE(hosts_cfg->get6(123, duid)); EXPECT_FALSE(hosts_cfg->get6(542, duid)); + // Check that options are assigned correctly. + opt_dns = retrieveOption(*host, D6O_NAME_SERVERS); + ASSERT_TRUE(opt_dns); + dns_addrs = opt_dns->getAddresses(); + ASSERT_EQ(1, dns_addrs.size()); + EXPECT_EQ("2001:db8:2::1111", dns_addrs[0].toText()); + opt_prf = retrieveOption(*host, D6O_PREFERENCE); + ASSERT_TRUE(opt_prf); + EXPECT_EQ(11, static_cast(opt_prf->getValue())); + // The HW address used for one of the reservations in the subnet 542 // consists of numbers from 6 to 1. So, let's just reverse the order @@ -3607,6 +3698,83 @@ TEST_F(Dhcp6ParserTest, reservations) { EXPECT_FALSE(hosts_cfg->get6(123, duid)); EXPECT_FALSE(hosts_cfg->get6(234, duid)); + // Check that options are assigned correctly. + opt_dns = retrieveOption(*host, D6O_NAME_SERVERS); + ASSERT_TRUE(opt_dns); + dns_addrs = opt_dns->getAddresses(); + ASSERT_EQ(1, dns_addrs.size()); + EXPECT_EQ("2001:db8:3::3333", dns_addrs[0].toText()); + opt_prf = retrieveOption(*host, D6O_PREFERENCE); + ASSERT_TRUE(opt_prf); + EXPECT_EQ(33, static_cast(opt_prf->getValue())); +} + +// This test checks that it is possible to configure option data for a +// host using a user defined option format. +TEST_F(Dhcp6ParserTest, reservationWithOptionDefinition) { + ConstElementPtr x; + // The following configuration contains host declaration in which + // a non-standard option is used. This option has option definition + // specified in the configuration. + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"option-def\": [ {" + " \"name\": \"foo\"," + " \"code\": 100," + " \"type\": \"uint32\"," + " \"space\": \"isc\"" + "} ]," + "\"subnet6\": [ " + " {" + " \"reservations\": [" + " {" + " \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + " \"ip-addresses\": [ \"2001:db8:2::1234\" ]," + " \"hostname\": \"\"," + " \"option-data\": [" + " {" + " \"name\": \"foo\"," + " \"data\": \"11\"," + " \"space\": \"isc\"" + " }" + " ]" + " }" + " ]," + " \"pools\": [ ]," + " \"subnet\": \"2001:db8:2::/64\", " + " \"id\": 234" + " }" + "]," + "\"preferred-lifetime\": 3000," + "\"valid-lifetime\": 4000 }"; + + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json)); + checkResult(x, 0); + + // Hosts configuration must be available. + CfgHostsPtr hosts_cfg = CfgMgr::instance().getStagingCfg()->getCfgHosts(); + ASSERT_TRUE(hosts_cfg); + + // Let's create an object holding DUID of the host. For simplicity the + // address is a collection of numbers from 1 to A. + std::vector duid_vec; + for (int i = 1; i < 0xB; ++i) { + duid_vec.push_back(static_cast(i)); + } + DuidPtr duid(new DUID(duid_vec)); + // Retrieve the reservation and sanity check the address reserved. + ConstHostPtr host = hosts_cfg->get6(234, duid); + ASSERT_TRUE(host); + + // Check if the option has been parsed. + OptionUint32Ptr opt_foo = retrieveOption(*host, "isc", + 100); + ASSERT_TRUE(opt_foo); + EXPECT_EQ(100, opt_foo->getType()); + EXPECT_EQ(11, opt_foo->getValue()); } // This test verifies that the bogus host reservation would trigger a @@ -3696,6 +3864,38 @@ TEST_F(Dhcp6ParserTest, reservationBogus) { EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json)); checkResult(x, 1); + // Case 4: Broken specification of option data. + config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ " + " { " + " \"pools\": [ ]," + " \"subnet\": \"2001:db8:3::/64\", " + " \"id\": 542," + " \"reservations\": [" + " {" + " \"duid\": \"0A:09:08:07:06:05:04:03:02:01\"," + " \"option-data\": [" + " {" + " \"name\": \"dns-servers\"," + " \"data\": \"invalid-ip-address\"" + " }" + " ]" + " }" + " ]" + " } " + "], " + "\"preferred-lifetime\": 3000," + "\"valid-lifetime\": 4000 }"; + + json = Element::fromJSON(config); + + // Remove existing configuration, if any. + CfgMgr::instance().clear(); + + EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json)); + checkResult(x, 1); } /// The goal of this test is to verify that configuration can include