]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4094] Added last UTs
authorFrancis Dupont <fdupont@isc.org>
Fri, 12 Sep 2025 13:48:13 +0000 (15:48 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 15 Sep 2025 19:44:28 +0000 (21:44 +0200)
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/http_control_socket_unittest.cc
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/http_control_socket_unittest.cc
src/lib/dhcpsrv/lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

index 493611ac729bd8716fa7ba95328284cae3722ae7..2f6b161450a5051321b8ee46d07016be4647e1fd 100644 (file)
@@ -3581,8 +3581,8 @@ TEST_F(CtrlChannelDhcpv4SrvTest, keaLfcStartPersistFalse) {
 
     sendUnixCommand("{ \"command\" : \"kea-lfc-start\" }", response);
     std::string expected = "{ \"result\": 2, \"text\": ";
-    expected += "\"'persist` parameter of `memfile` lease backend ";
-    expected += "was configured to `false`\" }";
+    expected += "\"'persist' parameter of 'memfile' lease backend ";
+    expected += "was configured to 'false'\" }";
     EXPECT_EQ(expected, response);
 }
 
index 1197d6ca8027c56e4104a963a5287637000b2208..c3132ded537b59c9494a36ad47f9a811475528a7 100644 (file)
@@ -3533,8 +3533,8 @@ BaseCtrlChannelDhcpv4Test::testKeaLfcStartPersistFalse() {
 
     sendHttpCommand("{ \"command\" : \"kea-lfc-start\" }", response);
     std::string expected = "[ { \"result\": 2, \"text\": ";
-    expected += "\"'persist` parameter of `memfile` lease backend ";
-    expected += "was configured to `false`\" } ]";
+    expected += "\"'persist' parameter of 'memfile' lease backend ";
+    expected += "was configured to 'false'\" } ]";
     EXPECT_EQ(expected, response);
 }
 
index c3a993b43d7c5de98823ccb54bd1a077cef4f031..e4e9ffa99b3801c9514ba83e2dbd173133dbe324 100644 (file)
@@ -2868,8 +2868,8 @@ TEST_F(CtrlChannelDhcpv6SrvTest, keaLfcStartPersistFalse) {
 
     sendUnixCommand("{ \"command\" : \"kea-lfc-start\" }", response);
     std::string expected = "{ \"result\": 2, \"text\": ";
-    expected += "\"'persist` parameter of `memfile` lease backend ";
-    expected += "was configured to `false`\" }";
+    expected += "\"'persist' parameter of 'memfile' lease backend ";
+    expected += "was configured to 'false'\" }";
     EXPECT_EQ(expected, response);
 }
 
index 269a1ecc7ece264bdbc09a31baba118e2323fdb4..37287937a559b3af437710735cafca87ff137d25 100644 (file)
@@ -3529,8 +3529,8 @@ BaseCtrlChannelDhcpv6Test::testKeaLfcStartPersistFalse() {
 
     sendHttpCommand("{ \"command\" : \"kea-lfc-start\" }", response);
     std::string expected = "[ { \"result\": 2, \"text\": ";
-    expected += "\"'persist` parameter of `memfile` lease backend ";
-    expected += "was configured to `false`\" } ]";
+    expected += "\"'persist' parameter of 'memfile' lease backend ";
+    expected += "was configured to 'false'\" } ]";
     EXPECT_EQ(expected, response);
 }
 
index 9994cd1f611e4fde840abe49af2755f235a83c09..958510e45ae35be6f6772bcce53b8fe7aa8fbb74 100644 (file)
@@ -1309,7 +1309,7 @@ LeaseMgr::byRemoteId6size() const {
 ConstElementPtr
 LeaseMgr::lfcStartHandler() {
     ostringstream msg;
-    msg << "lease backend `" << getName() << "' is not 'memfile'";
+    msg << "lease backend '" << getName() << "' is not 'memfile'";
     return (createAnswer(CONTROL_RESULT_COMMAND_UNSUPPORTED, msg.str()));
 }
 
index 92d804d492f517b00137b15bad351700e1c9b336..3ba5ea47fa926adb1c5d0a5e516ceea0443f6ab0 100644 (file)
@@ -164,11 +164,6 @@ LFCSetup::setup(const uint32_t lfc_interval,
                 const boost::shared_ptr<CSVLeaseFile6>& lease_file6,
                 bool run_once_now) {
 
-    // If to nothing to do, punt
-    if (lfc_interval == 0 && !run_once_now) {
-        return;
-    }
-
     // Start preparing the command line for kea-lfc.
     std::string executable;
     char* c_executable = getenv(KEA_LFC_EXECUTABLE_ENV_NAME);
@@ -2565,8 +2560,8 @@ ConstElementPtr
 Memfile_LeaseMgr::lfcStartHandler() {
     if (!persistLeases(V4) && !persistLeases(V6)) {
         std::ostringstream msg;
-        msg << "'persist` parameter of `memfile` lease backend "
-            << "was configured to `false`";
+        msg << "'persist' parameter of 'memfile' lease backend "
+            << "was configured to 'false'";
         return (createAnswer(CONTROL_RESULT_COMMAND_UNSUPPORTED, msg.str()));
     }
     MultiThreadingCriticalSection cs;
index df1e9ba3151f56400bb916b61e4613806a7ec43b..55e4b2684bf95937a2c52af5fe8242d87a8821d1 100644 (file)
@@ -82,6 +82,20 @@ TEST_F(LeaseMgrTest, getLease6) {
                  MultipleRecords);
 }
 
+// Verify generic lfcStartHandler.
+TEST_F(LeaseMgrTest, lfcStartHandler) {
+
+    DatabaseConnection::ParameterMap pmap;
+    boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+    ConstElementPtr response;
+    EXPECT_NO_THROW(response = mgr->lfcStartHandler());
+    ASSERT_TRUE(response);
+    string expected = "{ \"result\": 2, \"text\": ";
+    expected += "\"lease backend 'concrete' is not 'memfile'\" }";
+    EXPECT_EQ(expected, response->str());
+}
+
 // Verify LeaseStatsQuery default construction
 TEST (LeaseStatsQueryTest, defaultCtor) {
     LeaseStatsQueryPtr qry;
index 12b1b17a4f6ae0f52fc63b04b166bcc2f0c57741..ebbe5154185d4d3eb339705503d53215627ece1d 100644 (file)
@@ -106,16 +106,122 @@ public:
     using Memfile_LeaseMgr::buildExtendedInfoTables6;
 };
 
+/// @brief Common part of test fixture classes managing lease files.
+class BaseMemfileLeaseMgrTest {
+public:
+    /// @brief constructor
+    BaseMemfileLeaseMgrTest() :
+        io_service_(getIOService()),
+        timer_mgr_(TimerMgr::instance()),
+        extra_files_() {
+        timer_mgr_->setIOService(io_service_);
+        DatabaseConnection::setIOService(io_service_);
+        ProcessSpawn::setIOService(io_service_);
+
+        setenv("KEA_LFC_EXECUTABLE", KEA_LFC_EXECUTABLE, 1);
+    }
+
+    /// @brief destructor
+    virtual ~BaseMemfileLeaseMgrTest() {
+        // Stop TimerMgr worker thread if it is running.
+        // Make sure there are no timers registered.
+        timer_mgr_->unregisterTimers();
+
+        getIOService()->stopAndPoll();
+    }
+
+    /// @brief Remove files being products of Lease File Cleanup.
+    ///
+    /// @param base_name Path to the lease file name. This file is removed
+    /// and all files which names are created from this name (having specific
+    /// suffixes used by Lease File Cleanup mechanism).
+    void removeFiles(const std::string& base_name) const {
+        // Generate suffixes and append them to the base name. The
+        // resulting file names are the ones that may exist as a
+        // result of LFC.
+        for (int i = static_cast<int>(Memfile_LeaseMgr::FILE_CURRENT);
+             i <= static_cast<int>(Memfile_LeaseMgr::FILE_FINISH);
+             ++i) {
+            Memfile_LeaseMgr::LFCFileType type = static_cast<
+                Memfile_LeaseMgr::LFCFileType>(i);
+            LeaseFileIO io(Memfile_LeaseMgr::appendSuffix(base_name, type));
+            io.removeFile();
+        }
+    }
+
+    /// @brief Remove other files.
+    void removeOtherFiles() const {
+        for (auto const& file : extra_files_) {
+            LeaseFileIO io(file);
+            io.removeFile();
+        }
+    }
+
+    /// @brief Return path to the lease file used by unit tests.
+    ///
+    /// @param filename Name of the lease file appended to the path to the
+    /// directory where test data is held.
+    ///
+    /// @return Full path to the lease file.
+    static std::string getLeaseFilePath(const std::string& filename) {
+        std::ostringstream s;
+        s << CfgMgr::instance().getDataDir() << "/" << filename;
+        return (s.str());
+    }
+
+    /// @brief Single instance of IOService.
+    static asiolink::IOServicePtr getIOService() {
+        static asiolink::IOServicePtr io_service(new asiolink::IOService());
+        return (io_service);
+    }
+
+    /// @brief Waits for the specified process to finish.
+    ///
+    /// @param process An object which started the process.
+    /// @param timeout Timeout in seconds.
+    ///
+    /// @return true if the process ended, false otherwise
+    bool waitForProcess(const Memfile_LeaseMgr& lease_mgr,
+                        const uint8_t timeout) {
+        const uint32_t iterations_max = timeout * 1000;
+        IntervalTimer fast_path_timer(io_service_);
+        IntervalTimer timer(io_service_);
+        bool elapsed = false;
+        timer.setup([&]() {
+            io_service_->stop();
+            elapsed = true;
+        }, iterations_max, IntervalTimer::ONE_SHOT);
+
+        fast_path_timer.setup([&]() {
+            if (!lease_mgr.isLFCRunning()) {
+                io_service_->stop();
+            }
+        }, 1, IntervalTimer::REPEATING);
+
+        io_service_->run();
+        io_service_->stop();
+        io_service_->restart();
+        return (!elapsed);
+    }
+
+    /// @brief Pointer to the IO service used by the tests.
+    IOServicePtr io_service_;
+
+    /// @brief Pointer to the instance of the @c TimerMgr.
+    TimerMgrPtr timer_mgr_;
+
+    /// @brief List of names of other files to removed.
+    vector<string> extra_files_;
+};
+
 /// @brief Test fixture class for @c Memfile_LeaseMgr
-class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
+class MemfileLeaseMgrTest : public GenericLeaseMgrTest,
+                            public BaseMemfileLeaseMgrTest {
 public:
     /// @brief memfile lease mgr test constructor
     ///
     /// Creates memfile and stores it in lmptr_ pointer
     MemfileLeaseMgrTest() :
-        io_service_(getIOService()),
-        timer_mgr_(TimerMgr::instance()),
-        extra_files_(),
         data_dir_env_var_("KEA_DHCP_DATA_DIR") {
 
         // Reset the env variable.
@@ -126,12 +232,6 @@ public:
         original_datadir_ = CfgMgr::instance().getDataDir();
         CfgMgr::instance().getDataDir(true, TEST_DATA_BUILDDIR);
 
-        timer_mgr_->setIOService(io_service_);
-        DatabaseConnection::setIOService(io_service_);
-        ProcessSpawn::setIOService(io_service_);
-
-        setenv("KEA_LFC_EXECUTABLE", KEA_LFC_EXECUTABLE, 1);
-
         // Remove lease files and products of Lease File Cleanup.
         removeFiles(getLeaseFilePath("leasefile4_0.csv"));
         removeFiles(getLeaseFilePath("leasefile6_0.csv"));
@@ -160,9 +260,6 @@ public:
     ///
     /// destroys lease manager backend.
     virtual ~MemfileLeaseMgrTest() {
-        // Stop TimerMgr worker thread if it is running.
-        // Make sure there are no timers registered.
-        timer_mgr_->unregisterTimers();
         LeaseMgrFactory::destroy();
         // Remove lease files and products of Lease File Cleanup.
         removeFiles(getLeaseFilePath("leasefile4_0.csv"));
@@ -175,52 +272,11 @@ public:
         // Disable multi-threading.
         MultiThreadingMgr::instance().setMode(false);
 
-        getIOService()->stopAndPoll();
-
         // Revert to original data directory.
         CfgMgr::instance().getDataDir(true, original_datadir_);
         file::PathChecker::enableEnforcement(true);
     }
 
-    /// @brief Remove files being products of Lease File Cleanup.
-    ///
-    /// @param base_name Path to the lease file name. This file is removed
-    /// and all files which names are created from this name (having specific
-    /// suffixes used by Lease File Cleanup mechanism).
-    void removeFiles(const std::string& base_name) const {
-        // Generate suffixes and append them to the base name. The
-        // resulting file names are the ones that may exist as a
-        // result of LFC.
-        for (int i = static_cast<int>(Memfile_LeaseMgr::FILE_CURRENT);
-             i <= static_cast<int>(Memfile_LeaseMgr::FILE_FINISH);
-             ++i) {
-            Memfile_LeaseMgr::LFCFileType type = static_cast<
-                Memfile_LeaseMgr::LFCFileType>(i);
-            LeaseFileIO io(Memfile_LeaseMgr::appendSuffix(base_name, type));
-            io.removeFile();
-        }
-    }
-
-    /// @brief Remove other files.
-    void removeOtherFiles() const {
-        for (auto const& file : extra_files_) {
-            LeaseFileIO io(file);
-            io.removeFile();
-        }
-    }
-
-    /// @brief Return path to the lease file used by unit tests.
-    ///
-    /// @param filename Name of the lease file appended to the path to the
-    /// directory where test data is held.
-    ///
-    /// @return Full path to the lease file.
-    static std::string getLeaseFilePath(const std::string& filename) {
-        std::ostringstream s;
-        s << CfgMgr::instance().getDataDir() << "/" << filename;
-        return (s.str());
-    }
-
     /// @brief Returns the configuration string for the backend.
     ///
     /// This string configures the @c LeaseMgrFactory to create the memfile
@@ -268,41 +324,6 @@ public:
         io_service_->restart();
     }
 
-    /// @brief Waits for the specified process to finish.
-    ///
-    /// @param process An object which started the process.
-    /// @param timeout Timeout in seconds.
-    ///
-    /// @return true if the process ended, false otherwise
-    bool waitForProcess(const Memfile_LeaseMgr& lease_mgr,
-                        const uint8_t timeout) {
-        const uint32_t iterations_max = timeout * 1000;
-        IntervalTimer fast_path_timer(io_service_);
-        IntervalTimer timer(io_service_);
-        bool elapsed = false;
-        timer.setup([&]() {
-            io_service_->stop();
-            elapsed = true;
-        }, iterations_max, IntervalTimer::ONE_SHOT);
-
-        fast_path_timer.setup([&]() {
-            if (!lease_mgr.isLFCRunning()) {
-                io_service_->stop();
-            }
-        }, 1, IntervalTimer::REPEATING);
-
-        io_service_->run();
-        io_service_->stop();
-        io_service_->restart();
-        return (!elapsed);
-    }
-
-    /// @brief Single instance of IOService.
-    static asiolink::IOServicePtr getIOService() {
-        static asiolink::IOServicePtr io_service(new asiolink::IOService());
-        return (io_service);
-    }
-
     /// @brief Generates a DHCPv4 lease with random content.
     ///
     /// The following lease parameters are randomly generated:
@@ -401,15 +422,6 @@ public:
         return (lease);
     }
 
-    /// @brief Pointer to the IO service used by the tests.
-    IOServicePtr io_service_;
-
-    /// @brief Pointer to the instance of the @c TimerMgr.
-    TimerMgrPtr timer_mgr_;
-
-    /// @brief List of names of other files to removed.
-    vector<string> extra_files_;
-
     /// @brief RAII wrapper for KEA_DHCP_DATA_DIR env variable.
     EnvVarWrapper data_dir_env_var_;
 
@@ -4543,7 +4555,8 @@ TEST_F(MemfileLeaseMgrTest, bigStats) {
 }
 
 /// @brief Test fixture which allows log content to be tested.
-class MemfileLeaseMgrLogTest : public LogContentTest {
+class MemfileLeaseMgrLogTest : public LogContentTest,
+                               public BaseMemfileLeaseMgrTest {
 public:
     /// @brief memfile lease mgr test constructor
     ///
@@ -4568,6 +4581,11 @@ public:
     /// destroys lease manager backend.
     virtual ~MemfileLeaseMgrLogTest() {
         LeaseMgrFactory::destroy();
+        // Remove lease files and products of Lease File Cleanup.
+        removeFiles(getLeaseFilePath("leasefile4_0.csv"));
+        removeFiles(getLeaseFilePath("leasefile6_0.csv"));
+        // Remove other files.
+        removeOtherFiles();
 
         // Disable multi-threading.
         MultiThreadingMgr::instance().setMode(false);
@@ -4594,12 +4612,12 @@ TEST_F(MemfileLeaseMgrLogTest, warnWhenSecurityDisabled) {
     pmap["universe"] = "6";
     pmap["persist"] = "true";
     pmap["lfc-interval"] = "0";
-    pmap["name"] = "/tmp/leasefile6_1.csv";
+    pmap["name"] = "/tmp/leasefile6_0.csv";
     boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
 
     ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
     EXPECT_EQ(lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V6),
-              "/tmp/leasefile6_1.csv");
+              "/tmp/leasefile6_0.csv");
 
     std::ostringstream oss;
     oss << "DHCPSRV_MEMFILE_PATH_SECURITY_WARNING Lease file path specified is NOT SECURE:"
@@ -4609,4 +4627,107 @@ TEST_F(MemfileLeaseMgrLogTest, warnWhenSecurityDisabled) {
     EXPECT_EQ(1, countFile(oss.str()));
 }
 
+/// @brief Verifies that lfcStartHandler requires persist true.
+TEST_F(MemfileLeaseMgrLogTest, lfcStartHandlerPersistFalse) {
+    DatabaseConnection::ParameterMap pmap;
+    pmap["universe"] = "4";
+    pmap["persist"] = "false";
+    pmap["lfc-interval"] = "0";
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+    // Persist is false so there is no lease file...
+    ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+    ASSERT_TRUE(lease_mgr);
+    ConstElementPtr response;
+    EXPECT_NO_THROW(response = lease_mgr->lfcStartHandler());
+    ASSERT_TRUE(response);
+    string expected = "{ \"result\": 2, \"text\": ";
+    expected += "\"'persist' parameter of 'memfile' lease backend ";
+    expected += "was configured to 'false'\" }";
+    EXPECT_EQ(expected, response->str());
+
+    // No reschedule.
+    string msg = "DHCPSRV_MEMFILE_LFC_RESCHEDULED ";
+    msg += "rescheduled Lease File Cleanup";
+    EXPECT_EQ(0, countFile(msg));
+
+    // No start.
+    msg = "DHCPSRV_MEMFILE_LFC_START ";
+    msg += "starting Lease File Cleanup";
+    EXPECT_EQ(0, countFile(msg));
+}
+
+/// @brief Verifies that lfcStartHandler does not requires lfc-interval > 0.
+TEST_F(MemfileLeaseMgrLogTest, lfcStartHandlerLfcInterval0) {
+    DatabaseConnection::ParameterMap pmap;
+    pmap["universe"] = "4";
+    pmap["persist"] = "true";
+    pmap["lfc-interval"] = "0";
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+    // Persist is false so there is no lease file...
+    ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+    ASSERT_TRUE(lease_mgr);
+    ConstElementPtr response;
+    EXPECT_NO_THROW(response = lease_mgr->lfcStartHandler());
+    ASSERT_TRUE(response);
+    string expected = "{ \"result\": 0, \"text\": \"kea-lfc started\" }";
+    EXPECT_EQ(expected, response->str());
+
+    // Wait for the LFC process to complete.
+    ASSERT_TRUE(waitForProcess(*lease_mgr, 1));
+
+    // And make sure it has returned an exit status of 0.
+    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
+        << "environment not available to LFC";
+
+    // No reschedule.
+    string msg = "DHCPSRV_MEMFILE_LFC_RESCHEDULED ";
+    msg += "rescheduled Lease File Cleanup";
+    EXPECT_EQ(0, countFile(msg));
+
+    // Start.
+    msg = "DHCPSRV_MEMFILE_LFC_START ";
+    msg += "starting Lease File Cleanup";
+    EXPECT_EQ(1, countFile(msg));
+}
+
+/// @brief Verifies that lfcStartHandler reschedules and starts lfc.
+TEST_F(MemfileLeaseMgrLogTest, lfcStartHandler) {
+    DatabaseConnection::ParameterMap pmap;
+    pmap["universe"] = "4";
+    pmap["persist"] = "true";
+    pmap["lfc-interval"] = "10";
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+    // Persist is false so there is no lease file...
+    ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+    ASSERT_TRUE(lease_mgr);
+    ConstElementPtr response;
+    EXPECT_NO_THROW(response = lease_mgr->lfcStartHandler());
+    ASSERT_TRUE(response);
+    string expected = "{ \"result\": 0, \"text\": \"kea-lfc started\" }";
+    EXPECT_EQ(expected, response->str());
+
+    // Wait for the LFC process to complete.
+    ASSERT_TRUE(waitForProcess(*lease_mgr, 1));
+
+    // And make sure it has returned an exit status of 0.
+    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
+        << "environment not available to LFC";
+
+    // Reschedule.
+    string msg = "DHCPSRV_MEMFILE_LFC_RESCHEDULED ";
+    msg += "rescheduled Lease File Cleanup";
+    EXPECT_EQ(1, countFile(msg));
+
+    // Start.
+    msg = "DHCPSRV_MEMFILE_LFC_START ";
+    msg += "starting Lease File Cleanup";
+    EXPECT_EQ(1, countFile(msg));
+}
+
 }  // namespace