]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1387] Added unit tests
authorFrancis Dupont <fdupont@isc.org>
Tue, 2 Jul 2024 16:14:40 +0000 (18:14 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 4 Sep 2024 13:09:40 +0000 (15:09 +0200)
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h
src/lib/dhcpsrv/testutils/host_data_source_utils.cc
src/lib/dhcpsrv/testutils/host_data_source_utils.h

index 2076a5cdf714c7a1f936c2459f07130d46691409..1e71a9bb7aee6a3b5009efc2fab2c2c8f46c8533 100644 (file)
@@ -88,6 +88,7 @@ public:
     void testAdd6Invalid2Hosts();
     void testAllowAddress6AlreadyReserved();
     void testAllowPrefix6AlreadyReserved();
+    void testPrefixExclude();
     void testDuplicatesSubnet4HWAddr();
     void testDuplicatesSubnet4DUID();
     void testDuplicatesSubnet6HWAddr();
@@ -1733,6 +1734,31 @@ TEST_F(CfgHostsTest, unusedSubnetIDs) {
                                           IOAddress("10.0.0.1")))),
                  isc::BadValue);
 }
+// Test insert and retrieve a v6 host with prefix exclude option.
+TEST_F(CfgHostsTest, prefixExclude) {
+    CfgHosts cfg;
+
+    // Create a host reservation.
+    HostPtr host = HostPtr(new Host(duids_[0]->toText(), "duid",
+                                    SUBNET_ID_UNUSED, SubnetID(1),
+                                    IOAddress("0.0.0.0")));
+    IPv6Resrv resv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 48);
+    resv.setPDExclude(IOAddress("2001:db8:0:1::"), 64);
+    host->addReservation(resv);
+    SubnetID subnet = host->getIPv6SubnetID();
+
+    // Try to add it to the host config.
+    ASSERT_NO_THROW(cfg.add(host));
+
+    // Retrieve it.
+    ConstHostPtr from_cfg = cfg.get6(subnet, Host::IDENT_DUID,
+                                     &host->getIdentifier()[0],
+                                     host->getIdentifier().size());
+    ASSERT_TRUE(from_cfg);
+
+    // Compare host and from_cfg.
+    EXPECT_EQ(host->toText(), from_cfg->toText());
+}
 
 // This test verifies that it is not possible to add the same Host to the
 // same IPv4 subnet twice.
index 830a4dd96acf9c687db9743c789d4272fe88908b..01a3266ee165a0d5bcb1880cb01510673e6c32f0 100644 (file)
@@ -826,6 +826,11 @@ TEST_F(MySqlHostDataSourceTest, usercontextMultiThreading) {
     testUserContext(Element::fromJSON(comment));
 }
 
+/// @brief Test insert and retrieve a v6 host with prefix exclude option.
+TEST_F(MySqlHostDataSourceTest, prefixExclude) {
+    testPrefixExclude("2001:db8::", "2001:db8:0:1::");
+}
+
 /// @brief Test verifies if the hardware or client-id query can match hardware address.
 TEST_F(MySqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
     /// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
index 1f136cffb6046e01281c01890b294948dff8a6df..df2fb093d5456075505c3f17acdba5b6599c4edb 100644 (file)
@@ -794,6 +794,11 @@ TEST_F(PgSqlHostDataSourceTest, usercontextMultiThreading) {
     testUserContext(Element::fromJSON(comment));
 }
 
+/// @brief Test insert and retrieve a v6 host with prefix exclude option.
+TEST_F(PgSqlHostDataSourceTest, prefixExclude) {
+    testPrefixExclude("2001:db8::", "2001:db8:0:1::");
+}
+
 /// @brief Test verifies if the hardware or client-id query can match hardware address.
 TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
     /// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
index 8fce65f21646d8a153c9aab3083da314b818b330..361b3fb9f3f037f77f250219551a352ebfe15ecc 100644 (file)
@@ -1503,6 +1503,47 @@ GenericHostDataSourceTest::testUserContext(ConstElementPtr user_context) {
     HostDataSourceUtils::compareHosts(host, from_hds);
 }
 
+void
+GenericHostDataSourceTest::testPrefixExclude(std::string prefix,
+                                             std::string exclude) {
+
+    // Make sure we have a pointer to the host data source.
+    ASSERT_TRUE(hdsptr_);
+
+    // Create a host reservation.
+    HostPtr host = HostDataSourceUtils::initializeHost6(prefix,
+                                                        exclude,
+                                                        Host::IDENT_DUID,
+                                                        false);
+    ASSERT_TRUE(host);
+    auto const& resvs = host->getIPv6Reservations(IPv6Resrv::TYPE_PD);
+    ASSERT_EQ(1, std::distance(resvs.first, resvs.second));
+    EXPECT_TRUE(resvs.first->second.getPDExclude());
+    SubnetID subnet = host->getIPv6SubnetID();
+
+    // Try to add it to the host data source.
+    ASSERT_NO_THROW(hdsptr_->add(host));
+
+    // Retrieve it.
+    ConstHostPtr from_hds = hdsptr_->get6(subnet, Host::IDENT_DUID,
+                                          &host->getIdentifier()[0],
+                                          host->getIdentifier().size());
+    ASSERT_TRUE(from_hds);
+
+    HostDataSourceUtils::compareHosts(host, from_hds);
+
+#if 0
+    // Verify the test is meaningful.
+    HostPtr host2 = HostDataSourceUtils::initializeHost6(prefix,
+                                                         "2001:db8:0:2::",
+                                                         Host::IDENT_DUID,
+                                                         false);
+    host2->setIPv4SubnetID(host->getIPv4SubnetID());
+    host2->setIPv6SubnetID(host->getIPv6SubnetID());
+    ASSERT_TRUE(host2);
+    HostDataSourceUtils::compareHosts(host, host2);
+#endif
+}
 void
 GenericHostDataSourceTest::testMultipleSubnets(int subnets,
                                                const Host::IdentifierType& id) {
index 944daa602d7faef5b601b0a7f50b47d8496688fd..29c68e23f52369c36a55689b86786c9d4e048587 100644 (file)
@@ -328,6 +328,14 @@ public:
     /// @param user_context The user context.
     void testUserContext(isc::data::ConstElementPtr user_context);
 
+    /// @brief Test insert and retrieve a v6 host with prefix exclude option.
+    ///
+    /// Uses gtest macros to report failures.
+    ///
+    /// @param prefix Prefix to reserve (/48).
+    /// @param exclude Prefix to exclude (/64).
+    void testPrefixExclude(std::string prefix, std::string exclude);
+
     /// @brief Test inserts multiple reservations for the same host for different
     /// subnets and check that they can be retrieved properly.
     ///
@@ -485,6 +493,7 @@ public:
     /// @param n_of_hosts number of hosts to insert into and retrieve from the
     ///     database
     void stressTest(uint32_t n_of_hosts);
+
     /// @brief Tests that delete(subnet-id, addr4) call works.
     ///
     /// Uses gtest macros to report failures.
index cfcc0555be9f13cd0b2f03805fe24876265b2527..6a012847911e67731681cce16f43152b3fa36b25 100644 (file)
@@ -126,6 +126,46 @@ HostDataSourceUtils::initializeHost6(std::string address,
     return (host);
 }
 
+HostPtr
+HostDataSourceUtils::initializeHost6(std::string prefix,
+                                     std::string exclude,
+                                     Host::IdentifierType identifier,
+                                     bool new_identifier,
+                                     const std::string auth_key) {
+    std::vector<uint8_t> ident;
+    switch (identifier) {
+    case Host::IDENT_HWADDR:
+        ident = generateHWAddr(new_identifier);
+        break;
+    case Host::IDENT_DUID:
+        ident = generateIdentifier(new_identifier);
+        break;
+    default:
+        ADD_FAILURE() << "Unknown IdType: " << identifier;
+        return HostPtr();
+    }
+
+    // Let's create ever increasing subnet-ids. Let's keep those different,
+    // so subnet4 != subnet6. Useful for catching cases if the code confuses
+    // subnet4 with subnet6.
+    static SubnetID subnet4 = 0;
+    static SubnetID subnet6 = 100;
+    ++subnet4;
+    ++subnet6;
+
+    HostPtr host(new Host(&ident[0], ident.size(), identifier, subnet4, subnet6,
+                          IOAddress("0.0.0.0")));
+
+    host->setKey(AuthKey(auth_key));
+
+    // Create IPv6 reservation for a /48 prefix
+    IPv6Resrv resv(IPv6Resrv::TYPE_PD, IOAddress(prefix), 48);
+    resv.setPDExclude(IOAddress(exclude), 64);
+    host->addReservation(resv);
+
+    return (host);
+}
+
 bool
 HostDataSourceUtils::reservationExists(const IPv6Resrv& resrv,
                                        const IPv6ResrvRange& range) {
@@ -277,37 +317,55 @@ HostDataSourceUtils::compareReservations6(IPv6ResrvRange resrv1,
         for (; r2 != resrv2.second; ++r2) {
             // IPv6Resrv object implements equality operator.
             if (r1->second == r2->second) {
-                break;
+                // but this operator does not check Prefix Exclude options.
+                auto const& p1 = r1->second.getPDExclude();
+                auto const& p2 = r2->second.getPDExclude();
+                if (!p1 && !p2) {
+                    break;
+                } else if (p1 && p2 &&
+                           (p1->getExcludedPrefixLength() ==
+                            p2->getExcludedPrefixLength()) &&
+                           (p1->getExcludedPrefixSubnetID() ==
+                            p2->getExcludedPrefixSubnetID())) {
+                    break;
+                }
             }
         }
         // If r2 iterator reached the end of the range it means that there
         // is no match.
         if (r2 == resrv2.second) {
             ADD_FAILURE() << "No match found for reservation: "
-                          << resrv1.first->second.getPrefix().toText();
+                          << r1->second.getPrefix().toText();
+            return;
         }
     }
-
-    if (std::distance(resrv1.first, resrv1.second) > 0) {
-        for (; resrv1.first != resrv1.second; resrv1.first++) {
-            IPv6ResrvIterator iter = resrv2.first;
-            while (iter != resrv2.second) {
-                if ((resrv1.first->second.getType() ==
-                     iter->second.getType()) &&
-                    (resrv1.first->second.getPrefixLen() ==
-                     iter->second.getPrefixLen()) &&
-                    (resrv1.first->second.getPrefix() ==
-                     iter->second.getPrefix())) {
+    // Same with 1 and 2 swapped role.
+    for (IPv6ResrvIterator r2 = resrv2.first; r2 != resrv2.second; ++r2) {
+        IPv6ResrvIterator r1 = resrv1.first;
+        for (; r1 != resrv1.second; ++r1) {
+            // IPv6Resrv object implements equality operator.
+            if (r1->second == r2->second) {
+                // but this operator does not check Prefix Exclude options.
+                auto const& p1 = r1->second.getPDExclude();
+                auto const& p2 = r2->second.getPDExclude();
+                if (!p1 && !p1) {
+                    break;
+                } else if (p1 && p2 &&
+                           (p1->getExcludedPrefixLength() ==
+                            p2->getExcludedPrefixLength()) &&
+                           (p1->getExcludedPrefixSubnetID() ==
+                            p2->getExcludedPrefixSubnetID())) {
                     break;
-                }
-                iter++;
-                if (iter == resrv2.second) {
-                    ADD_FAILURE() << "Reservation comparison failed, "
-                                     "no match for reservation: "
-                                  << resrv1.first->second.getPrefix().toText();
                 }
             }
         }
+        // If r1 iterator reached the end of the range it means that there
+        // is no match.
+        if (r1 == resrv1.second) {
+            ADD_FAILURE() << "No match found for reservation: "
+                          << r2->second.getPrefix().toText();
+            return;
+        }
     }
 }
 
@@ -405,4 +463,3 @@ HostDataSourceUtils::compareOptions(const ConstCfgOptionPtr& cfg1,
 }
 }
 }
-
index ac96f110443fb5f4cf84876f8ed11724a554d9cd..60ebe31d70badd029a60796545cc85ebc91c71d7 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2024 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
@@ -45,6 +45,22 @@ public:
                                    bool prefix, bool new_identifier = true,
                                    const std::string key = "");
 
+    /// @brief Creates a host reservation for specified IPv6 prefix and
+    /// excluded prefix.
+    ///
+    /// @param prefix IPv6 prefix to be reserved
+    /// @param exclude IPv6 prefix to be excluded
+    /// @param id type of identifier (IDENT_DUID or IDENT_HWADDR are supported)
+    /// @param new_identifier Boolean value indicating if new host
+    /// identifier should be generated or the same as previously.
+    ///
+    /// @return generated Host object
+    static HostPtr initializeHost6(std::string prefix,
+                                   std::string exclude,
+                                   Host::IdentifierType id,
+                                   bool new_identifier = true,
+                                   const std::string key = "");
+
     /// @brief Generates a hardware address in text version.
     ///
     /// @param increase A boolean value indicating if new address (increased)
@@ -130,5 +146,4 @@ public:
 }
 }
 }
-
 #endif