Commit d8bb7626 authored by Francis Dupont's avatar Francis Dupont
Browse files

[295-min-max-lease-time-configuration-options] Added lifetime parsing unit tests

parent dd99e615
......@@ -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<uint32_t>(100));
network2->setT2(Triplet<uint32_t>(200));
network2->setValid(Triplet<uint32_t>(300));
network2->setValid(Triplet<uint32_t>(200, 300, 400));
network3->setIface("eth2");
network3->setValid(Triplet<uint32_t>(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"
......
......@@ -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<uint32_t>(100));
network2->setT2(Triplet<uint32_t>(200));
network2->setPreferred(Triplet<uint32_t>(200));
network2->setValid(Triplet<uint32_t>(300));
network3->setIface("eth2");
network3->setPreferred(Triplet<uint32_t>(100,200,300));
network3->setValid(Triplet<uint32_t>(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"
......
......@@ -1016,6 +1016,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
subnet2->setIface("lo");
subnet2->addRelayAddress(IOAddress("10.0.0.1"));
subnet2->setValid(Triplet<uint32_t>(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<uint32_t>(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
......@@ -616,6 +616,9 @@ TEST(CfgSubnets6Test, unparseSubnet) {
subnet2->setIface("lo");
subnet2->addRelayAddress(IOAddress("2001:db8:ff::2"));
subnet2->setValid(Triplet<uint32_t>(200));
subnet2->setPreferred(Triplet<uint32_t>(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<uint32_t>(100, 200, 300));
subnet3->setPreferred(Triplet<uint32_t>(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);