]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#226] Added UTs for the new parameter
authorFrancis Dupont <fdupont@isc.org>
Thu, 7 Aug 2025 16:06:37 +0000 (18:06 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 20 Aug 2025 15:39:15 +0000 (17:39 +0200)
src/lib/dhcpsrv/network.cc
src/lib/dhcpsrv/tests/cfg_shared_networks4_unittest.cc
src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc
src/lib/dhcpsrv/tests/network_unittest.cc
src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc

index e49edd27e6babee8ee4cfd0f6d5e3875be4c3a1b..2f6f33358bb9d4c74d00aff69c2b49d5c84acc10 100644 (file)
@@ -276,6 +276,11 @@ Network::toElement() const {
         map->set("allocator", Element::create(allocator_type_));
     }
 
+    if (!adaptive_lease_time_threshold_.unspecified()) {
+        map->set("adaptive-lease-time-threshold",
+                 Element::create(adaptive_lease_time_threshold_));
+    }
+
     return (map);
 }
 
index 1ed822d7a4713da490bcd0a11c43a2343582775b..430cf8db20bd90201c3ebcd69a11305706dc46bc 100644 (file)
@@ -210,6 +210,7 @@ TEST(CfgSharedNetworks4Test, unparse) {
     network1->setHostnameCharReplacement("x");
     network1->setCacheThreshold(.20);
     network1->setOfferLft(77);
+    network1->setAdaptiveLeaseTimeThreshold(.90);
 
     network2->setIface("eth1");
     network2->setT1(Triplet<uint32_t>(100));
@@ -255,6 +256,7 @@ TEST(CfgSharedNetworks4Test, unparse) {
         "    \"cache-max-age\": 50\n"
         "  },\n"
         "  {\n"
+        "    \"adaptive-lease-time-threshold\": .90,\n"
         "    \"calculate-tee-times\": true,\n"
         "    \"ddns-generated-prefix\": \"prefix\",\n"
         "    \"ddns-override-no-update\": true,\n"
index 9227be7f42414201d4609c8c5d362b6cf6eaae06..e185509e4a8cd2dc9c0b83bba13ce6726a58b8e5 100644 (file)
@@ -1087,6 +1087,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
     subnet1->setT1Percent(0.45);
     subnet1->setT2Percent(0.70);
     subnet1->setCacheThreshold(0.20);
+    subnet1->setAdaptiveLeaseTimeThreshold(.90);
 
     subnet2->setIface("lo");
     subnet2->addRelayAddress(IOAddress("10.0.0.1"));
@@ -1146,6 +1147,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
         "    \"4o6-interface\": \"\",\n"
         "    \"4o6-interface-id\": \"\",\n"
         "    \"4o6-subnet\": \"\",\n"
+        "    \"adaptive-lease-time-threshold\": .90,\n"
         "    \"option-data\": [ ],\n"
         "    \"pools\": [ ],\n"
         "    \"user-context\": { \"comment\": \"foo\" }\n"
@@ -1821,6 +1823,10 @@ TEST(CfgSubnets4Test, cacheParamValidation) {
         {"too big", 1.05,
          "subnet configuration failed: cache-threshold:"
          " 1.05 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
+        },
+        {"excluded", 1.0,
+         "subnet configuration failed: cache-threshold:"
+         " 1 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
         }
     };
 
@@ -1849,7 +1855,6 @@ TEST(CfgSubnets4Test, cacheParamValidation) {
         "            \"4o6-subnet\": \"\" \n"
         "        }";
 
-
     data::ElementPtr elems;
     ASSERT_NO_THROW(elems = data::Element::fromJSON(json))
                     << "invalid JSON:" << json << "\n test is broken";
@@ -1887,6 +1892,99 @@ TEST(CfgSubnets4Test, cacheParamValidation) {
     }
 }
 
+// This test verifies the Subnet4 parser's validation logic for
+// adaptive lease time parameter.
+TEST(CfgSubnets4Test, AdaptiveLeaseTimeParamValidation) {
+
+    // Describes a single test scenario.
+    struct Scenario {
+        std::string label;         // label used for logging test failures
+        double threshold;          // value of adaptive-lease-time-threshold
+        std::string error_message; // expected error message is parsing should fail
+    };
+
+    // Test Scenarios.
+    std::vector<Scenario> tests = {
+        {"valid", .25, ""},
+        {"valid", 1.0, ""},
+        {"negative", -.25,
+         "subnet configuration failed: adaptive-lease-time-threshold:"
+         " -0.25 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
+        },
+        {"excluded", 0.,
+         "subnet configuration failed: adaptive-lease-time-threshold:"
+         " 0 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
+        },
+        {"too big", 1.05,
+         "subnet configuration failed: adaptive-lease-time-threshold:"
+         " 1.05 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
+        }
+    };
+
+    // 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"
+        "            \"valid-lifetime\": 300, \n"
+        "            \"match-client-id\": false, \n"
+        "            \"authoritative\": false, \n"
+        "            \"next-server\": \"\", \n"
+        "            \"server-hostname\": \"\", \n"
+        "            \"boot-file-name\": \"\", \n"
+        "            \"client-classes\": [], \n"
+        "            \"evaluate-additional-classes\": [], \n"
+        "            \"reservations-global\": false, \n"
+        "            \"reservations-in-subnet\": true, \n"
+        "            \"reservations-out-of-pool\": false, \n"
+        "            \"4o6-interface\": \"\", \n"
+        "            \"4o6-interface-id\": \"\", \n"
+        "            \"4o6-subnet\": \"\" \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 const& test : tests) {
+        {
+            SCOPED_TRACE("test: " + test.label);
+
+            // Set this scenario's configuration parameters
+            elems->set("adaptive-lease-time-threshold",
+                       data::Element::create(test.threshold));
+
+            Subnet4Ptr subnet;
+            try {
+                // Attempt to parse the configuration.
+                Subnet4ConfigParser 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_TRUE(util::areDoublesEquivalent(test.threshold,
+                                                   subnet->getAdaptiveLeaseTimeThreshold()));
+        }
+    }
+}
+
 // This test verifies that the optional interface check works as expected.
 TEST(CfgSubnets4Test, iface) {
     // Create a configuration.
index fb615d71107d51e5b8e0b5ee6fd044f7446624ef..3445e9f2e1719e736a1884a3affe07b5e99baf2e 100644 (file)
@@ -684,6 +684,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
     subnet1->setT1Percent(0.45);
     subnet1->setT2Percent(0.70);
     subnet1->setCacheThreshold(0.20);
+    subnet1->setAdaptiveLeaseTimeThreshold(.90);
 
     subnet2->setIface("lo");
     subnet2->addRelayAddress(IOAddress("2001:db8:ff::2"));
@@ -740,6 +741,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
         "    \"valid-lifetime\": 4,\n"
         "    \"min-valid-lifetime\": 4,\n"
         "    \"max-valid-lifetime\": 4,\n"
+        "    \"adaptive-lease-time-threshold\": .90,\n"
         "    \"client-classes\": [ \"foo\", \"bar\" ],\n"
         "    \"pools\": [ ],\n"
         "    \"pd-pools\": [ ],\n"
@@ -1610,6 +1612,10 @@ TEST(CfgSubnets6Test, cacheParamValidation) {
         {"too big", 1.05,
          "subnet configuration failed: cache-threshold:"
          " 1.05 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
+        },
+        {"excluded", 1.0,
+         "subnet configuration failed: cache-threshold:"
+         " 1 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
         }
     };
 
@@ -1667,6 +1673,91 @@ TEST(CfgSubnets6Test, cacheParamValidation) {
     }
 }
 
+// This test verifies the Subnet6 parser's validation logic for
+// adaptive lease time parameter.
+TEST(CfgSubnets6Test, AdaptiveLeaseTimeParamValidation) {
+
+    // Describes a single test scenario.
+    struct Scenario {
+        std::string label;         // label used for logging test failures
+        double threshold;          // value of adaptive-lease-time-threshold
+        std::string error_message; // expected error message is parsing should fail
+    };
+
+    // Test Scenarios.
+    std::vector<Scenario> tests = {
+        {"valid", .25, ""},
+        {"valid", 1.0, ""},
+        {"negative", -.25,
+         "subnet configuration failed: adaptive-lease-time-threshold:"
+         " -0.25 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
+        },
+        {"excluded", 0.,
+         "subnet configuration failed: adaptive-lease-time-threshold:"
+         " 0 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
+        },
+        {"too big", 1.05,
+         "subnet configuration failed: adaptive-lease-time-threshold:"
+         " 1.05 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
+        }
+    };
+
+    // 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-classes\": [], \n"
+        "            \"evaluate-additional-classes\": [], \n"
+        "            \"reservations-global\": false, \n"
+        "            \"reservations-in-subnet\": true, \n"
+        "            \"reservations-out-of-pool\": false \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 const& test : tests) {
+        {
+            SCOPED_TRACE("test: " + test.label);
+
+            // Set this scenario's configuration parameters
+            elems->set("adaptive-lease-time-threshold",
+                       data::Element::create(test.threshold));
+
+            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_TRUE(util::areDoublesEquivalent(test.threshold,
+                                                   subnet->getAdaptiveLeaseTimeThreshold()));
+        }
+    }
+}
+
 // This test verifies that the optional interface check works as expected.
 TEST(CfgSubnets6Test, iface) {
     // Create a configuration.
index 6fb4d8a1aad0414fee8a72e0db6fa214ad332a9c..28788f91c09a282b3f21e6b4b00d50118b861d60 100644 (file)
@@ -186,6 +186,7 @@ TEST_F(NetworkTest, inheritanceSupport4) {
     globals_->set("ddns-ttl", Element::create(400));
     globals_->set("ddns-ttl-min", Element::create(200));
     globals_->set("ddns-ttl-max", Element::create(600));
+    globals_->set("adaptive-lease-time-threshold", Element::create(.90));
 
     // For each parameter for which inheritance is supported run
     // the test that checks if the values are inherited properly.
@@ -393,6 +394,12 @@ TEST_F(NetworkTest, inheritanceSupport4) {
                                              &Network::setDdnsTtlMax,
                                              500, 600);
     }
+    {
+        SCOPED_TRACE("adaptive-lease-time-threshold");
+        testNetworkInheritance<TestNetwork4>(&Network::getAdaptiveLeaseTimeThreshold,
+                                             &Network::setAdaptiveLeaseTimeThreshold,
+                                             .80, .90);
+    }
 }
 
 // This test verifies that the inheritance is supported for DHCPv6
@@ -420,6 +427,7 @@ TEST_F(NetworkTest, inheritanceSupport6) {
     globals_->set("ddns-ttl-max", Element::create(600));
     globals_->set("cache-threshold", Element::create(.35));
     globals_->set("cache-max-age", Element::create(20));
+    globals_->set("adaptive-lease-time-threshold", Element::create(.90));
 
     // For each parameter for which inheritance is supported run
     // the test that checks if the values are inherited properly.
@@ -558,6 +566,12 @@ TEST_F(NetworkTest, inheritanceSupport6) {
                                              &Network::setCacheMaxAge,
                                              10, 20);
     }
+    {
+        SCOPED_TRACE("adaptive-lease-time-threshold");
+        testNetworkInheritance<TestNetwork4>(&Network::getAdaptiveLeaseTimeThreshold,
+                                             &Network::setAdaptiveLeaseTimeThreshold,
+                                             .80, .90);
+    }
 
     // Interface-id requires special type of test.
     boost::shared_ptr<TestNetwork6> net_child(new TestNetwork6());
index 5c5b0b5a9b92e351f67e17de0232a782bdb80c12..b6a6ee6a71e1a7feed51e243cd9200ddd01186fa 100644 (file)
@@ -299,6 +299,7 @@ public:
                 "    \"store-extended-info\": true,"
                 "    \"cache-threshold\": 0.123,"
                 "    \"cache-max-age\": 123,"
+                "    \"adaptive-lease-time-threshold\": .90,"
                 "    \"offer-lifetime\": 777,"
                 "    \"ddns-update-on-renew\": true,"
                 "    \"option-data\": ["
@@ -336,7 +337,8 @@ public:
                 "            \"hostname-char-set\": \"\","
                 "            \"cache-threshold\": .20,"
                 "            \"cache-max-age\": 50,"
-                "            \"allocator\": \"random\""
+                "            \"allocator\": \"random\","
+                "            \"adaptive-lease-time-threshold\": .80"
                 "        },"
                 "        {"
                 "            \"id\": 2,"
@@ -362,7 +364,8 @@ public:
                 "            \"t1-percent\": .40,"
                 "            \"t2-percent\": .80,"
                 "            \"cache-threshold\": 0.0,"
-                "            \"cache-max-age\": 0"
+                "            \"cache-max-age\": 0,"
+                "            \"adaptive-lease-time-threshold\": .70"
                 "        }"
                 "    ]"
                 "}";
@@ -432,6 +435,7 @@ TEST_F(SharedNetwork4ParserTest, parse) {
     EXPECT_EQ(777, network->getOfferLft().get());
     EXPECT_TRUE(network->getDdnsUpdateOnRenew().get());
     EXPECT_EQ("iterative", network->getAllocatorType().get());
+    EXPECT_EQ(.90, network->getAdaptiveLeaseTimeThreshold().get());
 
     // Relay information.
     auto relay_info = network->getRelayInfo();
@@ -730,6 +734,7 @@ public:
                 "    \"ddns-update-on-renew\": true,"
                 "    \"allocator\": \"random\","
                 "    \"pd-allocator\": \"iterative\","
+                "    \"adaptive-lease-time-threshold\": .90,"
                 "    \"option-data\": ["
                 "        {"
                 "            \"name\": \"dns-servers\","
@@ -845,6 +850,7 @@ TEST_F(SharedNetwork6ParserTest, parse) {
     EXPECT_TRUE(network->getDdnsUpdateOnRenew().get());
     EXPECT_EQ("random", network->getAllocatorType().get());
     EXPECT_EQ("iterative", network->getPdAllocatorType().get());
+    EXPECT_EQ(.90, network->getAdaptiveLeaseTimeThreshold().get());
 
     // Relay information.
     auto relay_info = network->getRelayInfo();