From: Francis Dupont Date: Fri, 12 Sep 2025 13:48:13 +0000 (+0200) Subject: [#4094] Added last UTs X-Git-Tag: Kea-3.1.2~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e4b7dfa809f727ce5e934892e6659ad50efb0f26;p=thirdparty%2Fkea.git [#4094] Added last UTs --- diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc index 493611ac72..2f6b161450 100644 --- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc @@ -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); } diff --git a/src/bin/dhcp4/tests/http_control_socket_unittest.cc b/src/bin/dhcp4/tests/http_control_socket_unittest.cc index 1197d6ca80..c3132ded53 100644 --- a/src/bin/dhcp4/tests/http_control_socket_unittest.cc +++ b/src/bin/dhcp4/tests/http_control_socket_unittest.cc @@ -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); } diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc index c3a993b43d..e4e9ffa99b 100644 --- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc @@ -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); } diff --git a/src/bin/dhcp6/tests/http_control_socket_unittest.cc b/src/bin/dhcp6/tests/http_control_socket_unittest.cc index 269a1ecc7e..37287937a5 100644 --- a/src/bin/dhcp6/tests/http_control_socket_unittest.cc +++ b/src/bin/dhcp6/tests/http_control_socket_unittest.cc @@ -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); } diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc index 9994cd1f61..958510e45a 100644 --- a/src/lib/dhcpsrv/lease_mgr.cc +++ b/src/lib/dhcpsrv/lease_mgr.cc @@ -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())); } diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index 92d804d492..3ba5ea47fa 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -164,11 +164,6 @@ LFCSetup::setup(const uint32_t lfc_interval, const boost::shared_ptr& 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; diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc index df1e9ba315..55e4b2684b 100644 --- a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc @@ -82,6 +82,20 @@ TEST_F(LeaseMgrTest, getLease6) { MultipleRecords); } +// Verify generic lfcStartHandler. +TEST_F(LeaseMgrTest, lfcStartHandler) { + + DatabaseConnection::ParameterMap pmap; + boost::scoped_ptr 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; diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index 12b1b17a4f..ebbe515418 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -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(Memfile_LeaseMgr::FILE_CURRENT); + i <= static_cast(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 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(Memfile_LeaseMgr::FILE_CURRENT); - i <= static_cast(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 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 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 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 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 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