From aaaca540c568cbe8c91949dc90ff1b4f920dcc64 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 18 Oct 2016 15:49:16 +0200 Subject: [PATCH] [5023] Code fixed, unit-tests implemented. --- src/bin/dhcp6/json_config_parser.cc | 1 + src/bin/dhcp6/tests/config_parser_unittest.cc | 264 ++++++++++++++++-- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 16 +- src/lib/dhcpsrv/parsers/dhcp_parsers.h | 3 - 4 files changed, 256 insertions(+), 28 deletions(-) diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 31cab47201..6ceabe6666 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -189,6 +189,7 @@ public: parser = option_parser; } else if (entry == "user-context") { user_context_ = param.second; + continue; // no parser to remember, simply store the value } else { isc_throw(DhcpConfigError, "unsupported parameter: " << entry << " (" << param.second->getPosition() << ")"); diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 5ca86f087d..d063b2ce29 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -56,13 +56,13 @@ using namespace std; namespace { const char* PARSER_CONFIGS[] = { - // CONFIGURATION 0: - // - basic timers, one subnet + // CONFIGURATION 0: one subnet with one pool, no user contexts "{" - " \"inerfaces-config\": {" + " \"interfaces-config\": {" " \"interfaces\": [\"*\" ]" " }," " \"valid-lifetime\": 4000," + " \"preferred-lifetime\": 3000," " \"rebind-timer\": 2000," " \"renew-timer\": 1000," " \"subnet6\": [ {" @@ -72,22 +72,115 @@ const char* PARSER_CONFIGS[] = { " \"subnet\": \"2001:db8::/32\"" " } ]" "}", + + // Configuration 1: one pool with empty user context + "{" + " \"interfaces-config\": {" + " \"interfaces\": [\"*\" ]" + " }," + " \"valid-lifetime\": 4000," + " \"preferred-lifetime\": 3000," + " \"rebind-timer\": 2000," + " \"renew-timer\": 1000," + " \"subnet6\": [ {" + " \"pools\": [ " + " { \"pool\": \"2001:db8::/64\"," + " \"user-context\": {" + " }" + " }" + " ]," + " \"subnet\": \"2001:db8::/32\"" + " } ]" + "}", + + // Configuration 2: one pool with user context containing lw4over6 parameters "{" - " \"inerfaces-config\": {" + " \"interfaces-config\": {" " \"interfaces\": [\"*\" ]" " }," " \"valid-lifetime\": 4000," + " \"preferred-lifetime\": 3000," " \"rebind-timer\": 2000," " \"renew-timer\": 1000," " \"subnet6\": [ {" " \"pools\": [ " " { \"pool\": \"2001:db8::/64\"," " \"user-context\": {" + " \"lw4over6-sharing-ratio\": 64," + " \"lw4over6-v4-pool\": \"192.0.2.0/24\"," + " \"lw4over6-sysports-exclude\": true," + " \"lw4over6-bind-prefix-len\": 56" " }" " }" " ]," " \"subnet\": \"2001:db8::/32\"" " } ]" + "}", + + // Configuration 3: pd-pool without any user-context + "{" + " \"interfaces-config\": {" + " \"interfaces\": [\"*\" ]" + " }," + " \"valid-lifetime\": 4000," + " \"preferred-lifetime\": 3000," + " \"rebind-timer\": 2000," + " \"renew-timer\": 1000," + " \"subnet6\": [ {" + " \"pd-pools\": [ " + " { \"prefix\": \"2001:db8::\"," + " \"prefix-len\": 56," + " \"delegated-len\": 64 }" + " ]," + " \"subnet\": \"2001:db8::/32\"" + " } ]" + "}", + + // Configuration 4: pd-pool with empty user-context + "{" + " \"interfaces-config\": {" + " \"interfaces\": [\"*\" ]" + " }," + " \"valid-lifetime\": 4000," + " \"preferred-lifetime\": 3000," + " \"rebind-timer\": 2000," + " \"renew-timer\": 1000," + " \"subnet6\": [ {" + " \"pd-pools\": [ " + " { \"prefix\": \"2001:db8::\"," + " \"prefix-len\": 56," + " \"delegated-len\": 64," + " \"user-context\": { }" + " }" + " ]," + " \"subnet\": \"2001:db8::/32\"" + " } ]" + "}", + + // Configuration 5: pd-pool with user-context with lw4over6 parameters + "{" + " \"interfaces-config\": {" + " \"interfaces\": [\"*\" ]" + " }," + " \"valid-lifetime\": 4000," + " \"preferred-lifetime\": 3000," + " \"rebind-timer\": 2000," + " \"renew-timer\": 1000," + " \"subnet6\": [ {" + " \"pd-pools\": [ " + " { \"prefix\": \"2001:db8::\"," + " \"prefix-len\": 56," + " \"delegated-len\": 64," + " \"user-context\": {" + " \"lw4over6-sharing-ratio\": 64," + " \"lw4over6-v4-pool\": \"192.0.2.0/24\"," + " \"lw4over6-sysports-exclude\": true," + " \"lw4over6-bind-prefix-len\": 56" + " }" + " }" + " ]," + " \"subnet\": \"2001:db8::/32\"" + " } ]" "}" }; @@ -598,6 +691,37 @@ public: CfgMgr::instance().clear(); } + /// @brief This utility method attempts to configure using specified + /// config and then returns requested pool from requested subnet + /// + /// @param config configuration to be applied + /// @param subnet_index index of the subnet to be returned (0 - the first subnet) + /// @param pool_index index of the pool within a subnet (0 - the first pool) + /// @param type Pool type (TYPE_NA or TYPE_PD) + /// @param pool [out] Pool pointer will be stored here (if found) + void getPool(const std::string& config, size_t subnet_index, + size_t pool_index, Lease::Type type, PoolPtr& pool) { + ConstElementPtr status; + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + ConstCfgSubnets6Ptr subnets6 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); + ASSERT_TRUE(subnets6); + + const Subnet6Collection* subnets = subnets6->getAll(); + ASSERT_TRUE(subnets); + ASSERT_GE(subnets->size(), subnet_index + 1); + + const PoolCollection pools = subnets->at(subnet_index)->getPools(type); + ASSERT_GE(pools.size(), pool_index + 1); + + pool = pools.at(pool_index); + EXPECT_TRUE(pool); + } + int rcode_; ///< Return code (see @ref isc::config::parseAnswer) Dhcpv6Srv srv_; ///< Instance of the Dhcp6Srv used during tests ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer) @@ -4554,27 +4678,129 @@ TEST_F(Dhcp6ParserTest, invalidClientClassDictionary) { checkResult(status, 1); } -TEST_F(Dhcp6ParserTest, PdPoolUserContextEmpty) { +// Test verifies that regular configuration does not provide any user context +// in the address pool. +TEST_F(Dhcp6ParserTest, poolUserContextMissing) { + PoolPtr pool; + getPool(string(PARSER_CONFIGS[0]), 0, 0, Lease::TYPE_NA, pool); + ASSERT_TRUE(pool); + EXPECT_FALSE(pool->getContext()); +} - ConstElementPtr status; - ElementPtr json = Element::fromJSON(string(PARSER_CONFIGS[0])); +// Test verifies that it's possible to specify empty user context in the +// address pool. +TEST_F(Dhcp6ParserTest, poolUserContextEmpty) { + PoolPtr pool; + getPool(string(PARSER_CONFIGS[1]), 0, 0, Lease::TYPE_NA, pool); + ASSERT_TRUE(pool); + ConstElementPtr ctx = pool->getContext(); + ASSERT_TRUE(ctx); - EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); - ASSERT_TRUE(status); - checkResult(status, 1); + // The context should be of type map and not contain any parameters. + EXPECT_EQ(Element::map, ctx->getType()); + EXPECT_EQ(0, ctx->size()); +} - ConstCfgSubnets6Ptr subnets6 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6(); - ASSERT_TRUE(subnets6); +// Test verifies that it's possible to specify parameters in the user context +// in the address pool. +TEST_F(Dhcp6ParserTest, poolUserContextlw4over6) { + PoolPtr pool; + getPool(string(PARSER_CONFIGS[2]), 0, 0, Lease::TYPE_NA, pool); + ASSERT_TRUE(pool); + ConstElementPtr ctx = pool->getContext(); + ASSERT_TRUE(ctx); + + // The context should be of type map and contain 4 parameters. + EXPECT_EQ(Element::map, ctx->getType()); + EXPECT_EQ(4, ctx->size()); + ConstElementPtr ratio = ctx->get("lw4over6-sharing-ratio"); + ConstElementPtr v4pool = ctx->get("lw4over6-v4-pool"); + ConstElementPtr exclude = ctx->get("lw4over6-sysports-exclude"); + ConstElementPtr v6len = ctx->get("lw4over6-bind-prefix-len"); + + ASSERT_TRUE(ratio); + ASSERT_EQ(Element::integer, ratio->getType()); + int64_t int_value; + EXPECT_NO_THROW(ratio->getValue(int_value)); + EXPECT_EQ(64L, int_value); + + ASSERT_TRUE(v4pool); + ASSERT_EQ(Element::string, v4pool->getType()); + EXPECT_EQ("192.0.2.0/24", v4pool->stringValue()); + + ASSERT_TRUE(exclude); + bool bool_value; + ASSERT_EQ(Element::boolean, exclude->getType()); + EXPECT_NO_THROW(exclude->getValue(bool_value)); + EXPECT_EQ(true, bool_value); + + ASSERT_TRUE(v6len); + ASSERT_EQ(Element::integer, v6len->getType()); + EXPECT_NO_THROW(v6len->getValue(int_value)); + EXPECT_EQ(56L, int_value); +} - const Subnet6Collection* subnets = subnets6->getAll(); - ASSERT_TRUE(subnets); +// Test verifies that regular configuration does not provide any user context +// in the address pool. +TEST_F(Dhcp6ParserTest, pdPoolUserContextMissing) { + PoolPtr pool; + getPool(string(PARSER_CONFIGS[3]), 0, 0, Lease::TYPE_PD, pool); + ASSERT_TRUE(pool); + EXPECT_FALSE(pool->getContext()); +} - ASSERT_EQ(1, subnets->size()); +// Test verifies that it's possible to specify empty user context in the +// address pool. +TEST_F(Dhcp6ParserTest, pdPoolUserContextEmpty) { + PoolPtr pool; + getPool(string(PARSER_CONFIGS[4]), 0, 0, Lease::TYPE_PD, pool); + ASSERT_TRUE(pool); + ConstElementPtr ctx = pool->getContext(); + ASSERT_TRUE(ctx); - const PoolCollection pools = subnets->at(0)->getPools(Lease::TYPE_NA); - ASSERT_EQ(1, pools.size()); - - + // The context should be of type map and not contain any parameters. + EXPECT_EQ(Element::map, ctx->getType()); + EXPECT_EQ(0, ctx->size()); } +// Test verifies that it's possible to specify parameters in the user context +// in the address pool. +TEST_F(Dhcp6ParserTest, pdPoolUserContextlw4over6) { + PoolPtr pool; + getPool(string(PARSER_CONFIGS[5]), 0, 0, Lease::TYPE_PD, pool); + ASSERT_TRUE(pool); + ConstElementPtr ctx = pool->getContext(); + ASSERT_TRUE(ctx); + + // The context should be of type map and contain 4 parameters. + EXPECT_EQ(Element::map, ctx->getType()); + EXPECT_EQ(4, ctx->size()); + ConstElementPtr ratio = ctx->get("lw4over6-sharing-ratio"); + ConstElementPtr v4pool = ctx->get("lw4over6-v4-pool"); + ConstElementPtr exclude = ctx->get("lw4over6-sysports-exclude"); + ConstElementPtr v6len = ctx->get("lw4over6-bind-prefix-len"); + + ASSERT_TRUE(ratio); + ASSERT_EQ(Element::integer, ratio->getType()); + int64_t int_value; + EXPECT_NO_THROW(ratio->getValue(int_value)); + EXPECT_EQ(64L, int_value); + + ASSERT_TRUE(v4pool); + ASSERT_EQ(Element::string, v4pool->getType()); + EXPECT_EQ("192.0.2.0/24", v4pool->stringValue()); + + ASSERT_TRUE(exclude); + bool bool_value; + ASSERT_EQ(Element::boolean, exclude->getType()); + EXPECT_NO_THROW(exclude->getValue(bool_value)); + EXPECT_EQ(true, bool_value); + + ASSERT_TRUE(v6len); + ASSERT_EQ(Element::integer, v6len->getType()); + EXPECT_NO_THROW(v6len->getValue(int_value)); + EXPECT_EQ(56L, int_value); +} + + }; diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index b5f4cf5a48..04ac63aab2 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -1100,6 +1100,16 @@ PoolParser::build(ConstElementPtr pool_structure) { pool = poolMaker(addr, len); local_pools_.push_back(pool); + // If there's user-context specified, store it. + ConstElementPtr user_context = pool_structure->get("user-context"); + if (user_context) { + if (user_context->getType() != Element::map) { + isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map (" + << user_context->getPosition() << ")"); + } + pool->setUserContext(user_context); + } + } else { // Is this min-max notation? @@ -1144,12 +1154,6 @@ PoolParser::build(ConstElementPtr pool_structure) { << " (" << option_data->getPosition() << ")"); } } - - user_context_ = pool_structure->get("user-context"); - if (user_context_ && user_context_->getType() != Element::map) { - isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map (" - << user_context_->getPosition() << ")"); - } } void diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h index f6ea3d93b4..67f62074c1 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.h @@ -885,9 +885,6 @@ protected: /// A storage for pool specific option values. CfgOptionPtr options_; - /// A storage for user context. - isc::data::ConstElementPtr user_context_; - /// @brief Address family: AF_INET (for DHCPv4) or AF_INET6 for DHCPv6. uint16_t address_family_; }; -- 2.47.3