From: Francis Dupont Date: Fri, 17 May 2019 15:54:34 +0000 (+0200) Subject: [295-min-max-lease-time-configuration-options] Added lifetime parsing unit tests X-Git-Tag: Kea-1.6.0-beta2~248 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8bb76263b865208a0a0110d30dcbcb0431695c6;p=thirdparty%2Fkea.git [295-min-max-lease-time-configuration-options] Added lifetime parsing unit tests --- diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc index cd4e7ca468..54b28e5af1 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc @@ -191,6 +191,7 @@ TEST(CfgSharedNetworks4Test, duplicateName) { TEST(CfgSharedNetworks4Test, unparse) { SharedNetwork4Ptr network1(new SharedNetwork4("frog")); SharedNetwork4Ptr network2(new SharedNetwork4("dog")); + SharedNetwork4Ptr network3(new SharedNetwork4("cat")); network1->setIface("eth0"); network1->addRelayAddress(IOAddress("198.16.1.1")); network1->addRelayAddress(IOAddress("198.16.1.2")); @@ -201,15 +202,27 @@ TEST(CfgSharedNetworks4Test, unparse) { network2->setIface("eth1"); network2->setT1(Triplet(100)); network2->setT2(Triplet(200)); - network2->setValid(Triplet(300)); + network2->setValid(Triplet(200, 300, 400)); + + network3->setIface("eth2"); + network3->setValid(Triplet(100)); CfgSharedNetworks4 cfg; ASSERT_NO_THROW(cfg.add(network1)); ASSERT_NO_THROW(cfg.add(network2)); + ASSERT_NO_THROW(cfg.add(network3)); std::string expected = "[\n" " {\n" + " \"interface\": \"eth2\",\n" + " \"name\": \"cat\",\n" + " \"option-data\": [ ],\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" + " \"subnet4\": [ ],\n" + " \"valid-lifetime\": 100\n" + " },\n" + " {\n" " \"interface\": \"eth1\",\n" " \"name\": \"dog\",\n" " \"rebind-timer\": 200,\n" @@ -217,7 +230,9 @@ TEST(CfgSharedNetworks4Test, unparse) { " \"renew-timer\": 100,\n" " \"relay\": { \"ip-addresses\": [ ] },\n" " \"subnet4\": [ ],\n" - " \"valid-lifetime\": 300\n" + " \"valid-lifetime\": 300,\n" + " \"min-valid-lifetime\": 200,\n" + " \"max-valid-lifetime\": 400\n" " },\n" " {\n" " \"calculate-tee-times\": true,\n" diff --git a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc index 0f6bd7ce53..6d338083fc 100644 --- a/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_shared_networks6_unittest.cc @@ -192,6 +192,7 @@ TEST(CfgSharedNetworks6Test, duplicateName) { TEST(CfgSharedNetworks6Test, unparse) { SharedNetwork6Ptr network1(new SharedNetwork6("frog")); SharedNetwork6Ptr network2(new SharedNetwork6("dog")); + SharedNetwork6Ptr network3(new SharedNetwork6("cat")); network1->setIface("eth0"); network1->addRelayAddress(IOAddress("2001:db8:1::1")); @@ -203,15 +204,34 @@ TEST(CfgSharedNetworks6Test, unparse) { network2->setIface("eth1"); network2->setT1(Triplet(100)); network2->setT2(Triplet(200)); + network2->setPreferred(Triplet(200)); network2->setValid(Triplet(300)); + network3->setIface("eth2"); + network3->setPreferred(Triplet(100,200,300)); + network3->setValid(Triplet(200,300,400)); + CfgSharedNetworks6 cfg; ASSERT_NO_THROW(cfg.add(network1)); ASSERT_NO_THROW(cfg.add(network2)); + ASSERT_NO_THROW(cfg.add(network3)); std::string expected = "[\n" " {\n" + " \"interface\": \"eth2\",\n" + " \"name\": \"cat\",\n" + " \"option-data\": [ ],\n" + " \"relay\": { \"ip-addresses\": [ ] },\n" + " \"subnet6\": [ ],\n" + " \"preferred-lifetime\": 200,\n" + " \"min-preferred-lifetime\": 100,\n" + " \"max-preferred-lifetime\": 300,\n" + " \"valid-lifetime\": 300,\n" + " \"min-valid-lifetime\": 200,\n" + " \"max-valid-lifetime\": 400\n" + " },\n" + " {\n" " \"interface\": \"eth1\",\n" " \"name\": \"dog\",\n" " \"option-data\": [ ],\n" @@ -219,6 +239,7 @@ TEST(CfgSharedNetworks6Test, unparse) { " \"relay\": { \"ip-addresses\": [ ] },\n" " \"renew-timer\": 100,\n" " \"subnet6\": [ ],\n" + " \"preferred-lifetime\": 200,\n" " \"valid-lifetime\": 300\n" " },\n" " {\n" diff --git a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc index 85ec286e6f..c033f04d07 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc @@ -1016,6 +1016,7 @@ TEST(CfgSubnets4Test, unparseSubnet) { subnet2->setIface("lo"); subnet2->addRelayAddress(IOAddress("10.0.0.1")); + subnet2->setValid(Triplet(100)); subnet3->setIface("eth1"); subnet3->requireClientClass("foo"); @@ -1029,6 +1030,7 @@ TEST(CfgSubnets4Test, unparseSubnet) { subnet3->setSiaddr(IOAddress("192.0.2.2")); subnet3->setSname("frog"); subnet3->setFilename("/dev/null"); + subnet3->setValid(Triplet(100, 200, 300)); data::ElementPtr ctx1 = data::Element::fromJSON("{ \"comment\": \"foo\" }"); subnet1->setContext(ctx1); @@ -1064,7 +1066,7 @@ TEST(CfgSubnets4Test, unparseSubnet) { " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" " \"relay\": { \"ip-addresses\": [ \"10.0.0.1\" ] },\n" - " \"valid-lifetime\": 3,\n" + " \"valid-lifetime\": 100,\n" " \"4o6-interface\": \"\",\n" " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" @@ -1082,7 +1084,9 @@ TEST(CfgSubnets4Test, unparseSubnet) { " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" " \"relay\": { \"ip-addresses\": [ ] },\n" - " \"valid-lifetime\": 3,\n" + " \"valid-lifetime\": 200,\n" + " \"min-valid-lifetime\": 100,\n" + " \"max-valid-lifetime\": 300,\n" " \"4o6-interface\": \"\",\n" " \"4o6-interface-id\": \"\",\n" " \"4o6-subnet\": \"\",\n" @@ -1295,4 +1299,247 @@ TEST(CfgSubnets4Test, teeTimePercentValidation) { } } +// This test verifies the Subnet4 parser's validation logic for +// valid-lifetime and indirectly shared lifetime parsing. +TEST(CfgSubnets4Test, validLifetimeValidation) { + // First we create a set of elements that provides all + // required for a Subnet4. + std::string json = + " {" + " \"id\": 1,\n" + " \"subnet\": \"10.1.2.0/24\", \n" + " \"interface\": \"\", \n" + " \"renew-timer\": 100, \n" + " \"rebind-timer\": 200, \n" + " \"match-client-id\": false, \n" + " \"authoritative\": false, \n" + " \"next-server\": \"\", \n" + " \"server-hostname\": \"\", \n" + " \"boot-file-name\": \"\", \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"; + + { + SCOPED_TRACE("no valid-lifetime"); + + data::ElementPtr copied = data::copy(elems); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_TRUE(subnet->getValid().unspecified()); + data::ConstElementPtr repr = subnet->toElement(); + EXPECT_FALSE(repr->get("valid-lifetime")); + EXPECT_FALSE(repr->get("min-valid-lifetime")); + EXPECT_FALSE(repr->get("max-valid-lifetime")); + } + + { + SCOPED_TRACE("valid-lifetime only"); + + data::ElementPtr copied = data::copy(elems); + copied->set("valid-lifetime", data::Element::create(100)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(100, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(100, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + EXPECT_FALSE(repr->get("min-valid-lifetime")); + EXPECT_FALSE(repr->get("max-valid-lifetime")); + } + + { + SCOPED_TRACE("min-valid-lifetime only"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(100)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(100, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(100, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + // Bound only: forgot it was a bound. + EXPECT_FALSE(repr->get("min-valid-lifetime")); + EXPECT_FALSE(repr->get("max-valid-lifetime")); + } + + { + SCOPED_TRACE("max-valid-lifetime only"); + data::ElementPtr copied = data::copy(elems); + copied->set("max-valid-lifetime", data::Element::create(100)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(100, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(100, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + // Bound only: forgot it was a bound. + EXPECT_FALSE(repr->get("min-valid-lifetime")); + EXPECT_FALSE(repr->get("max-valid-lifetime")); + } + + { + SCOPED_TRACE("min-valid-lifetime and valid-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(100)); + // Use a different (and greater) value for the default. + copied->set("valid-lifetime", data::Element::create(200)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(200, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(200, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("200", value->str()); + data::ConstElementPtr min_value = repr->get("min-valid-lifetime"); + ASSERT_TRUE(min_value); + EXPECT_EQ("100", min_value->str()); + EXPECT_FALSE(repr->get("max-valid-lifetime")); + } + + { + SCOPED_TRACE("max-valid-lifetime and valid-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("max-valid-lifetime", data::Element::create(200)); + // Use a different (and smaller) value for the default. + copied->set("valid-lifetime", data::Element::create(100)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(100, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(200, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + data::ConstElementPtr max_value = repr->get("max-valid-lifetime"); + ASSERT_TRUE(max_value); + EXPECT_EQ("200", max_value->str()); + EXPECT_FALSE(repr->get("min-valid-lifetime")); + } + + { + SCOPED_TRACE("min-valid-lifetime and max-valid-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(100)); + copied->set("max-valid-lifetime", data::Element::create(200)); + Subnet4ConfigParser parser; + // No idea about the value to use for the default so failing. + ASSERT_THROW(parser.parse(copied), DhcpConfigError); + } + + { + SCOPED_TRACE("all 3 (min, max and default) valid-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(100)); + // Use a different (and greater) value for the default. + copied->set("valid-lifetime", data::Element::create(200)); + // Use a different (and greater than both) value for max. + copied->set("max-valid-lifetime", data::Element::create(300)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(200, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(300, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("200", value->str()); + data::ConstElementPtr min_value = repr->get("min-valid-lifetime"); + ASSERT_TRUE(min_value); + EXPECT_EQ("100", min_value->str()); + data::ConstElementPtr max_value = repr->get("max-valid-lifetime"); + ASSERT_TRUE(max_value); + EXPECT_EQ("300", max_value->str()); + } + + { + SCOPED_TRACE("default value too small"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(200)); + // 100 < 200 so it will fail. + copied->set("valid-lifetime", data::Element::create(100)); + // Use a different (and greater than both) value for max. + copied->set("max-valid-lifetime", data::Element::create(300)); + Subnet4ConfigParser parser; + ASSERT_THROW(parser.parse(copied), DhcpConfigError); + } + + { + SCOPED_TRACE("default value too large"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(100)); + // Use a different (and greater) value for the default. + copied->set("valid-lifetime", data::Element::create(300)); + // 300 > 200 so it will fail. + copied->set("max-valid-lifetime", data::Element::create(200)); + Subnet4ConfigParser parser; + ASSERT_THROW(parser.parse(copied), DhcpConfigError); + } + + { + SCOPED_TRACE("equal bounds are ignored"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-valid-lifetime", data::Element::create(100)); + copied->set("valid-lifetime", data::Element::create(100)); + copied->set("max-valid-lifetime", data::Element::create(100)); + Subnet4Ptr subnet; + Subnet4ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getValid().unspecified()); + EXPECT_EQ(100, subnet->getValid()); + EXPECT_EQ(100, subnet->getValid().getMin()); + EXPECT_EQ(100, subnet->getValid().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("valid-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + EXPECT_FALSE(repr->get("min-valid-lifetime")); + EXPECT_FALSE(repr->get("max-valid-lifetime")); + } +} + } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc index c37a79f899..a0b5c8f302 100644 --- a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc @@ -616,6 +616,9 @@ TEST(CfgSubnets6Test, unparseSubnet) { subnet2->setIface("lo"); subnet2->addRelayAddress(IOAddress("2001:db8:ff::2")); + subnet2->setValid(Triplet(200)); + subnet2->setPreferred(Triplet(100)); + subnet3->setIface("eth1"); subnet3->requireClientClass("foo"); subnet3->requireClientClass("bar"); @@ -624,6 +627,8 @@ TEST(CfgSubnets6Test, unparseSubnet) { subnet3->setCalculateTeeTimes(true); subnet3->setT1Percent(0.50); subnet3->setT2Percent(0.65); + subnet3->setValid(Triplet(100, 200, 300)); + subnet3->setPreferred(Triplet(50, 100, 150)); data::ElementPtr ctx1 = data::Element::fromJSON("{ \"comment\": \"foo\" }"); subnet1->setContext(ctx1); @@ -659,8 +664,8 @@ TEST(CfgSubnets6Test, unparseSubnet) { " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" " \"relay\": { \"ip-addresses\": [ \"2001:db8:ff::2\" ] },\n" - " \"preferred-lifetime\": 3,\n" - " \"valid-lifetime\": 4,\n" + " \"preferred-lifetime\": 100,\n" + " \"valid-lifetime\": 200,\n" " \"user-context\": { },\n" " \"pools\": [ ],\n" " \"pd-pools\": [ ],\n" @@ -672,8 +677,12 @@ TEST(CfgSubnets6Test, unparseSubnet) { " \"renew-timer\": 1,\n" " \"rebind-timer\": 2,\n" " \"relay\": { \"ip-addresses\": [ ] },\n" - " \"preferred-lifetime\": 3,\n" - " \"valid-lifetime\": 4,\n" + " \"preferred-lifetime\": 100,\n" + " \"min-preferred-lifetime\": 50,\n" + " \"max-preferred-lifetime\": 150,\n" + " \"valid-lifetime\": 200,\n" + " \"min-valid-lifetime\": 100,\n" + " \"max-valid-lifetime\": 300,\n" " \"rapid-commit\": false,\n" " \"reservation-mode\": \"all\",\n" " \"pools\": [ ],\n" @@ -1087,4 +1096,244 @@ TEST(CfgSubnets6Test, teeTimePercentValidation) { } } +// This test verifies the Subnet6 parser's validation logic for +// preferred-lifetime and indirectly shared lifetime parsing. +// Note the valid-lifetime stuff is similar and already done for Subnet4. +TEST(CfgSubnets6Test, preferredLifetimeValidation) { + // 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"; + + { + SCOPED_TRACE("no preferred-lifetime"); + + data::ElementPtr copied = data::copy(elems); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_TRUE(subnet->getPreferred().unspecified()); + data::ConstElementPtr repr = subnet->toElement(); + EXPECT_FALSE(repr->get("preferred-lifetime")); + EXPECT_FALSE(repr->get("min-preferred-lifetime")); + EXPECT_FALSE(repr->get("max-preferred-lifetime")); + } + + { + SCOPED_TRACE("preferred-lifetime only"); + + data::ElementPtr copied = data::copy(elems); + copied->set("preferred-lifetime", data::Element::create(100)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(100, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(100, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + EXPECT_FALSE(repr->get("min-preferred-lifetime")); + EXPECT_FALSE(repr->get("max-preferred-lifetime")); + } + + { + SCOPED_TRACE("min-preferred-lifetime only"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(100)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(100, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(100, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + // Bound only: forgot it was a bound. + EXPECT_FALSE(repr->get("min-preferred-lifetime")); + EXPECT_FALSE(repr->get("max-preferred-lifetime")); + } + + { + SCOPED_TRACE("max-preferred-lifetime only"); + data::ElementPtr copied = data::copy(elems); + copied->set("max-preferred-lifetime", data::Element::create(100)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(100, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(100, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + // Bound only: forgot it was a bound. + EXPECT_FALSE(repr->get("min-preferred-lifetime")); + EXPECT_FALSE(repr->get("max-preferred-lifetime")); + } + + { + SCOPED_TRACE("min-preferred-lifetime and preferred-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(100)); + // Use a different (and greater) value for the default. + copied->set("preferred-lifetime", data::Element::create(200)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(200, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(200, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("200", value->str()); + data::ConstElementPtr min_value = repr->get("min-preferred-lifetime"); + ASSERT_TRUE(min_value); + EXPECT_EQ("100", min_value->str()); + EXPECT_FALSE(repr->get("max-preferred-lifetime")); + } + + { + SCOPED_TRACE("max-preferred-lifetime and preferred-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("max-preferred-lifetime", data::Element::create(200)); + // Use a different (and smaller) value for the default. + copied->set("preferred-lifetime", data::Element::create(100)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(100, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(200, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + data::ConstElementPtr max_value = repr->get("max-preferred-lifetime"); + ASSERT_TRUE(max_value); + EXPECT_EQ("200", max_value->str()); + EXPECT_FALSE(repr->get("min-preferred-lifetime")); + } + + { + SCOPED_TRACE("min-preferred-lifetime and max-preferred-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(100)); + copied->set("max-preferred-lifetime", data::Element::create(200)); + Subnet6ConfigParser parser; + // No idea about the value to use for the default so failing. + ASSERT_THROW(parser.parse(copied), DhcpConfigError); + } + + { + SCOPED_TRACE("all 3 (min, max and default) preferred-lifetime"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(100)); + // Use a different (and greater) value for the default. + copied->set("preferred-lifetime", data::Element::create(200)); + // Use a different (and greater than both) value for max. + copied->set("max-preferred-lifetime", data::Element::create(300)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(200, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(300, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("200", value->str()); + data::ConstElementPtr min_value = repr->get("min-preferred-lifetime"); + ASSERT_TRUE(min_value); + EXPECT_EQ("100", min_value->str()); + data::ConstElementPtr max_value = repr->get("max-preferred-lifetime"); + ASSERT_TRUE(max_value); + EXPECT_EQ("300", max_value->str()); + } + + { + SCOPED_TRACE("default value too small"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(200)); + // 100 < 200 so it will fail. + copied->set("preferred-lifetime", data::Element::create(100)); + // Use a different (and greater than both) value for max. + copied->set("max-preferred-lifetime", data::Element::create(300)); + Subnet6ConfigParser parser; + ASSERT_THROW(parser.parse(copied), DhcpConfigError); + } + + { + SCOPED_TRACE("default value too large"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(100)); + // Use a different (and greater) value for the default. + copied->set("preferred-lifetime", data::Element::create(300)); + // 300 > 200 so it will fail. + copied->set("max-preferred-lifetime", data::Element::create(200)); + Subnet6ConfigParser parser; + ASSERT_THROW(parser.parse(copied), DhcpConfigError); + } + + { + SCOPED_TRACE("equal bounds are ignored"); + data::ElementPtr copied = data::copy(elems); + copied->set("min-preferred-lifetime", data::Element::create(100)); + copied->set("preferred-lifetime", data::Element::create(100)); + copied->set("max-preferred-lifetime", data::Element::create(100)); + Subnet6Ptr subnet; + Subnet6ConfigParser parser; + ASSERT_NO_THROW(subnet = parser.parse(copied)); + ASSERT_TRUE(subnet); + EXPECT_FALSE(subnet->getPreferred().unspecified()); + EXPECT_EQ(100, subnet->getPreferred()); + EXPECT_EQ(100, subnet->getPreferred().getMin()); + EXPECT_EQ(100, subnet->getPreferred().getMax()); + data::ConstElementPtr repr = subnet->toElement(); + data::ConstElementPtr value = repr->get("preferred-lifetime"); + ASSERT_TRUE(value); + EXPECT_EQ("100", value->str()); + EXPECT_FALSE(repr->get("min-preferred-lifetime")); + EXPECT_FALSE(repr->get("max-preferred-lifetime")); + } +} + } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc b/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc index 9c007727ad..82744d88fc 100644 --- a/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc @@ -130,6 +130,8 @@ public: " \"require-client-classes\": [ \"runner\" ]," " \"user-context\": { \"comment\": \"example\" }," " \"valid-lifetime\": 399," + " \"min-valid-lifetime\": 299," + " \"max-valid-lifetime\": 499," " \"calculate-tee-times\": true," " \"t1-percent\": 0.345," " \"t2-percent\": 0.721," @@ -147,6 +149,8 @@ public: " \"renew-timer\": 100," " \"rebind-timer\": 200," " \"valid-lifetime\": 300," + " \"min-valid-lifetime\": 200," + " \"max-valid-lifetime\": 400," " \"match-client-id\": false," " \"authoritative\": false," " \"next-server\": \"\"," @@ -237,6 +241,8 @@ TEST_F(SharedNetwork4ParserTest, parse) { EXPECT_EQ(99, network->getT1()); EXPECT_EQ(199, network->getT2()); EXPECT_EQ(399, network->getValid()); + EXPECT_EQ(299, network->getValid().getMin()); + EXPECT_EQ(499, network->getValid().getMax()); EXPECT_TRUE(network->getCalculateTeeTimes()); EXPECT_EQ(0.345, network->getT1Percent()); EXPECT_EQ(0.721, network->getT2Percent()); @@ -264,11 +270,17 @@ TEST_F(SharedNetwork4ParserTest, parse) { Subnet4Ptr subnet1 = network->getSubnet(SubnetID(1)); ASSERT_TRUE(subnet1); EXPECT_EQ("10.1.2.0", subnet1->get().first.toText()); + EXPECT_EQ(300, subnet1->getValid()); + EXPECT_EQ(200, subnet1->getValid().getMin()); + EXPECT_EQ(400, subnet1->getValid().getMax()); // Subnet with id 2 Subnet4Ptr subnet2 = network->getSubnet(SubnetID(2)); ASSERT_TRUE(subnet2); EXPECT_EQ("192.0.2.0", subnet2->get().first.toText()); + EXPECT_EQ(30, subnet2->getValid()); + EXPECT_EQ(30, subnet2->getValid().getMin()); + EXPECT_EQ(30, subnet2->getValid().getMax()); // DHCP options ConstCfgOptionPtr cfg_option = network->getCfgOption(); @@ -422,6 +434,8 @@ public: "\"eth1\"," " \"name\": \"bird\"," " \"preferred-lifetime\": 211," + " \"min-preferred-lifetime\": 111," + " \"max-preferred-lifetime\": 311," " \"rapid-commit\": true," " \"rebind-timer\": 199," " \"relay\": { \"ip-addresses\": [ \"2001:db8:1::1\" ] }," @@ -430,6 +444,8 @@ public: " \"reservation-mode\": \"out-of-pool\"," " \"user-context\": { }," " \"valid-lifetime\": 399," + " \"min-valid-lifetime\": 299," + " \"max-valid-lifetime\": 499," " \"calculate-tee-times\": true," " \"t1-percent\": 0.345," " \"t2-percent\": 0.721," @@ -448,7 +464,11 @@ public: " \"renew-timer\": 100," " \"rebind-timer\": 200," " \"preferred-lifetime\": 300," + " \"min-preferred-lifetime\": 200," + " \"max-preferred-lifetime\": 400," " \"valid-lifetime\": 400," + " \"min-valid-lifetime\": 300," + " \"max-valid-lifetime\": 500," " \"client-class\": \"\"," " \"require-client-classes\": []\n," " \"reservation-mode\": \"all\"," @@ -514,10 +534,14 @@ TEST_F(SharedNetwork6ParserTest, parse) { EXPECT_EQ("bird", network->getName()); EXPECT_EQ("eth1", network->getIface().get()); EXPECT_EQ(211, network->getPreferred()); + EXPECT_EQ(111, network->getPreferred().getMin()); + EXPECT_EQ(311, network->getPreferred().getMax()); EXPECT_TRUE(network->getRapidCommit()); EXPECT_EQ(99, network->getT1()); EXPECT_EQ(199, network->getT2()); EXPECT_EQ(399, network->getValid()); + EXPECT_EQ(299, network->getValid().getMin()); + EXPECT_EQ(499, network->getValid().getMax()); EXPECT_TRUE(network->getCalculateTeeTimes()); EXPECT_EQ(0.345, network->getT1Percent()); EXPECT_EQ(0.721, network->getT2Percent()); @@ -541,11 +565,23 @@ TEST_F(SharedNetwork6ParserTest, parse) { Subnet6Ptr subnet1 = network->getSubnet(SubnetID(1)); ASSERT_TRUE(subnet1); EXPECT_EQ("3000::", subnet1->get().first.toText()); + EXPECT_EQ(300, subnet1->getPreferred()); + EXPECT_EQ(200, subnet1->getPreferred().getMin()); + EXPECT_EQ(400, subnet1->getPreferred().getMax()); + EXPECT_EQ(400, subnet1->getValid()); + EXPECT_EQ(300, subnet1->getValid().getMin()); + EXPECT_EQ(500, subnet1->getValid().getMax()); // Subnet with id 2 Subnet6Ptr subnet2 = network->getSubnet(SubnetID(2)); ASSERT_TRUE(subnet2); EXPECT_EQ("2001:db8:1::", subnet2->get().first.toText()); + EXPECT_EQ(30, subnet2->getPreferred()); + EXPECT_EQ(30, subnet2->getPreferred().getMin()); + EXPECT_EQ(30, subnet2->getPreferred().getMax()); + EXPECT_EQ(40, subnet2->getValid()); + EXPECT_EQ(40, subnet2->getValid().getMin()); + EXPECT_EQ(40, subnet2->getValid().getMax()); // DHCP options ConstCfgOptionPtr cfg_option = network->getCfgOption();