]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3536] implemented register and deregister in lease mgr factory
authorRazvan Becheriu <razvan@isc.org>
Wed, 28 Aug 2024 14:51:41 +0000 (17:51 +0300)
committerRazvan Becheriu <razvan@isc.org>
Wed, 11 Sep 2024 08:36:40 +0000 (11:36 +0300)
17 files changed:
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp4/tests/dhcp4_test_utils.cc
src/bin/dhcp6/json_config_parser.cc
src/bin/dhcp6/tests/dhcp6_test_utils.cc
src/hooks/dhcp/lease_cmds/tests/lease_cmds4_unittest.cc
src/lib/dhcpsrv/dhcpsrv_messages.cc
src/lib/dhcpsrv/dhcpsrv_messages.h
src/lib/dhcpsrv/dhcpsrv_messages.mes
src/lib/dhcpsrv/host_data_source_factory.cc
src/lib/dhcpsrv/lease_mgr_factory.cc
src/lib/dhcpsrv/lease_mgr_factory.h
src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc
src/lib/dhcpsrv/tests/lease_mgr_factory_unittest.cc
src/lib/dhcpsrv/testutils/generic_cb_dhcp4_unittest.cc
src/lib/dhcpsrv/testutils/generic_cb_dhcp6_unittest.cc
src/lib/dhcpsrv/tracking_lease_mgr.h

index a07ae52f60de5864627b061d704e815f3d89d103..68fa6db7395edba42ac48ba1531666a7ae452739 100644 (file)
@@ -25,6 +25,7 @@
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/config_backend_dhcp4_mgr.h>
 #include <dhcpsrv/db_type.h>
+#include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/parsers/client_class_def_parser.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/parsers/expiration_config_parser.h>
@@ -341,9 +342,6 @@ processDhcp4Config(isc::data::ConstElementPtr config_set) {
     // for option definitions. This is equivalent to committing empty container.
     LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
 
-    // Print the list of known backends.
-    HostDataSourceFactory::printRegistered();
-
     // Answer will hold the result.
     ConstElementPtr answer;
 
@@ -902,8 +900,15 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
         }
     }
 
+    // Print the list of known backends.
+    LeaseMgrFactory::printRegistered();
+
+    // Print the list of known backends.
+    HostDataSourceFactory::printRegistered();
+
     // Moved from the commit block to add the config backend indication.
     if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
+
         try {
             // If there are config backends, fetch and merge into staging config
             server.getCBControl()->databaseConfigFetch(srv_config,
index 8f303b9d3d215bdfafe79cd48820a634c77bb98b..f3db6b19121f0bfdd1e2fe768884cd4620fe6142 100644 (file)
@@ -828,7 +828,7 @@ Dhcpv4SrvTest::configure(const std::string& config,
     ConstElementPtr json;
     try {
         json = parseJSON(config);
-    } catch (const std::exception& ex){
+    } catch (const std::exception& ex) {
         // Fatal failure on parsing error
         FAIL() << "parsing failure:"
                << "config:" << config << std::endl
index 9b05170d4b409fea7a525cd5607d34e1b94d5554..74c4f9087d145135a2409dcd650cff10dc74482b 100644 (file)
@@ -24,6 +24,7 @@
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/db_type.h>
+#include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/parsers/client_class_def_parser.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/parsers/duid_config_parser.h>
@@ -443,9 +444,6 @@ processDhcp6Config(isc::data::ConstElementPtr config_set) {
     // for option definitions. This is equivalent to committing empty container.
     LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
 
-    // Print the list of known backends.
-    HostDataSourceFactory::printRegistered();
-
     // Answer will hold the result.
     ConstElementPtr answer;
 
@@ -1038,6 +1036,12 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
         }
     }
 
+    // Print the list of known backends.
+    LeaseMgrFactory::printRegistered();
+
+    // Print the list of known backends.
+    HostDataSourceFactory::printRegistered();
+
     // Moved from the commit block to add the config backend indication.
     if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
         try {
index 49d4d25680bbd8a86ca0b3c9dd30ac4ffedd87bc..c3a36473de0aed9a560fafa60a5a22fed22b0466 100644 (file)
@@ -51,7 +51,7 @@ BaseServerTest::~BaseServerTest() {
     // Revert to original data directory.
     CfgMgr::instance().setDataDir(original_datadir_);
 
-    // Revert to unit test logging in case the test reconfigured logging.
+    // Revert to unit test logging, in case the test reconfigured it.
     isc::log::initLogger();
 }
 
@@ -606,7 +606,6 @@ Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
 
     ObservationPtr stat = StatsMgr::instance().getObservation(name);
     ASSERT_TRUE(stat);
-    uint64_t before = stat->getInteger().first;
 
     // Let's create a RELEASE
     Pkt6Ptr rel = createMessage(DHCPV6_RELEASE, type, release_addr, prefix_len,
index 783d5ce52e22c708d85a539bcff1d3c3d8ff5343..4dcc6efc868f07d41990d8ae111cc3990314e748 100644 (file)
@@ -3519,12 +3519,12 @@ TEST_F(Lease4CmdsTest, lease4AddDeclinedLeasesMultiThreading) {
 }
 
 TEST_F(Lease4CmdsTest, lease4AddReleasedLeases) {
-    testLease4AddDeclinedLeases();
+    testLease4AddReleasedLeases();
 }
 
 TEST_F(Lease4CmdsTest, lease4AddReleasedLeasesMultiThreading) {
     MultiThreadingTest mt(true);
-    testLease4AddDeclinedLeases();
+    testLease4AddReleasedLeases();
 }
 
 TEST_F(Lease4CmdsTest, lease4AddExisting) {
index b9b61b9a900292f7236904ca2852eec2a2d40d52..471bef7f8f52ec27ffe7ddb9ef94685c43afe8b7 100644 (file)
@@ -69,6 +69,9 @@ extern const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL = "DHC
 extern const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED = "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED";
 extern const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL = "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL";
 extern const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED = "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED";
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_BACKENDS_REGISTERED = "DHCPSRV_LEASE_MGR_BACKENDS_REGISTERED";
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_BACKEND_DEREGISTER = "DHCPSRV_LEASE_MGR_BACKEND_DEREGISTER";
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_BACKEND_REGISTER = "DHCPSRV_LEASE_MGR_BACKEND_REGISTER";
 extern const isc::log::MessageID DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION = "DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION";
 extern const isc::log::MessageID DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION = "DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION";
 extern const isc::log::MessageID DHCPSRV_LEASE_MGR_DB_OPEN_CONNECTION_WITH_RETRY_FAILED = "DHCPSRV_LEASE_MGR_DB_OPEN_CONNECTION_WITH_RETRY_FAILED";
@@ -339,6 +342,9 @@ const char* values[] = {
     "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED", "extended info for lease %1 was upgraded",
     "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL", "extended info for lease %1 failed checks (%2)",
     "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED", "extended info for lease %1 was upgraded",
+    "DHCPSRV_LEASE_MGR_BACKENDS_REGISTERED", "the following lease backend types are available: %1",
+    "DHCPSRV_LEASE_MGR_BACKEND_DEREGISTER", "deregistered lease backend type: %1",
+    "DHCPSRV_LEASE_MGR_BACKEND_REGISTER", "registered lease backend type: %1",
     "DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION", "exception occurred in a lease manager callback for callback type %1, subnet id %2, and lease %3: %4",
     "DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION", "unknown exception occurred in a lease manager callback for callback type %1, subnet id %2, and lease %3",
     "DHCPSRV_LEASE_MGR_DB_OPEN_CONNECTION_WITH_RETRY_FAILED", "Failed to connect to database: %1 with error: %2",
index 788a84417fc4b92625b974697cd47328e74ccb05..59b8652a39cbab76290839815728f578515e92ca 100644 (file)
@@ -70,6 +70,9 @@ extern const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL;
 extern const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED;
 extern const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL;
 extern const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED;
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_BACKENDS_REGISTERED;
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_BACKEND_DEREGISTER;
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_BACKEND_REGISTER;
 extern const isc::log::MessageID DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION;
 extern const isc::log::MessageID DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION;
 extern const isc::log::MessageID DHCPSRV_LEASE_MGR_DB_OPEN_CONNECTION_WITH_RETRY_FAILED;
index c6cacd017bdc208789495a6e31424e71a9d4f9c0..eb184e56486d38121bc019f5f8c364d9f753afba 100644 (file)
@@ -410,6 +410,20 @@ the lease database. The operation started a retry to connect procedure.
 The database access string with password redacted is logged, along with the
 error and details for the reconnect procedure.
 
+% DHCPSRV_LEASE_MGR_BACKENDS_REGISTERED the following lease backend types are available: %1
+This informational message lists all possible lease backends that could
+be used in lease-database.
+
+% DHCPSRV_LEASE_MGR_BACKEND_DEREGISTER deregistered lease backend type: %1
+Logged at debug log level 40.
+This debug message is issued when a backend factory was deregistered.
+It is no longer possible to use lease backend of this type.
+
+% DHCPSRV_LEASE_MGR_BACKEND_REGISTER registered lease backend type: %1
+Logged at debug log level 40.
+This debug message is issued when a backend factory was successfully
+registered. It is now possible to use lease backend of this type.
+
 % DHCPSRV_LEASE_SANITY_FAIL The lease %1 with subnet-id %2 failed subnet-id checks (%3).
 This warning message is printed when the lease being loaded does not match the
 configuration. Due to lease-checks value, the lease will be loaded, but
index 955a4cafff9a9a7c75ea6a246feafd83f3eafc84..b8064ee7932063fcd0eeaa1f0b05c3d230f0f616 100644 (file)
@@ -184,6 +184,7 @@ using namespace isc::dhcp;
 
 namespace {
 
+// Code will be moved to appropriate hook library.
 #ifdef HAVE_MYSQL
 struct MySqlHostDataSourceInit {
     // Constructor registers
@@ -209,6 +210,7 @@ struct MySqlHostDataSourceInit {
 MySqlHostDataSourceInit mysql_init_;
 #endif
 
+// Code will be moved to appropriate hook library.
 #ifdef HAVE_PGSQL
 struct PgSqlHostDataSourceInit {
     // Constructor registers
index 0cb9d019ad33fa4ebba217d33ddf29549a6790ac..ed2cb862c79fd018683908fb75ac744c675222a0 100644 (file)
@@ -31,9 +31,11 @@ using namespace std;
 namespace isc {
 namespace dhcp {
 
-boost::scoped_ptr<TrackingLeaseMgr>&
+map<string, LeaseMgrFactory::Factory> LeaseMgrFactory::map_;
+
+TrackingLeaseMgrPtr&
 LeaseMgrFactory::getLeaseMgrPtr() {
-    static boost::scoped_ptr<TrackingLeaseMgr> lease_mgr_ptr;
+    static TrackingLeaseMgrPtr lease_mgr_ptr;
     return (lease_mgr_ptr);
 }
 
@@ -45,47 +47,70 @@ LeaseMgrFactory::create(const std::string& dbaccess) {
     DatabaseConnection::ParameterMap parameters = DatabaseConnection::parse(dbaccess);
     std::string redacted = DatabaseConnection::redactedAccessString(parameters);
 
-    // Is "type" present?
-    if (parameters.find(type) == parameters.end()) {
+    // Get the database type and open the corresponding database
+    DatabaseConnection::ParameterMap::iterator it = parameters.find(type);
+    if (it == parameters.end()) {
         LOG_ERROR(dhcpsrv_logger, DHCPSRV_NOTYPE_DB).arg(dbaccess);
         isc_throw(InvalidParameter, "Database configuration parameters do not "
                   "contain the 'type' keyword");
     }
 
-    // Yes, check what it is.
-    if (parameters[type] == string("mysql")) {
+    // Code will be moved to appropriate hook library.
 #ifdef HAVE_MYSQL
-        LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_DB).arg(redacted);
-        getLeaseMgrPtr().reset(new MySqlLeaseMgr(parameters));
-        return;
-#else
-        LOG_ERROR(dhcpsrv_logger, DHCPSRV_UNKNOWN_DB).arg("mysql");
-        isc_throw(InvalidType, "The Kea server has not been compiled with "
-                  "support for database type: mysql");
+    // Factory method
+    auto mysql_factory = [](const DatabaseConnection::ParameterMap& parameters) -> TrackingLeaseMgrPtr {
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_DB)
+            .arg(DatabaseConnection::redactedAccessString(parameters));
+        return (TrackingLeaseMgrPtr(new MySqlLeaseMgr(parameters)));
+    };
+    LeaseMgrFactory::registerFactory("mysql", mysql_factory, true);
 #endif
-    }
 
-    if (parameters[type] == string("postgresql")) {
+    // Code will be moved to appropriate hook library.
 #ifdef HAVE_PGSQL
-        LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_DB).arg(redacted);
-        getLeaseMgrPtr().reset(new PgSqlLeaseMgr(parameters));
-        return;
-#else
-        LOG_ERROR(dhcpsrv_logger, DHCPSRV_UNKNOWN_DB).arg("postgresql");
-        isc_throw(InvalidType, "The Kea server has not been compiled with "
-                  "support for database type: postgresql");
+    // Factory method
+    auto pgsql_factory = [](const DatabaseConnection::ParameterMap& parameters) -> TrackingLeaseMgrPtr {
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_DB)
+            .arg(DatabaseConnection::redactedAccessString(parameters));
+        return (TrackingLeaseMgrPtr(new PgSqlLeaseMgr(parameters)));
+    };
+    LeaseMgrFactory::registerFactory("postgresql", pgsql_factory, true);
 #endif
-    }
+
     if (parameters[type] == string("memfile")) {
         LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_DB).arg(redacted);
         getLeaseMgrPtr().reset(new Memfile_LeaseMgr(parameters));
         return;
     }
 
-    // Get here on no match
-    LOG_ERROR(dhcpsrv_logger, DHCPSRV_UNKNOWN_DB).arg(parameters[type]);
-    isc_throw(InvalidType, "Database access parameter 'type' does "
-              "not specify a supported database backend: " << parameters[type]);
+    string db_type = it->second;
+    auto index = map_.find(db_type);
+
+    // No match?
+    if (index == map_.end()) {
+        if ((db_type == "mysql") ||
+            (db_type == "postgresql")) {
+            LOG_ERROR(dhcpsrv_logger, DHCPSRV_UNKNOWN_DB).arg(db_type);
+            string with = (db_type == "postgresql" ? "pgsql" : db_type);
+            isc_throw(InvalidType, "The Kea server has not been compiled with "
+                      "support for database type: " << db_type
+                      << ". Did you forget to use --with-"
+                      << with << " during compilation?");
+        }
+        // Get here on no match
+        LOG_ERROR(dhcpsrv_logger, DHCPSRV_UNKNOWN_DB).arg(parameters[type]);
+        isc_throw(InvalidType, "Database access parameter 'type' does "
+                  "not specify a supported database backend: " << parameters[type]);
+    }
+
+    // Call the factory.
+    getLeaseMgrPtr() = index->second(parameters);
+
+    // Check the factory did not return NULL.
+    if (!getLeaseMgrPtr()) {
+        isc_throw(Unexpected, "Lease database " << db_type <<
+                  " factory returned NULL");
+    }
 }
 
 void
@@ -97,6 +122,14 @@ LeaseMgrFactory::destroy() {
             .arg(getLeaseMgrPtr()->getType());
     }
     getLeaseMgrPtr().reset();
+    // Code will be moved to appropriate hook library.
+#ifdef HAVE_MYSQL
+    LeaseMgrFactory::deregisterFactory("mysql", true);
+#endif
+    // Code will be moved to appropriate hook library.
+#ifdef HAVE_PGSQL
+    LeaseMgrFactory::deregisterFactory("postgresql", true);
+#endif
 }
 
 void
@@ -132,5 +165,58 @@ LeaseMgrFactory::instance() {
     return (*lmptr);
 }
 
+bool
+LeaseMgrFactory::registerFactory(const string& db_type,
+                                 const Factory& factory,
+                                 bool no_log) {
+    if (map_.count(db_type)) {
+        return (false);
+    }
+    map_.insert(pair<string, Factory>(db_type, factory));
+
+    // We are dealing here with static logger initialization fiasco.
+    // registerFactory may be called from constructors of static global
+    // objects for built in backends. The logging is not initialized yet,
+    // so the LOG_DEBUG would throw.
+    if (!no_log) {
+        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_LEASE_MGR_BACKEND_REGISTER)
+            .arg(db_type);
+    }
+    return (true);
+}
+
+bool
+LeaseMgrFactory::deregisterFactory(const string& db_type, bool no_log) {
+    auto index = map_.find(db_type);
+    if (index != map_.end()) {
+        map_.erase(index);
+        if (!no_log) {
+            LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+                    DHCPSRV_LEASE_MGR_BACKEND_DEREGISTER)
+                .arg(db_type);
+        }
+        return (true);
+    } else {
+        return (false);
+    }
+}
+
+bool
+LeaseMgrFactory::registeredFactory(const std::string& db_type) {
+    auto index = map_.find(db_type);
+    return (index != map_.end());
+}
+
+void
+LeaseMgrFactory::printRegistered() {
+    std::stringstream txt;
+
+    for (auto const& x : map_) {
+        txt << x.first << " ";
+    }
+
+    LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_MGR_BACKENDS_REGISTERED).arg(txt.str());
+}
+
 } // namespace dhcp
 } // namespace isc
index 69fef85dc42856c5d9c79c7d36b52dc2e5fedfdc..7e0cc7f420d3e74b402baa1dd78fae1530caa2d3 100644 (file)
@@ -103,14 +103,61 @@ public:
     /// @return True if the lease manager instance exists, false otherwise.
     static bool haveInstance();
 
+    /// @brief Type of lease mgr factory
+    ///
+    /// A factory takes a parameter map and returns a pointer to a lease mgr.
+    /// In case of failure it must throw and not return NULL.
+    typedef std::function<TrackingLeaseMgrPtr (const db::DatabaseConnection::ParameterMap&)> Factory;
+
+    /// @brief Register a lease mgr factory
+    ///
+    /// Associate the factory to a database type in the map.
+    /// The no_log is to avoid logging before the logger is initialized
+    /// as when called at global object initialization.
+    ///
+    /// @param db_type database type
+    /// @param factory lease mgr factory
+    /// @param no_log do not log (default false)
+    /// @return true if the factory was successfully added to the map, false
+    /// if it already exists.
+    static bool registerFactory(const std::string& db_type,
+                                const Factory& factory, bool no_log = false);
+
+    /// @brief Deregister a lease mgr factory
+    ///
+    /// Disassociate the factory to a database type in the map.
+    /// The no_log is to avoid logging during global object deinitialization.
+    ///
+    /// @param db_type database type
+    /// @param no_log do not log (default false)
+    /// @return true if the factory was successfully removed from the map,
+    /// false if it was not found.
+    static bool deregisterFactory(const std::string& db_type,
+                                  bool no_log = false);
+
+    /// @brief Check if a lease mgr factory was registered
+    ///
+    /// @param db_type database type
+    /// @return true if a factory was registered for db_type, false if not.
+    static bool registeredFactory(const std::string& db_type);
+
+    /// @brief Prints out all registered backends.
+    ///
+    /// We need a dedicated method for this, because we sometimes can't log
+    /// the backend type when doing early initialization for backends
+    /// initialized statically.
+    static void printRegistered();
+
 private:
     /// @brief Hold pointer to lease manager
     ///
     /// Holds a pointer to the singleton lease manager.  The singleton
     /// is encapsulated in this method to avoid a "static initialization
     /// fiasco" if defined in an external static variable.
-    static boost::scoped_ptr<TrackingLeaseMgr>& getLeaseMgrPtr();
+    static TrackingLeaseMgrPtr& getLeaseMgrPtr();
 
+    /// @brief Factory map
+    static std::map<std::string, Factory> map_;
 };
 
 } // end of isc::dhcp namespace
index 4ebd19ec4de14a54201521dc2d50de92dfdde921..33c7a39aa90a94fa890ceafccfe05544749692b5 100644 (file)
@@ -860,6 +860,8 @@ TEST_F(AllocEngine6Test, requestReuseReleasedLease6) {
                                cumulative, subnet_->getID()));
     glbl_cumulative += 1;
     EXPECT_TRUE(testStatistics("cumulative-assigned-nas", glbl_cumulative));
+    EXPECT_FALSE(testStatistics("cumulative-assigned-nas",
+                                other_cumulative, other_subnetid, false));
     EXPECT_TRUE(testStatistics("reclaimed-leases", 1));
     EXPECT_TRUE(testStatistics("reclaimed-leases", 0, subnet_->getID()));
     EXPECT_TRUE(testStatistics("reclaimed-leases", 1, other_subnetid));
index 1e71a9bb7aee6a3b5009efc2fab2c2c8f46c8533..5dc401ea6c61e6e8379acd5f9a2172bdf8d1e552 100644 (file)
@@ -724,7 +724,6 @@ CfgHostsTest::testDelete2ForIPv6() {
     // Add a host with two addresses.
     IOAddress address1("2001:db8:1::1");
     IOAddress address2("2001:db8:2::2");
-    size_t host_count = 10;
     SubnetID subnet_id(42);
 
     HostPtr host = HostPtr(new Host(duids_[0]->toText(), "duid",
@@ -759,7 +758,6 @@ CfgHostsTest::testDeleteBothForIPv6() {
     // Add a host with two addresses.
     IOAddress address1("2001:db8:1::1");
     IOAddress address2("2001:db8:2::");
-    size_t host_count = 10;
     SubnetID subnet_id(42);
 
     HostPtr host = HostPtr(new Host(duids_[0]->toText(), "duid",
index 5e8b9994c8569d24b5244626f0d43998ca4c0249..aa781c4741a6be7c8cf341d97e29bcef038c2b01 100644 (file)
@@ -7,7 +7,10 @@
 #include <config.h>
 
 #include <asiolink/io_address.h>
+#include <database/database_connection.h>
 #include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/memfile_lease_mgr.h>
+#include <dhcpsrv/tracking_lease_mgr.h>
 #include <exceptions/exceptions.h>
 
 #include <gtest/gtest.h>
@@ -16,6 +19,8 @@
 #include <sstream>
 
 using namespace std;
+using namespace isc;
+using namespace isc::db;
 using namespace isc::dhcp;
 
 // This set of tests only check the parsing functions of LeaseMgrFactory.
@@ -28,4 +33,188 @@ using namespace isc::dhcp;
 
 namespace {
 
-}; // end of anonymous namespace
+TrackingLeaseMgrPtr
+memFactory(const DatabaseConnection::ParameterMap& parameters) {
+    return (TrackingLeaseMgrPtr(new Memfile_LeaseMgr(parameters)));
+}
+
+// @brief Register memFactory
+bool registerFactory() {
+    return (LeaseMgrFactory::registerFactory("mem", memFactory));
+}
+
+// @brief Derive mem1 class
+class Mem1LeaseMgr : public Memfile_LeaseMgr {
+public:
+    Mem1LeaseMgr(const DatabaseConnection::ParameterMap& parameters) :
+        Memfile_LeaseMgr(parameters) {
+    }
+    virtual ~Mem1LeaseMgr() = default;
+    virtual string getType() const {
+        return ("mem1");
+    }
+};
+
+// @brief Factory of mem1
+TrackingLeaseMgrPtr
+mem1Factory(const DatabaseConnection::ParameterMap& parameters) {
+    return (TrackingLeaseMgrPtr(new Mem1LeaseMgr(parameters)));
+}
+
+// @brief Register mem1Factory
+bool registerFactory1() {
+    return (LeaseMgrFactory::registerFactory("mem1", mem1Factory));
+}
+
+// @brief Derive mem2 class
+class Mem2LeaseMgr : public Memfile_LeaseMgr {
+public:
+    Mem2LeaseMgr(const DatabaseConnection::ParameterMap& parameters) :
+        Memfile_LeaseMgr(parameters) {
+    }
+    virtual ~Mem2LeaseMgr() = default;
+    virtual string getType() const {
+        return ("mem2");
+    }
+};
+
+// @brief Factory of mem2
+TrackingLeaseMgrPtr
+mem2Factory(const DatabaseConnection::ParameterMap& parameters) {
+    return (TrackingLeaseMgrPtr(new Mem2LeaseMgr(parameters)));
+}
+
+// @brief Register mem2Factory
+bool registerFactory2() {
+    return (LeaseMgrFactory::registerFactory("mem2", mem2Factory));
+}
+
+// @brief Factory function returning 0
+TrackingLeaseMgrPtr
+factory0(const DatabaseConnection::ParameterMap&) {
+    return (TrackingLeaseMgrPtr());
+}
+
+// @brief Test fixture class
+class LeaseMgrFactoryTest : public ::testing::Test {
+public:
+    /// @brief Constructor
+    LeaseMgrFactoryTest() = default;
+
+    /// @brief Destructor
+    virtual ~LeaseMgrFactoryTest() = default;
+
+private:
+    // @brief Prepares the class for a test.
+    virtual void SetUp() {
+        LeaseMgrFactory::destroy();
+    }
+
+    // @brief Cleans up after the test.
+    virtual void TearDown() {
+        LeaseMgrFactory::destroy();
+        LeaseMgrFactory::deregisterFactory("mem");
+        LeaseMgrFactory::deregisterFactory("mem1");
+        LeaseMgrFactory::deregisterFactory("mem2");
+    }
+};
+
+// Verify a factory can be registered and only once.
+TEST_F(LeaseMgrFactoryTest, registerFactory) {
+    EXPECT_TRUE(registerFactory());
+
+    // Only once
+    EXPECT_FALSE(registerFactory());
+}
+
+// Verify a factory registration can be checked.
+TEST_F(LeaseMgrFactoryTest, registeredFactory) {
+    // Not yet registered
+    EXPECT_FALSE(LeaseMgrFactory::registeredFactory("mem"));
+    EXPECT_FALSE(LeaseMgrFactory::registeredFactory("mem1"));
+
+    // Register mem
+    EXPECT_TRUE(registerFactory());
+
+    // Now mem is registered but not mem1
+    EXPECT_TRUE(LeaseMgrFactory::registeredFactory("mem"));
+    EXPECT_FALSE(LeaseMgrFactory::registeredFactory("mem1"));
+}
+
+// Verify a factory can be registered and deregistered
+TEST_F(LeaseMgrFactoryTest, deregisterFactory) {
+    // Does not exist at the beginning
+    EXPECT_FALSE(LeaseMgrFactory::deregisterFactory("mem"));
+
+    // Register and deregister
+    EXPECT_TRUE(registerFactory());
+    EXPECT_TRUE(LeaseMgrFactory::deregisterFactory("mem"));
+    EXPECT_FALSE(LeaseMgrFactory::registeredFactory("mem"));
+
+    // No longer exists
+    EXPECT_FALSE(LeaseMgrFactory::deregisterFactory("mem"));
+}
+
+// Verify a registered factory can be called
+TEST_F(LeaseMgrFactoryTest, create) {
+    EXPECT_TRUE(registerFactory());
+    EXPECT_NO_THROW(LeaseMgrFactory::create("type=mem persist=false universe=4"));
+    EXPECT_TRUE(LeaseMgrFactory::haveInstance());
+    EXPECT_EQ(LeaseMgrFactory::instance().getType(), "memfile");
+}
+
+// Verify that type is required
+TEST_F(LeaseMgrFactoryTest, notype) {
+    EXPECT_THROW(LeaseMgrFactory::create("tp=mem"),
+                 InvalidParameter);
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+    EXPECT_THROW(LeaseMgrFactory::create("type=mem"),
+                 InvalidType);
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+}
+
+// Verify that factory must not return NULL
+TEST_F(LeaseMgrFactoryTest, null) {
+    EXPECT_TRUE(LeaseMgrFactory::registerFactory("mem", factory0));
+    EXPECT_THROW(LeaseMgrFactory::create("type=mem"),
+                 Unexpected);
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+}
+
+// Verify destroy class method
+TEST_F(LeaseMgrFactoryTest, destroy) {
+    // No sources at the beginning
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+    EXPECT_NO_THROW(LeaseMgrFactory::destroy());
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+
+    // Add mem
+    EXPECT_TRUE(registerFactory());
+    EXPECT_NO_THROW(LeaseMgrFactory::create("type=mem persist=false universe=6"));
+    EXPECT_TRUE(LeaseMgrFactory::haveInstance());
+
+    EXPECT_NO_THROW(LeaseMgrFactory::destroy());
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+}
+
+// Verify create and destroy class method on multiple backends
+TEST_F(LeaseMgrFactoryTest, multiple) {
+    // Add foo twice
+    EXPECT_TRUE(registerFactory1());
+    EXPECT_NO_THROW(LeaseMgrFactory::create("type=mem1 persist=false universe=4"));
+    EXPECT_NO_THROW(LeaseMgrFactory::create("type=mem1 persist=false universe=6"));
+    EXPECT_TRUE(LeaseMgrFactory::haveInstance());
+    EXPECT_EQ(LeaseMgrFactory::instance().getType(), "mem1");
+
+    // Add mem2 once
+    EXPECT_TRUE(registerFactory2());
+    EXPECT_NO_THROW(LeaseMgrFactory::create("type=mem2 persist=false universe=6"));
+    EXPECT_TRUE(LeaseMgrFactory::haveInstance());
+    EXPECT_EQ(LeaseMgrFactory::instance().getType(), "mem2");
+
+    // Delete them
+    EXPECT_NO_THROW(LeaseMgrFactory::destroy());
+    EXPECT_FALSE(LeaseMgrFactory::haveInstance());
+}
+
+} // end of anonymous namespace
index 4731f6019e1d8fa2ee042c30d98dabcf24f78cb1..87d7e67e902d18210f83b24f27d706d3f48e57ca 100644 (file)
@@ -4296,6 +4296,11 @@ GenericConfigBackendDHCPv4Test::createUpdateClientClass4OptionsTest() {
     ASSERT_NO_THROW_LOG(client_class = cbptr_->getClientClass4(ServerSelector::ALL(), class1->getName()));
     ASSERT_TRUE(client_class);
 
+    // Verify lifetime values.
+    EXPECT_EQ(30, client_class->getValid().getMin());
+    EXPECT_EQ(60, client_class->getValid().get());
+    EXPECT_EQ(90, client_class->getValid().getMax());
+
     // Validate options belonging to the class.
     ASSERT_TRUE(client_class->getCfgOption());
     OptionDescriptor returned_opt_boot_file_name =
@@ -4341,6 +4346,11 @@ GenericConfigBackendDHCPv4Test::createUpdateClientClass4OptionsTest() {
     ASSERT_NO_THROW_LOG(client_class = cbptr_->getClientClass4(ServerSelector::ALL(), class1->getName()));
     ASSERT_TRUE(client_class);
 
+    // Re-check lifetime values. This ensure bindings line up.
+    EXPECT_EQ(30, client_class->getValid().getMin());
+    EXPECT_EQ(60, client_class->getValid().get());
+    EXPECT_EQ(90, client_class->getValid().getMax());
+
     // Ensure that the first option definition is gone.
     ASSERT_TRUE(client_class->getCfgOptionDef());
     returned_def_foo = client_class->getCfgOptionDef()->get(test_option_defs_[0]->getOptionSpaceName(),
index 216697ba437e1e3fb2000f3f2edfb0462726b320..55554af2f64a7a3783cbb7b56d9695abe756d78f 100644 (file)
@@ -4450,7 +4450,7 @@ GenericConfigBackendDHCPv6Test::createUpdateClientClass6OptionsTest() {
     ASSERT_NO_THROW_LOG(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
     ASSERT_TRUE(client_class);
 
-    // Verify lifetime values.  
+    // Verify lifetime values.
     EXPECT_EQ(30, client_class->getValid().getMin());
     EXPECT_EQ(60, client_class->getValid().get());
     EXPECT_EQ(90, client_class->getValid().getMax());
@@ -4503,7 +4503,7 @@ GenericConfigBackendDHCPv6Test::createUpdateClientClass6OptionsTest() {
     ASSERT_NO_THROW_LOG(client_class = cbptr_->getClientClass6(ServerSelector::ALL(), class1->getName()));
     ASSERT_TRUE(client_class);
 
-    //  Re-check lifetime values. This ensure bindings line up. 
+    // Re-check lifetime values. This ensure bindings line up.
     EXPECT_EQ(30, client_class->getValid().getMin());
     EXPECT_EQ(60, client_class->getValid().get());
     EXPECT_EQ(90, client_class->getValid().getMax());
index fe21177102913a29757027cbe9d47aff05c7e325..96b1d0b9648f68e5d80cead6db4600db1cb139ff 100644 (file)
@@ -302,6 +302,9 @@ protected:
     std::unordered_set<asiolink::IOAddress, asiolink::IOAddress::Hash> locked_leases_;
 };
 
+/// @brief TrackingLeaseMgr pointer
+typedef boost::shared_ptr<TrackingLeaseMgr> TrackingLeaseMgrPtr;
+
 } // end of namespace isc::dhcp
 } // end of namespace isc