From: Thomas Markwalder Date: Fri, 5 Apr 2019 06:04:23 +0000 (-0400) Subject: [#365,!296] Added kea-dhcp6 parsing support for calculate-tee-time and percents X-Git-Tag: Kea-1.6.0-beta~190 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=c1954eb6804de4f7870da0c1c82ac60399147ede;p=thirdparty%2Fkea.git [#365,!296] Added kea-dhcp6 parsing support for calculate-tee-time and percents src/bin/dhcp6/dhcp6_lexer.ll src/bin/dhcp6/dhcp6_parser.yy src/bin/dhcp6/json_config_parser.cc src/lib/dhcpsrv/parsers/simple_parser6.cc added support for calculate-tee-times, t1-percent and t2-percent src/bin/dhcp6/tests/tee_times_unittest.cc - new file with tests for t1/t2 determination src/lib/dhcpsrv/parsers/dhcp_parsers.cc Subnet6ConfigParser::initSubnet() - added invocation of parseTeePercents() src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc updated tests src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc TEST(CfgSubnets6Test, teeTimePercentValidation) - new test --- diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 3a2f461158..10c54e8219 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -1171,6 +1171,39 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} } } +\"calculate-tee-times\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_CALCULATE_TEE_TIMES(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("calculate-tee-times", driver.loc_); + } +} + +\"t1-percent\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_T1_PERCENT(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("t1-percent", driver.loc_); + } +} + +\"t2-percent\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_T2_PERCENT(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("t2-percent", driver.loc_); + } +} + \"Logging\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::CONFIG: diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index bd321f3d99..24f9f39de5 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -89,6 +89,9 @@ using namespace std; VALID_LIFETIME "valid-lifetime" RENEW_TIMER "renew-timer" REBIND_TIMER "rebind-timer" + CALCULATE_TEE_TIMES "calculate-tee-times" + T1_PERCENT "t1-percent" + T2_PERCENT "t2-percent" DECLINE_PROBATION_PERIOD "decline-probation-period" SERVER_TAG "server-tag" SUBNET6 "subnet6" @@ -472,6 +475,9 @@ global_param: data_directory | config_control | server_tag | reservation_mode + | calculate_tee_times + | t1_percent + | t2_percent | unknown_map_entry ; @@ -503,6 +509,21 @@ rebind_timer: REBIND_TIMER COLON INTEGER { ctx.stack_.back()->set("rebind-timer", prf); }; +calculate_tee_times: CALCULATE_TEE_TIMES COLON BOOLEAN { + ElementPtr ctt(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("calculate-tee-times", ctt); +}; + +t1_percent: T1_PERCENT COLON FLOAT { + ElementPtr t1(new DoubleElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("t1-percent", t1); +}; + +t2_percent: T2_PERCENT COLON FLOAT { + ElementPtr t2(new DoubleElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("t2-percent", t2); +}; + decline_probation_period: DECLINE_PROBATION_PERIOD COLON INTEGER { ElementPtr dpp(new IntElement($3, ctx.loc2pos(@3))); ctx.stack_.back()->set("decline-probation-period", dpp); diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index c15c2ce7bc..b495e41ed7 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -670,7 +670,11 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set, (config_pair.first == "decline-probation-period") || (config_pair.first == "dhcp4o6-port") || (config_pair.first == "server-tag") || - (config_pair.first == "reservation-mode")) { + (config_pair.first == "reservation-mode") || + (config_pair.first == "calculate-tee-times") || + (config_pair.first == "t1-percent") || + (config_pair.first == "t2-percent")) { + CfgMgr::instance().getStagingCfg()->addConfiguredGlobal(config_pair.first, config_pair.second); continue; diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index 15ad57b9de..7b017efb73 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/src/bin/dhcp6/tests/Makefile.am @@ -107,6 +107,7 @@ dhcp6_unittests_SOURCES += renew_unittest.cc dhcp6_unittests_SOURCES += sarr_unittest.cc dhcp6_unittests_SOURCES += simple_parser6_unittest.cc dhcp6_unittests_SOURCES += shared_network_unittest.cc +dhcp6_unittests_SOURCES += tee_times_unittest.cc dhcp6_unittests_SOURCES += vendor_opts_unittest.cc nodist_dhcp6_unittests_SOURCES = marker_file.h test_libraries.h diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index 4c429e1f7d..fa23d7acbc 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2019 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 @@ -870,6 +870,21 @@ Dhcp6Client::getStatusCode(const uint32_t iaid) const { return (0xFFFF); } +bool +Dhcp6Client::getTeeTimes(const uint32_t iaid, uint32_t& t1, uint32_t& t2) const { + + auto leases = getLeasesByIAID(iaid); + if (leases.empty()) { + // No aquired leases so punt. + return (false); + } + + // All leases for a given iaid should have the same values for T1 + // and T2, so using them from the first one should be fine. + t1 = leases[0].t1_; + t2 = leases[0].t2_; + return (true); +} void Dhcp6Client::setDUID(const std::string& str) { diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index 13efc6a2d8..f69f3ab1ae 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/src/bin/dhcp6/tests/dhcp6_client.h @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2019 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 @@ -499,14 +499,29 @@ public: /// @brief Returns status code set by the server for the IAID. /// - /// @warning This method doesn't check if the specified index is out of - /// range. The caller is responsible for using a correct offset by - /// invoking the @c getLeaseNum function. - /// - /// @param at Index of the lease held by the client. - /// @return A status code for the lease at the specified index. + /// @param iaid for which the status is desired + /// @return A status code for the given iaid uint16_t getStatusCode(const uint32_t iaid) const; + /// @brief Returns T1 and T2 timers associated with a given iaid + /// + /// Currently this method gleans the T1 an T2 times from the first + /// aquired lease belonging to the target iaid. Since all leases for + /// an iaid should have the same values for T1 and T2, this should be + /// fine. If there are no acquired leases for the iaid, then t1 and + /// t2 are indeterminate. + /// + /// The primary impetus for this method is isolate the fact that T1 + /// and T2 are stored on each lease. This may change in the future. + /// + /// @param iaid iaid of the target IA + /// @param[out] t1 set to the value of the IA's T1 + /// @param[out] t2 set to the value of the IA's T2 + /// if there are no leases for the iaid + /// + /// @return true if there are aquired leases for the given iaid + bool getTeeTimes(const uint32_t iaid, uint32_t& t1, uint32_t& t2) const; + /// @brief Returns number of acquired leases. size_t getLeaseNum() const { return (config_.leases_.size()); diff --git a/src/bin/dhcp6/tests/tee_times_unittest.cc b/src/bin/dhcp6/tests/tee_times_unittest.cc new file mode 100644 index 0000000000..1f33980ccc --- /dev/null +++ b/src/bin/dhcp6/tests/tee_times_unittest.cc @@ -0,0 +1,183 @@ +// Copyright (C) 2019 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace isc; +using namespace isc::asiolink; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::dhcp::test; + +namespace { + +/// @brief Set of JSON configurations used throughout the Rebind tests. +/// +/// - Configuration 0: +/// - only addresses (no prefixes) +/// - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::/64 +/// - 1 subnet for eth0 and 1 subnet for eth1 +/// +const char* TEE_CONFIGS[] = { + // Configuration 0, Timers explicitly set + "{ \n" + " \"interfaces-config\": { \n" + " \"interfaces\": [ \"*\" ] \n" + " }, \n" + " \"renew-timer\": 1000, \n" + " \"rebind-timer\": 2000, \n" + " \"preferred-lifetime\": 3000, \n" + " \"valid-lifetime\": 4000, \n" + " \"subnet6\": [ { \n" + " \"interface\": \"eth0\", \n" + " \"subnet\": \"2001:db8:1::/48\", \n" + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], \n" + " \"pd-pools\": [ \n" + " { \n" + " \"prefix\": \"3000::\", \n " + " \"prefix-len\": 72, \n" + " \"delegated-len\": 80 \n" + " }] \n" + " }] \n" + "} \n" + , // Configuration 1, Calculate default timers + "{ \n" + " \"interfaces-config\": { \n" + " \"interfaces\": [ \"*\" ] \n" + " }, \n" + " \"calculate-tee-times\": true, \n" + " \"preferred-lifetime\": 3000, \n" + " \"valid-lifetime\": 4000, \n" + " \"subnet6\": [ { \n" + " \"interface\": \"eth0\", \n" + " \"subnet\": \"2001:db8:1::/48\", \n" + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], \n" + " \"pd-pools\": [ \n" + " { \n" + " \"prefix\": \"3000::\", \n " + " \"prefix-len\": 72, \n" + " \"delegated-len\": 80 \n" + " }] \n" + " }] \n" + "} \n" +}; + +/// @brief Test fixture class for testing Rebind. +class TeeTest : public Dhcpv6MessageTest { +public: + + /// @brief Constructor. + /// + /// Sets up fake interfaces. + TeeTest() + : Dhcpv6MessageTest() { + } + + void genRequest(const std::string& config, Dhcp6Client& client, + uint32_t exp_leases) { + // Configure the server. + ASSERT_NO_THROW(configure(config, *client.getServer())); + + // Do the actual 4-way exchange. + ASSERT_NO_THROW(client.doSARR()); + + // Make sure that we go the expectec number of leases. + ASSERT_EQ(exp_leases, client.getLeaseNum()); + + // Simulate aging of leases, by moving their cltt_ back by 1000s. + client.fastFwdTime(1000); + } +}; + +TEST_F(TeeTest, explicitTimers) { + Dhcp6Client client; + + uint32_t na_iaid = 2222; + client.requestAddress(na_iaid); + + uint32_t pd_iaid = 3333; + client.requestPrefix(pd_iaid); + + uint32_t exp_leases = 2; + + // Configure client to request IA_NA. + // Make 4-way exchange to get the lease. + ASSERT_NO_FATAL_FAILURE(genRequest(TEE_CONFIGS[0], client, exp_leases)); + + // Make sure the timers are right for both IAs + uint32_t actual_t1; + uint32_t actual_t2; + + ASSERT_TRUE(client.getTeeTimes(na_iaid, actual_t1, actual_t2)); + EXPECT_EQ(1000, actual_t1); + EXPECT_EQ(2000, actual_t2); + + ASSERT_TRUE(client.getTeeTimes(pd_iaid, actual_t1, actual_t2)); + EXPECT_EQ(1000, actual_t1); + EXPECT_EQ(2000, actual_t2); + + // Let's renew the leases. + ASSERT_NO_THROW(client.doRenew()); + + // Now check the timers again. + ASSERT_TRUE(client.getTeeTimes(na_iaid, actual_t1, actual_t2)); + EXPECT_EQ(1000, actual_t1); + EXPECT_EQ(2000, actual_t2); + + ASSERT_TRUE(client.getTeeTimes(pd_iaid, actual_t1, actual_t2)); + EXPECT_EQ(1000, actual_t1); + EXPECT_EQ(2000, actual_t2); +} + +TEST_F(TeeTest, calculateTimers) { + Dhcp6Client client; + + uint32_t na_iaid = 2222; + client.requestAddress(na_iaid); + + uint32_t pd_iaid = 3333; + client.requestPrefix(pd_iaid); + + uint32_t exp_leases = 2; + + // Configure client to request IA_NA. + // Make 4-way exchange to get the lease. + ASSERT_NO_FATAL_FAILURE(genRequest(TEE_CONFIGS[1], client, exp_leases)); + + // Make sure the timers are right for both IAs + uint32_t actual_t1; + uint32_t actual_t2; + + ASSERT_TRUE(client.getTeeTimes(na_iaid, actual_t1, actual_t2)); + EXPECT_EQ(2000, actual_t1); + EXPECT_EQ(3200, actual_t2); + + ASSERT_TRUE(client.getTeeTimes(pd_iaid, actual_t1, actual_t2)); + EXPECT_EQ(2000, actual_t1); + EXPECT_EQ(3200, actual_t2); + + // Let's renew the leases. + ASSERT_NO_THROW(client.doRenew()); + + // Now check the timers again. + ASSERT_TRUE(client.getTeeTimes(na_iaid, actual_t1, actual_t2)); + EXPECT_EQ(2000, actual_t1); + EXPECT_EQ(3200, actual_t2); + + ASSERT_TRUE(client.getTeeTimes(pd_iaid, actual_t1, actual_t2)); + EXPECT_EQ(2000, actual_t1); + EXPECT_EQ(3200, actual_t2); +} + + +} // end of anonymous namespace diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 79af4c879b..eaf0ba9821 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -904,6 +904,7 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params, // Copy options to the subnet configuration. options_->copyTo(*subnet4->getCfgOption()); + // Parse t1-percent and t2-percent parseTeePercents(params, network); } @@ -1274,6 +1275,9 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params, // Copy options to the subnet configuration. options_->copyTo(*subnet6->getCfgOption()); + + // Parse t1-percent and t2-percent + parseTeePercents(params, network); } //**************************** Subnet6ListConfigParser ******************** diff --git a/src/lib/dhcpsrv/parsers/simple_parser6.cc b/src/lib/dhcpsrv/parsers/simple_parser6.cc index 3db7114676..6a2cd50b29 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser6.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser6.cc @@ -66,7 +66,10 @@ const SimpleKeywords SimpleParser6::GLOBAL6_PARAMETERS = { { "reservations", Element::list }, { "config-control", Element::map }, { "server-tag", Element::string }, - { "reservation-mode", Element::string } + { "reservation-mode", Element::string }, + { "calculate-tee-times", Element::boolean }, + { "t1-percent", Element::real }, + { "t2-percent", Element::real } }; /// @brief This table defines default values for option definitions in DHCPv6. @@ -97,14 +100,15 @@ const SimpleDefaults SimpleParser6::OPTION6_DEFAULTS = { /// in Dhcp6) are optional. If not defined, the following values will be /// used. const SimpleDefaults SimpleParser6::GLOBAL6_DEFAULTS = { - { "renew-timer", Element::integer, "900" }, - { "rebind-timer", Element::integer, "1800" }, { "preferred-lifetime", Element::integer, "3600" }, { "valid-lifetime", Element::integer, "7200" }, { "decline-probation-period", Element::integer, "86400" }, // 24h { "dhcp4o6-port", Element::integer, "0" }, { "server-tag", Element::string, "" }, - { "reservation-mode", Element::string, "all" } + { "reservation-mode", Element::string, "all" }, + { "calculate-tee-times", Element::boolean, "false" }, + { "t1-percent", Element::real, ".50" }, + { "t2-percent", Element::real, ".80" } }; /// @brief This table defines default values for each IPv6 subnet. @@ -154,7 +158,10 @@ const ParamsList SimpleParser6::INHERIT_TO_SUBNET6 = { "relay", "renew-timer", "reservation-mode", - "valid-lifetime" + "valid-lifetime", + "calculate-tee-times", + "t1-percent", + "t2-percent" }; /// @brief This table defines default values for dhcp-queue-control in DHCPv4. diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc index 44f4b72c26..0f6bd7ce53 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc @@ -196,6 +196,9 @@ TEST(CfgSharedNetworks6Test, unparse) { network1->setIface("eth0"); network1->addRelayAddress(IOAddress("2001:db8:1::1")); network1->addRelayAddress(IOAddress("2001:db8:1::2")); + network1->setCalculateTeeTimes(true); + network1->setT1Percent(.35); + network1->setT2Percent(.655); network2->setIface("eth1"); network2->setT1(Triplet(100)); @@ -219,11 +222,14 @@ TEST(CfgSharedNetworks6Test, unparse) { " \"valid-lifetime\": 300\n" " },\n" " {\n" + " \"calculate-tee-times\": true,\n" " \"interface\": \"eth0\",\n" " \"name\": \"frog\",\n" " \"option-data\": [ ],\n" " \"relay\": { \"ip-addresses\": [ \"2001:db8:1::1\", \"2001:db8:1::2\" ] },\n" - " \"subnet6\": [ ]\n" + " \"subnet6\": [ ],\n" + " \"t1-percent\": .35,\n" + " \"t2-percent\": .655\n" " }\n" "]\n"; diff --git a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc index 332f8fc1f4..2fd5119f31 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc @@ -11,10 +11,13 @@ #include #include #include +#include #include #include #include #include +#include + #include #include @@ -537,6 +540,10 @@ TEST(CfgSubnets6Test, unparseSubnet) { OptionPtr ifaceid = generateInterfaceId("relay.eth0"); subnet1->setInterfaceId(ifaceid); subnet1->allowClientClass("foo"); + + subnet1->setT1Percent(0.45); + subnet1->setT2Percent(0.70); + subnet2->setIface("lo"); subnet2->addRelayAddress(IOAddress("2001:db8:ff::2")); subnet3->setIface("eth1"); @@ -544,6 +551,9 @@ TEST(CfgSubnets6Test, unparseSubnet) { subnet3->requireClientClass("bar"); subnet3->setHostReservationMode(Network::HR_ALL); subnet3->setRapidCommit(false); + subnet3->setCalculateTeeTimes(true); + subnet3->setT1Percent(0.50); + subnet3->setT2Percent(0.65); data::ElementPtr ctx1 = data::Element::fromJSON("{ \"comment\": \"foo\" }"); subnet1->setContext(ctx1); @@ -560,6 +570,8 @@ TEST(CfgSubnets6Test, unparseSubnet) { " \"comment\": \"foo\",\n" " \"id\": 123,\n" " \"subnet\": \"2001:db8:1::/48\",\n" + " \"t1-percent\": 0.45," + " \"t2-percent\": 0.7," " \"interface-id\": \"relay.eth0\",\n" " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" @@ -597,7 +609,10 @@ TEST(CfgSubnets6Test, unparseSubnet) { " \"pools\": [ ],\n" " \"pd-pools\": [ ],\n" " \"option-data\": [ ],\n" - " \"require-client-classes\": [ \"foo\", \"bar\" ]\n" + " \"require-client-classes\": [ \"foo\", \"bar\" ],\n" + " \"calculate-tee-times\": true,\n" + " \"t1-percent\": 0.50,\n" + " \"t2-percent\": 0.65\n" "} ]\n"; runToElementTest(expected, cfg); } @@ -898,4 +913,107 @@ TEST(CfgSubnets6Test, mergeSubnets) { EXPECT_EQ("RULE!", opstr->getValue()); } +// This test verifies the Subnet6 parser's validation logic for +// t1-percent and t2-percent parameters. +TEST(CfgSubnets6Test, teeTimePercentValidation) { + + // Describes a single test scenario. + struct Scenario { + std::string label; // label used for logging test failures + bool calculate_tee_times; // value of calculate-tee-times parameter + double t1_percent; // value of t1-percent parameter + double t2_percent; // value of t2-percent parameter + std::string error_message; // expected error message is parsing should fail + }; + + // Test Scenarios. + std::vector tests = { + {"off and valid", false, .5, .95, ""}, + {"on and valid", true, .5, .95, ""}, + {"t2_negative", true, .5, -.95, + "subnet configuration failed: t2-percent:" + " -0.95 is invalid, it must be greater than 0.0 and less than 1.0" + }, + {"t2_too_big", true, .5, 1.95, + "subnet configuration failed: t2-percent:" + " 1.95 is invalid, it must be greater than 0.0 and less than 1.0" + }, + {"t1_negative", true, -.5, .95, + "subnet configuration failed: t1-percent:" + " -0.5 is invalid it must be greater than 0.0 and less than 1.0" + }, + {"t1_too_big", true, 1.5, .95, + "subnet configuration failed: t1-percent:" + " 1.5 is invalid it must be greater than 0.0 and less than 1.0" + }, + {"t1_bigger_than_t2", true, .85, .45, + "subnet configuration failed: t1-percent:" + " 0.85 is invalid, it must be less than t2-percent: 0.45" + } + }; + + // First we create a set of elements that provides all + // required for a Subnet6. + std::string json = + " {" + " \"id\": 1,\n" + " \"subnet\": \"2001:db8:1::/64\", \n" + " \"interface\": \"\", \n" + " \"renew-timer\": 100, \n" + " \"rebind-timer\": 200, \n" + " \"valid-lifetime\": 300, \n" + " \"client-class\": \"\", \n" + " \"require-client-classes\": [] \n," + " \"reservation-mode\": \"all\", \n" + " \"4o6-interface\": \"\", \n" + " \"4o6-interface-id\": \"\", \n" + " \"4o6-subnet\": \"\", \n" + " \"dhcp4o6-port\": 0, \n" + " \"decline-probation-period\": 86400 \n" + " }"; + + + data::ElementPtr elems; + ASSERT_NO_THROW(elems = data::Element::fromJSON(json)) + << "invalid JSON:" << json << "\n test is broken"; + + // Iterate over the test scenarios, verifying each prescribed + // outcome. + for (auto test = tests.begin(); test != tests.end(); ++test) { + { + SCOPED_TRACE("test: " + (*test).label); + + // Set this scenario's configuration parameters + elems->set("calculate-tee-times", data::Element::create((*test).calculate_tee_times)); + elems->set("t1-percent", data::Element::create((*test).t1_percent)); + elems->set("t2-percent", data::Element::create((*test).t2_percent)); + + Subnet6Ptr subnet; + try { + // Attempt to parse the configuration. + Subnet6ConfigParser parser; + subnet = parser.parse(elems); + } catch (const std::exception& ex) { + if (!(*test).error_message.empty()) { + // We expected a failure, did we fail the correct way? + EXPECT_EQ((*test).error_message, ex.what()); + } else { + // Should not have failed. + ADD_FAILURE() << "Scenario should not have failed: " << ex.what(); + } + + // Either way we're done with this scenario. + continue; + } + + // We parsed correctly, make sure the values are right. + EXPECT_EQ((*test).calculate_tee_times, subnet->getCalculateTeeTimes()); + EXPECT_TRUE(util::areDoublesEquivalent((*test).t1_percent, subnet->getT1Percent())) + << "expected:" << (*test).t1_percent << " actual: " << subnet->getT1Percent(); + EXPECT_TRUE(util::areDoublesEquivalent((*test).t2_percent, subnet->getT2Percent())) + << "expected:" << (*test).t2_percent << " actual: " << subnet->getT2Percent(); + } + } +} + } // end of anonymous namespace