Browse Source

[master] Merge branch 'trac2592' (getLease4 in memfile LeaseMgr)

Conflicts:
	ChangeLog
	src/lib/dhcpsrv/memfile_lease_mgr.cc
	src/lib/dhcpsrv/memfile_lease_mgr.h
	src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
Tomek Mrugalski 11 years ago
parent
commit
b3172918d5

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+671.	[func]		dclink,tomek
+	memfile backend now supports getLease4(hwaddr) and getLease4(client-id)
+	methods. Thanks to David Carlier for contributing a patch.
+	(Trac #2592, git a11683be53db2f9f8f9b71c1d1c163511e0319b3)
+
 670.	[func]		marcin
 670.	[func]		marcin
 	libdhcpsrv: Added support to MySQL lease database backend to
 	libdhcpsrv: Added support to MySQL lease database backend to
 	store FQDN data for the lease.
 	store FQDN data for the lease.

+ 4 - 6
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -1477,18 +1477,16 @@ TEST_F(Dhcpv4SrvTest, ReleaseBasic) {
     EXPECT_FALSE(l);
     EXPECT_FALSE(l);
 
 
     // Try to get the lease by hardware address
     // Try to get the lease by hardware address
-    // @todo: Uncomment this once trac2592 is implemented
-    // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
-    // EXPECT_EQ(leases.size(), 0);
+    Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
+    EXPECT_EQ(leases.size(), 0);
 
 
     // Try to get it by hw/subnet_id combination
     // Try to get it by hw/subnet_id combination
     l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
     l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
     EXPECT_FALSE(l);
     EXPECT_FALSE(l);
 
 
     // Try by client-id
     // Try by client-id
-    // @todo: Uncomment this once trac2592 is implemented
-    //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
-    //EXPECT_EQ(leases.size(), 0);
+    leases = LeaseMgrFactory::instance().getLease4(*client_id_);
+    EXPECT_EQ(leases.size(), 0);
 
 
     // Try by client-id/subnet-id
     // Try by client-id/subnet-id
     l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
     l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());

+ 5 - 0
src/lib/dhcpsrv/dhcpsrv_messages.mes

@@ -210,6 +210,11 @@ A debug message issued when the server is attempting to obtain an IPv6
 lease from the memory file database for a client with the specified IAID
 lease from the memory file database for a client with the specified IAID
 (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).
 (Identity Association ID), Subnet ID and DUID (DHCP Unique Identifier).
 
 
+% DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID obtaining IPv4 lease for client ID %1, hardware address %2 and subnet ID %3
+A debug message issued when the server is attempting to obtain an IPv4
+lease from the memory file database for a client with the specified
+client ID, hardware address and subnet ID.
+
 % DHCPSRV_MEMFILE_GET_SUBID_CLIENTID obtaining IPv4 lease for subnet ID %1 and client ID %2
 % DHCPSRV_MEMFILE_GET_SUBID_CLIENTID obtaining IPv4 lease for subnet ID %1 and client ID %2
 A debug message issued when the server is attempting to obtain an IPv4
 A debug message issued when the server is attempting to obtain an IPv4
 lease from the memory file database for a client with the specified
 lease from the memory file database for a client with the specified

+ 85 - 21
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -28,7 +28,8 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
 Memfile_LeaseMgr::~Memfile_LeaseMgr() {
 Memfile_LeaseMgr::~Memfile_LeaseMgr() {
 }
 }
 
 
-bool Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
+bool
+Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
               DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
 
 
@@ -40,7 +41,8 @@ bool Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
     return (true);
     return (true);
 }
 }
 
 
-bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
+bool
+Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
               DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
 
 
@@ -52,7 +54,8 @@ bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
     return (true);
     return (true);
 }
 }
 
 
-Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
               DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
 
 
@@ -66,15 +69,27 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) cons
     }
     }
 }
 }
 
 
-Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
+Lease4Collection
+Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
               DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
+    typedef Lease4Storage::nth_index<0>::type SearchIndex;
+    Lease4Collection collection;
+    const SearchIndex& idx = storage4_.get<0>();
+    for(SearchIndex::const_iterator lease = idx.begin();
+        lease != idx.end(); ++lease) {
+
+        // Every Lease4 has a hardware address, so we can compare it
+        if((* lease)->hwaddr_ == hwaddr.hwaddr_) {
+            collection.push_back((* lease));
+        }
+    }
 
 
-    isc_throw(NotImplemented, "getLease4(HWaddr x) method not implemented yet");
+    return (collection);
 }
 }
 
 
-Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr,
-                                      SubnetID subnet_id) const {
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
               DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
         .arg(hwaddr.toText());
         .arg(hwaddr.toText());
@@ -90,21 +105,65 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr,
         idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
         idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
     // Lease was not found. Return empty pointer to the caller.
     // Lease was not found. Return empty pointer to the caller.
     if (lease == idx.end()) {
     if (lease == idx.end()) {
-        return Lease4Ptr();
+        return (Lease4Ptr());
     }
     }
 
 
     // Lease was found. Return it to the caller.
     // Lease was found. Return it to the caller.
     return (Lease4Ptr(new Lease4(**lease)));
     return (Lease4Ptr(new Lease4(**lease)));
 }
 }
 
 
-Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& clientid) const {
+Lease4Collection
+Memfile_LeaseMgr::getLease4(const ClientId& clientid) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_CLIENTID).arg(clientid.toText());
               DHCPSRV_MEMFILE_GET_CLIENTID).arg(clientid.toText());
-    isc_throw(NotImplemented, "getLease4(ClientId) not implemented");
+    typedef Memfile_LeaseMgr::Lease4Storage::nth_index<0>::type SearchIndex;
+    Lease4Collection collection;
+    const SearchIndex& idx = storage4_.get<0>();
+    for(SearchIndex::const_iterator lease = idx.begin();
+        lease != idx.end(); ++ lease) {
+
+        // client-id is not mandatory in DHCPv4. There can be a lease that does
+        // not have a client-id. Dereferencing null pointer would be a bad thing
+        if((*lease)->client_id_ && *(*lease)->client_id_ == clientid) {
+            collection.push_back((* lease));
+        }
+    }
+
+    return (collection);
 }
 }
 
 
-Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId& client_id,
-                                      SubnetID subnet_id) const {
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const ClientId& client_id,
+                            const HWAddr& hwaddr,
+                            SubnetID subnet_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
+                                                        .arg(hwaddr.toText())
+                                                        .arg(subnet_id);
+
+    // We are going to use index #3 of the multi index container.
+    // We define SearchIndex locally in this function because
+    // currently only this function uses this index.
+    typedef Lease4Storage::nth_index<3>::type SearchIndex;
+    // Get the index.
+    const SearchIndex& idx = storage4_.get<3>();
+    // Try to get the lease using client id, hardware address and subnet id.
+    SearchIndex::const_iterator lease =
+        idx.find(boost::make_tuple(client_id.getClientId(), hwaddr.hwaddr_,
+                                   subnet_id));
+
+    if (lease == idx.end()) {
+        // Lease was not found. Return empty pointer to the caller.
+        return (Lease4Ptr());
+    }
+
+    // Lease was found. Return it to the caller.
+    return (*lease);
+}
+
+Lease4Ptr
+Memfile_LeaseMgr::getLease4(const ClientId& client_id,
+                            SubnetID subnet_id) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
               DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
               .arg(client_id.toText());
               .arg(client_id.toText());
@@ -120,7 +179,7 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId& client_id,
         idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
         idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
     // Lease was not found. Return empty pointer to the caller.
     // Lease was not found. Return empty pointer to the caller.
     if (lease == idx.end()) {
     if (lease == idx.end()) {
-        return Lease4Ptr();
+        return (Lease4Ptr());
     }
     }
     // Lease was found. Return it to the caller.
     // Lease was found. Return it to the caller.
     return (Lease4Ptr(new Lease4(**lease)));
     return (Lease4Ptr(new Lease4(**lease)));
@@ -139,16 +198,17 @@ Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
     }
     }
 }
 }
 
 
-Lease6Collection Memfile_LeaseMgr::getLease6(const DUID& duid,
-                                             uint32_t iaid) const {
+Lease6Collection
+Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_IAID_DUID).arg(iaid).arg(duid.toText());
               DHCPSRV_MEMFILE_GET_IAID_DUID).arg(iaid).arg(duid.toText());
 
 
     return (Lease6Collection());
     return (Lease6Collection());
 }
 }
 
 
-Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
-                                      SubnetID subnet_id) const {
+Lease6Ptr
+Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
+                            SubnetID subnet_id) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
               DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
               .arg(iaid).arg(subnet_id).arg(duid.toText());
               .arg(iaid).arg(subnet_id).arg(duid.toText());
@@ -170,7 +230,8 @@ Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
     return (Lease6Ptr(new Lease6(**lease)));
     return (Lease6Ptr(new Lease6(**lease)));
 }
 }
 
 
-void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
+void
+Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
               DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
 
 
@@ -182,7 +243,8 @@ void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
     **lease_it = *lease;
     **lease_it = *lease;
 }
 }
 
 
-void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
+void
+Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
               DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
 
 
@@ -194,7 +256,8 @@ void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
     **lease_it = *lease;
     **lease_it = *lease;
 }
 }
 
 
-bool Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
+bool
+Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
               DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
     if (addr.isV4()) {
     if (addr.isV4()) {
@@ -221,7 +284,8 @@ bool Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
     }
     }
 }
 }
 
 
-std::string Memfile_LeaseMgr::getDescription() const {
+std::string
+Memfile_LeaseMgr::getDescription() const {
     return (std::string("This is a dummy memfile backend implementation.\n"
     return (std::string("This is a dummy memfile backend implementation.\n"
                         "It does not offer any useful lease management and its only\n"
                         "It does not offer any useful lease management and its only\n"
                         "purpose is to test abstract lease manager API."));
                         "purpose is to test abstract lease manager API."));

+ 45 - 6
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -54,7 +54,6 @@ public:
 
 
     /// @brief Adds an IPv4 lease.
     /// @brief Adds an IPv4 lease.
     ///
     ///
-    /// @todo Not implemented yet
     /// @param lease lease to be added
     /// @param lease lease to be added
     virtual bool addLease(const Lease4Ptr& lease);
     virtual bool addLease(const Lease4Ptr& lease);
 
 
@@ -75,8 +74,6 @@ public:
 
 
     /// @brief Returns existing IPv4 leases for specified hardware address.
     /// @brief Returns existing IPv4 leases for specified hardware address.
     ///
     ///
-    /// @todo Not implemented yet
-    ///
     /// Although in the usual case there will be only one lease, for mobile
     /// Although in the usual case there will be only one lease, for mobile
     /// clients or clients with multiple static/fixed/reserved leases there
     /// clients or clients with multiple static/fixed/reserved leases there
     /// can be more than one. Thus return type is a container, not a single
     /// can be more than one. Thus return type is a container, not a single
@@ -105,11 +102,24 @@ public:
 
 
     /// @brief Returns existing IPv4 lease for specified client-id
     /// @brief Returns existing IPv4 lease for specified client-id
     ///
     ///
-    /// @todo Not implemented yet
-    ///
     /// @param clientid client identifier
     /// @param clientid client identifier
     virtual Lease4Collection getLease4(const ClientId& clientid) const;
     virtual Lease4Collection getLease4(const ClientId& clientid) const;
 
 
+    /// @brief Returns IPv4 lease for specified client-id/hwaddr/subnet-id tuple
+    ///
+    /// There can be at most one lease for a given client-id/hwaddr tuple
+    /// in a single pool, so this method with either return a single lease
+    /// or NULL.
+    ///
+    /// @param clientid client identifier
+    /// @param hwaddr hardware address of the client
+    /// @param subnet_id identifier of the subnet that lease must belong to
+    ///
+    /// @return a pointer to the lease (or NULL if a lease is not found)
+    virtual Lease4Ptr getLease4(const ClientId& clientid,
+                                const HWAddr& hwaddr,
+                                SubnetID subnet_id) const;
+
     /// @brief Returns existing IPv4 lease for specified client-id
     /// @brief Returns existing IPv4 lease for specified client-id
     ///
     ///
     /// This function returns a copy of the lease. The modification in the
     /// This function returns a copy of the lease. The modification in the
@@ -145,7 +155,7 @@ public:
     /// @return collection of IPv6 leases
     /// @return collection of IPv6 leases
     virtual Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
     virtual Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
 
 
-    /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+    /// @brief Returns existing IPv6 lease for a given DUID/IA/subnet-id tuple
     ///
     ///
     /// This function returns a copy of the lease. The modification in the
     /// This function returns a copy of the lease. The modification in the
     /// return lease does not affect the instance held in the lease storage.
     /// return lease does not affect the instance held in the lease storage.
@@ -332,6 +342,35 @@ protected:
                     // The subnet id is accessed through the subnet_id_ member.
                     // The subnet id is accessed through the subnet_id_ member.
                     boost::multi_index::member<Lease, uint32_t, &Lease::subnet_id_>
                     boost::multi_index::member<Lease, uint32_t, &Lease::subnet_id_>
                 >
                 >
+            >,
+
+            // Specification of the fourth index starts here.
+            boost::multi_index::ordered_unique<
+                // This is a composite index that uses two values to search for a
+                // lease: client id and subnet id.
+                boost::multi_index::composite_key<
+                    Lease4,
+                    // The client id value is not directly accessible through the
+                    // Lease4 object as it is wrapped with the ClientIdPtr object.
+                    // Therefore we use the KeyFromKeyExtractor class to access
+                    // client id through this cascaded structure. The client id
+                    // is used as an index value.
+                    KeyFromKeyExtractor<
+                        // Specify that the vector holding client id value can be obtained
+                        // from the ClientId object.
+                        boost::multi_index::const_mem_fun<ClientId, std::vector<uint8_t>,
+                                                          &ClientId::getClientId>,
+                        // Specify that the ClientId object (actually pointer to it) can
+                        // be accessed by the client_id_ member of Lease4 class.
+                        boost::multi_index::member<Lease4, ClientIdPtr, &Lease4::client_id_>
+                    >,
+                    // The hardware address is held in the hwaddr_ member of the
+                    // Lease4 object.
+                    boost::multi_index::member<Lease4, std::vector<uint8_t>,
+                                               &Lease4::hwaddr_>,
+                    // The subnet id is accessed through the subnet_id_ member.
+                    boost::multi_index::member<Lease, SubnetID, &Lease::subnet_id_>
+                >
             >
             >
         >
         >
     > Lease4Storage; // Specify the type name for this container.
     > Lease4Storage; // Specify the type name for this container.

+ 81 - 3
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -18,7 +18,7 @@
 #include <dhcp/duid.h>
 #include <dhcp/duid.h>
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/memfile_lease_mgr.h>
 #include <dhcpsrv/memfile_lease_mgr.h>
-
+#include <dhcpsrv/tests/test_utils.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 #include <iostream>
 #include <iostream>
@@ -28,10 +28,11 @@ using namespace std;
 using namespace isc;
 using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
+using namespace isc::dhcp::test;
 
 
 namespace {
 namespace {
 // empty class for now, but may be extended once Addr6 becomes bigger
 // empty class for now, but may be extended once Addr6 becomes bigger
-class MemfileLeaseMgrTest : public ::testing::Test {
+class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
 public:
 public:
     MemfileLeaseMgrTest() {
     MemfileLeaseMgrTest() {
     }
     }
@@ -130,6 +131,83 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
     EXPECT_EQ(Lease6Ptr(), x);
     EXPECT_EQ(Lease6Ptr(), x);
 }
 }
 
 
-// TODO: Write more memfile tests
+// @todo Write more memfile tests
+
+// Simple test about lease4 retrieval through client id method
+TEST_F(MemfileLeaseMgrTest, getLease4ClientId) {
+    const LeaseMgr::ParameterMap pmap;
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+    // Let's initialize a specific lease ...
+    Lease4Ptr lease = initializeLease4(straddress4_[1]);
+    EXPECT_TRUE(lease_mgr->addLease(lease));
+    Lease4Collection returned = lease_mgr->getLease4(*lease->client_id_);
+
+    ASSERT_EQ(1, returned.size());
+    // We should retrieve our lease...
+    detailCompareLease(lease, *returned.begin());
+    lease = initializeLease4(straddress4_[2]);
+    returned = lease_mgr->getLease4(*lease->client_id_);
+
+    ASSERT_EQ(0, returned.size());
+}
+
+// Checks that lease4 retrieval client id is null is working
+TEST_F(MemfileLeaseMgrTest, getLease4NullClientId) {
+    const LeaseMgr::ParameterMap pmap;
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+    // Let's initialize a specific lease ... But this time
+    // We keep its client id for further lookup and
+    // We clearly 'reset' it ...
+    Lease4Ptr lease = initializeLease4(straddress4_[4]);
+    ClientIdPtr client_id = lease->client_id_;
+    lease->client_id_ = ClientIdPtr();
+    EXPECT_TRUE(lease_mgr->addLease(lease));
+
+    Lease4Collection returned = lease_mgr->getLease4(*client_id);
+    // Shouldn't have our previous lease ...
+    ASSERT_EQ(0, returned.size());
+}
+
+// Checks lease4 retrieval through HWAddr
+TEST_F(MemfileLeaseMgrTest, getLease4HWAddr) {
+    const LeaseMgr::ParameterMap pmap;
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+    // Let's initialize two different leases 4 and just add the first ...
+    Lease4Ptr leaseA = initializeLease4(straddress4_[5]);
+    HWAddr hwaddrA(leaseA->hwaddr_, HTYPE_ETHER);
+    HWAddr hwaddrB(vector<uint8_t>(6, 0x80), HTYPE_ETHER);
+
+    EXPECT_TRUE(lease_mgr->addLease(leaseA));
+
+    // we should not have a lease, with this MAC Addr
+    Lease4Collection returned = lease_mgr->getLease4(hwaddrB);
+    ASSERT_EQ(0, returned.size());
+
+    // But with this one
+    returned = lease_mgr->getLease4(hwaddrA);
+    ASSERT_EQ(1, returned.size());
+}
+
+// Checks lease4 retrieval with clientId, HWAddr and subnet_id
+TEST_F(MemfileLeaseMgrTest, getLease4ClientIdHWAddrSubnetId) {
+    const LeaseMgr::ParameterMap pmap;
+    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+
+    Lease4Ptr leaseA = initializeLease4(straddress4_[4]);
+    Lease4Ptr leaseB = initializeLease4(straddress4_[5]);
+    HWAddr hwaddrA(leaseA->hwaddr_, HTYPE_ETHER);
+    HWAddr hwaddrB(leaseB->hwaddr_, HTYPE_ETHER);
+    EXPECT_TRUE(lease_mgr->addLease(leaseA));
+    // First case we should retrieve our lease
+    Lease4Ptr lease = lease_mgr->getLease4(*leaseA->client_id_, hwaddrA, leaseA->subnet_id_);
+    detailCompareLease(lease, leaseA);
+    lease = lease_mgr->getLease4(*leaseB->client_id_, hwaddrA, leaseA->subnet_id_);
+    detailCompareLease(lease, leaseA);
+    // But not the folowing, with different  hwaddr and subnet
+    lease = lease_mgr->getLease4(*leaseA->client_id_, hwaddrB, leaseA->subnet_id_);
+    EXPECT_TRUE(lease == Lease4Ptr());
+    lease = lease_mgr->getLease4(*leaseA->client_id_, hwaddrA, leaseB->subnet_id_);
+    EXPECT_TRUE(lease == Lease4Ptr());
+}
 
 
 }; // end of anonymous namespace
 }; // end of anonymous namespace

+ 2 - 387
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc

@@ -20,6 +20,7 @@
 #include <dhcpsrv/tests/test_utils.h>
 #include <dhcpsrv/tests/test_utils.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 
 
+
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 #include <algorithm>
 #include <algorithm>
@@ -39,18 +40,6 @@ namespace {
 // This holds statements to create and destroy the schema.
 // This holds statements to create and destroy the schema.
 #include "schema_copy.h"
 #include "schema_copy.h"
 
 
-// IPv4 and IPv6 addresses used in the tests
-const char* ADDRESS4[] = {
-    "192.0.2.0", "192.0.2.1", "192.0.2.2", "192.0.2.3",
-    "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7",
-    NULL
-};
-const char* ADDRESS6[] = {
-    "2001:db8::0", "2001:db8::1", "2001:db8::2", "2001:db8::3",
-    "2001:db8::4", "2001:db8::5", "2001:db8::6", "2001:db8::7",
-    NULL
-};
-
 // Connection strings.
 // Connection strings.
 // Database: keatest
 // Database: keatest
 // Host: localhost
 // Host: localhost
@@ -155,26 +144,12 @@ void createSchema() {
 /// Opens the database prior to each test and closes it afterwards.
 /// Opens the database prior to each test and closes it afterwards.
 /// All pending transactions are deleted prior to closure.
 /// All pending transactions are deleted prior to closure.
 
 
-class MySqlLeaseMgrTest : public ::testing::Test {
+class MySqlLeaseMgrTest : public GenericLeaseMgrTest {
 public:
 public:
     /// @brief Constructor
     /// @brief Constructor
     ///
     ///
     /// Deletes everything from the database and opens it.
     /// Deletes everything from the database and opens it.
     MySqlLeaseMgrTest() {
     MySqlLeaseMgrTest() {
-        // Initialize address strings and IOAddresses
-        for (int i = 0; ADDRESS4[i] != NULL; ++i) {
-            string addr(ADDRESS4[i]);
-            straddress4_.push_back(addr);
-            IOAddress ioaddr(addr);
-            ioaddress4_.push_back(ioaddr);
-        }
-
-        for (int i = 0; ADDRESS6[i] != NULL; ++i) {
-            string addr(ADDRESS6[i]);
-            straddress6_.push_back(addr);
-            IOAddress ioaddr(addr);
-            ioaddress6_.push_back(ioaddr);
-        }
 
 
         // Ensure schema is the correct one.
         // Ensure schema is the correct one.
         destroySchema();
         destroySchema();
@@ -214,361 +189,6 @@ public:
         lmptr_ = &(LeaseMgrFactory::instance());
         lmptr_ = &(LeaseMgrFactory::instance());
     }
     }
 
 
-    /// @brief Initialize Lease4 Fields
-    ///
-    /// Returns a pointer to a Lease4 structure.  Different values are put into
-    /// the lease according to the address passed.
-    ///
-    /// This is just a convenience function for the test methods.
-    ///
-    /// @param address Address to use for the initialization
-    ///
-    /// @return Lease4Ptr.  This will not point to anything if the
-    ///         initialization failed (e.g. unknown address).
-    Lease4Ptr initializeLease4(std::string address) {
-        Lease4Ptr lease(new Lease4());
-
-        // Set the address of the lease
-        lease->addr_ = IOAddress(address);
-
-        // Initialize unused fields.
-        lease->ext_ = 0;                            // Not saved
-        lease->t1_ = 0;                             // Not saved
-        lease->t2_ = 0;                             // Not saved
-        lease->fixed_ = false;                      // Unused
-        lease->comments_ = std::string("");         // Unused
-
-        // Set other parameters.  For historical reasons, address 0 is not used.
-        if (address == straddress4_[0]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x08);
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x42)));
-            lease->valid_lft_ = 8677;
-            lease->cltt_ = 168256;
-            lease->subnet_id_ = 23;
-            lease->fqdn_rev_ = true;
-            lease->fqdn_fwd_ = false;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress4_[1]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x19);
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x53)));
-            lease->valid_lft_ = 3677;
-            lease->cltt_ = 123456;
-            lease->subnet_id_ = 73;
-            lease->fqdn_rev_ = true;
-            lease->fqdn_fwd_ = true;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress4_[2]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x2a);
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x64)));
-            lease->valid_lft_ = 5412;
-            lease->cltt_ = 234567;
-            lease->subnet_id_ = 73;                         // Same as lease 1
-            lease->fqdn_rev_ = false;
-            lease->fqdn_fwd_ = false;
-            lease->hostname_ = "";
-
-        } else if (address == straddress4_[3]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x19);      // Same as lease 1
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x75)));
-
-            // The times used in the next tests are deliberately restricted - we
-            // should be able to cope with valid lifetimes up to 0xffffffff.
-            //  However, this will lead to overflows.
-            // @TODO: test overflow conditions when code has been fixed
-            lease->valid_lft_ = 7000;
-            lease->cltt_ = 234567;
-            lease->subnet_id_ = 37;
-            lease->fqdn_rev_ = true;
-            lease->fqdn_fwd_ = true;
-            lease->hostname_ = "otherhost.example.com.";
-
-        } else if (address == straddress4_[4]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x4c);
-            // Same ClientId as straddr4_[1]
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x53)));    // Same as lease 1
-            lease->valid_lft_ = 7736;
-            lease->cltt_ = 222456;
-            lease->subnet_id_ = 85;
-            lease->fqdn_rev_ = true;
-            lease->fqdn_fwd_ = true;
-            lease->hostname_ = "otherhost.example.com.";
-
-        } else if (address == straddress4_[5]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x19);      // Same as lease 1
-            // Same ClientId and IAID as straddress4_1
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x53)));    // Same as lease 1
-            lease->valid_lft_ = 7832;
-            lease->cltt_ = 227476;
-            lease->subnet_id_ = 175;
-            lease->fqdn_rev_ = false;
-            lease->fqdn_fwd_ = false;
-            lease->hostname_ = "otherhost.example.com.";
-
-        } else if (address == straddress4_[6]) {
-            lease->hwaddr_ = vector<uint8_t>(6, 0x6e);
-            // Same ClientId as straddress4_1
-            lease->client_id_ = ClientIdPtr(
-                new ClientId(vector<uint8_t>(8, 0x53)));    // Same as lease 1
-            lease->valid_lft_ = 1832;
-            lease->cltt_ = 627476;
-            lease->subnet_id_ = 112;
-            lease->fqdn_rev_ = false;
-            lease->fqdn_fwd_ = true;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress4_[7]) {
-            lease->hwaddr_ = vector<uint8_t>();             // Empty
-            lease->client_id_ = ClientIdPtr();              // Empty
-            lease->valid_lft_ = 7975;
-            lease->cltt_ = 213876;
-            lease->subnet_id_ = 19;
-            lease->fqdn_rev_ = true;
-            lease->fqdn_fwd_ = true;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else {
-            // Unknown address, return an empty pointer.
-            lease.reset();
-
-        }
-
-        return (lease);
-    }
-
-    /// @brief Initialize Lease6 Fields
-    ///
-    /// Returns a pointer to a Lease6 structure.  Different values are put into
-    /// the lease according to the address passed.
-    ///
-    /// This is just a convenience function for the test methods.
-    ///
-    /// @param address Address to use for the initialization
-    ///
-    /// @return Lease6Ptr.  This will not point to anything if the initialization
-    ///         failed (e.g. unknown address).
-    Lease6Ptr initializeLease6(std::string address) {
-        Lease6Ptr lease(new Lease6());
-
-        // Set the address of the lease
-        lease->addr_ = IOAddress(address);
-
-        // Initialize unused fields.
-        lease->t1_ = 0;                             // Not saved
-        lease->t2_ = 0;                             // Not saved
-        lease->fixed_ = false;                      // Unused
-        lease->comments_ = std::string("");         // Unused
-
-        // Set other parameters.  For historical reasons, address 0 is not used.
-        if (address == straddress6_[0]) {
-            lease->type_ = Lease6::LEASE_IA_TA;
-            lease->prefixlen_ = 4;
-            lease->iaid_ = 142;
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x77)));
-            lease->preferred_lft_ = 900;
-            lease->valid_lft_ = 8677;
-            lease->cltt_ = 168256;
-            lease->subnet_id_ = 23;
-            lease->fqdn_fwd_ = true;
-            lease->fqdn_rev_ = true;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress6_[1]) {
-            lease->type_ = Lease6::LEASE_IA_TA;
-            lease->prefixlen_ = 0;
-            lease->iaid_ = 42;
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
-            lease->preferred_lft_ = 3600;
-            lease->valid_lft_ = 3677;
-            lease->cltt_ = 123456;
-            lease->subnet_id_ = 73;
-            lease->fqdn_fwd_ = false;
-            lease->fqdn_rev_ = true;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress6_[2]) {
-            lease->type_ = Lease6::LEASE_IA_PD;
-            lease->prefixlen_ = 7;
-            lease->iaid_ = 89;
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x3a)));
-            lease->preferred_lft_ = 1800;
-            lease->valid_lft_ = 5412;
-            lease->cltt_ = 234567;
-            lease->subnet_id_ = 73;                     // Same as lease 1
-            lease->fqdn_fwd_ = false;
-            lease->fqdn_rev_ = false;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress6_[3]) {
-            lease->type_ = Lease6::LEASE_IA_NA;
-            lease->prefixlen_ = 28;
-            lease->iaid_ = 0xfffffffe;
-            vector<uint8_t> duid;
-            for (uint8_t i = 31; i < 126; ++i) {
-                duid.push_back(i);
-            }
-            lease->duid_ = DuidPtr(new DUID(duid));
-
-            // The times used in the next tests are deliberately restricted - we
-            // should be able to cope with valid lifetimes up to 0xffffffff.
-            //  However, this will lead to overflows.
-            // @TODO: test overflow conditions when code has been fixed
-            lease->preferred_lft_ = 7200;
-            lease->valid_lft_ = 7000;
-            lease->cltt_ = 234567;
-            lease->subnet_id_ = 37;
-            lease->fqdn_fwd_ = true;
-            lease->fqdn_rev_ = false;
-            lease->hostname_ = "myhost.example.com.";
-
-        } else if (address == straddress6_[4]) {
-            // Same DUID and IAID as straddress6_1
-            lease->type_ = Lease6::LEASE_IA_PD;
-            lease->prefixlen_ = 15;
-            lease->iaid_ = 42;
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
-            lease->preferred_lft_ = 4800;
-            lease->valid_lft_ = 7736;
-            lease->cltt_ = 222456;
-            lease->subnet_id_ = 671;
-            lease->fqdn_fwd_ = true;
-            lease->fqdn_rev_ = true;
-            lease->hostname_ = "otherhost.example.com.";
-
-        } else if (address == straddress6_[5]) {
-            // Same DUID and IAID as straddress6_1
-            lease->type_ = Lease6::LEASE_IA_PD;
-            lease->prefixlen_ = 24;
-            lease->iaid_ = 42;                          // Same as lease 4
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
-                                                        // Same as lease 4
-            lease->preferred_lft_ = 5400;
-            lease->valid_lft_ = 7832;
-            lease->cltt_ = 227476;
-            lease->subnet_id_ = 175;
-            lease->fqdn_fwd_ = false;
-            lease->fqdn_rev_ = true;
-            lease->hostname_ = "hostname.example.com.";
-
-        } else if (address == straddress6_[6]) {
-            // Same DUID as straddress6_1
-            lease->type_ = Lease6::LEASE_IA_PD;
-            lease->prefixlen_ = 24;
-            lease->iaid_ = 93;
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
-                                                        // Same as lease 4
-            lease->preferred_lft_ = 5400;
-            lease->valid_lft_ = 1832;
-            lease->cltt_ = 627476;
-            lease->subnet_id_ = 112;
-            lease->fqdn_fwd_ = false;
-            lease->fqdn_rev_ = true;
-            lease->hostname_ = "hostname.example.com.";
-
-        } else if (address == straddress6_[7]) {
-            // Same IAID as straddress6_1
-            lease->type_ = Lease6::LEASE_IA_PD;
-            lease->prefixlen_ = 24;
-            lease->iaid_ = 42;
-            lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0xe5)));
-            lease->preferred_lft_ = 5600;
-            lease->valid_lft_ = 7975;
-            lease->cltt_ = 213876;
-            lease->subnet_id_ = 19;
-            lease->fqdn_fwd_ = false;
-            lease->fqdn_rev_ = true;
-            lease->hostname_ = "hostname.example.com.";
-
-        } else {
-            // Unknown address, return an empty pointer.
-            lease.reset();
-
-        }
-
-        return (lease);
-    }
-
-    /// @brief Check Leases present and different
-    ///
-    /// Checks a vector of lease pointers and ensures that all the leases
-    /// they point to are present and different.  If not, a GTest assertion
-    /// will fail.
-    ///
-    /// @param leases Vector of pointers to leases
-    template <typename T>
-    void checkLeasesDifferent(const std::vector<T>& leases) const {
-
-        // Check they were created
-        for (int i = 0; i < leases.size(); ++i) {
-            ASSERT_TRUE(leases[i]);
-        }
-
-        // Check they are different
-        for (int i = 0; i < (leases.size() - 1); ++i) {
-            for (int j = (i + 1); j < leases.size(); ++j) {
-                stringstream s;
-                s << "Comparing leases " << i << " & " << j << " for equality";
-                SCOPED_TRACE(s.str());
-                EXPECT_TRUE(*leases[i] != *leases[j]);
-            }
-        }
-    }
-
-    /// @brief Creates leases for the test
-    ///
-    /// Creates all leases for the test and checks that they are different.
-    ///
-    /// @return vector<Lease4Ptr> Vector of pointers to leases
-    vector<Lease4Ptr> createLeases4() {
-
-        // Create leases for each address
-        vector<Lease4Ptr> leases;
-        for (int i = 0; i < straddress4_.size(); ++i) {
-            leases.push_back(initializeLease4(straddress4_[i]));
-        }
-        EXPECT_EQ(8, leases.size());
-
-        // Check all were created and that they are different.
-        checkLeasesDifferent(leases);
-
-        return (leases);
-    }
-
-    /// @brief Creates leases for the test
-    ///
-    /// Creates all leases for the test and checks that they are different.
-    ///
-    /// @return vector<Lease6Ptr> Vector of pointers to leases
-    vector<Lease6Ptr> createLeases6() {
-
-        // Create leases for each address
-        vector<Lease6Ptr> leases;
-        for (int i = 0; i < straddress6_.size(); ++i) {
-            leases.push_back(initializeLease6(straddress6_[i]));
-        }
-        EXPECT_EQ(8, leases.size());
-
-        // Check all were created and that they are different.
-        checkLeasesDifferent(leases);
-
-        return (leases);
-    }
-
-
-    // Member variables
-
-    LeaseMgr*   lmptr_;             ///< Pointer to the lease manager
-    vector<string>  straddress4_;   ///< String forms of IPv4 addresses
-    vector<IOAddress> ioaddress4_;  ///< IOAddress forms of IPv4 addresses
-    vector<string>  straddress6_;   ///< String forms of IPv6 addresses
-    vector<IOAddress> ioaddress6_;  ///< IOAddress forms of IPv6 addresses
 };
 };
 
 
 /// @brief Check that database can be opened
 /// @brief Check that database can be opened
@@ -1051,11 +671,6 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
                                              leases[1]->subnet_id_),
                                              leases[1]->subnet_id_),
                  isc::dhcp::MultipleRecords);
                  isc::dhcp::MultipleRecords);
 
 
-    // Delete all leases in the database
-    for (int i = 0; ADDRESS4[i] != NULL; ++i) {
-        IOAddress addr(ADDRESS4[i]);
-        (void) lmptr_->deleteLease(addr);
-    }
 }
 }
 
 
 // @brief Get lease4 by hardware address and subnet ID (2)
 // @brief Get lease4 by hardware address and subnet ID (2)

+ 384 - 0
src/lib/dhcpsrv/tests/test_utils.cc

@@ -13,12 +13,29 @@
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
 #include "test_utils.h"
 #include "test_utils.h"
+#include <asiolink/io_address.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
+#include <sstream>
+
+using namespace std;
+using namespace isc::asiolink;
 
 
 namespace isc {
 namespace isc {
 namespace dhcp {
 namespace dhcp {
 namespace test {
 namespace test {
 
 
+// IPv4 and IPv6 addresses used in the tests
+const char* ADDRESS4[] = {
+    "192.0.2.0", "192.0.2.1", "192.0.2.2", "192.0.2.3",
+    "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7",
+    NULL
+};
+const char* ADDRESS6[] = {
+    "2001:db8::0", "2001:db8::1", "2001:db8::2", "2001:db8::3",
+    "2001:db8::4", "2001:db8::5", "2001:db8::6", "2001:db8::7",
+    NULL
+};
+
 void
 void
 detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second) {
 detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second) {
     // Compare address strings.  Comparison of address objects is not used, as
     // Compare address strings.  Comparison of address objects is not used, as
@@ -75,6 +92,373 @@ detailCompareLease(const Lease6Ptr& first, const Lease6Ptr& second) {
     EXPECT_EQ(first->hostname_, second->hostname_);
     EXPECT_EQ(first->hostname_, second->hostname_);
 }
 }
 
 
+
+GenericLeaseMgrTest::GenericLeaseMgrTest()
+    :lmptr_(NULL) {
+    // Initialize address strings and IOAddresses
+    for (int i = 0; ADDRESS4[i] != NULL; ++i) {
+        string addr(ADDRESS4[i]);
+        straddress4_.push_back(addr);
+        IOAddress ioaddr(addr);
+        ioaddress4_.push_back(ioaddr);
+    }
+
+    for (int i = 0; ADDRESS6[i] != NULL; ++i) {
+        string addr(ADDRESS6[i]);
+        straddress6_.push_back(addr);
+        IOAddress ioaddr(addr);
+        ioaddress6_.push_back(ioaddr);
+    }
+}
+
+/// @brief Initialize Lease4 Fields
+///
+/// Returns a pointer to a Lease4 structure.  Different values are put into
+/// the lease according to the address passed.
+///
+/// This is just a convenience function for the test methods.
+///
+/// @param address Address to use for the initialization
+///
+/// @return Lease4Ptr.  This will not point to anything if the
+///         initialization failed (e.g. unknown address).
+Lease4Ptr
+GenericLeaseMgrTest::initializeLease4(std::string address) {
+    Lease4Ptr lease(new Lease4());
+
+    // Set the address of the lease
+    lease->addr_ = IOAddress(address);
+
+    // Initialize unused fields.
+    lease->ext_ = 0;                            // Not saved
+    lease->t1_ = 0;                             // Not saved
+    lease->t2_ = 0;                             // Not saved
+    lease->fixed_ = false;                      // Unused
+    lease->comments_ = std::string("");         // Unused
+
+    // Set other parameters.  For historical reasons, address 0 is not used.
+    if (address == straddress4_[0]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x08);
+        lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x42)));
+        lease->valid_lft_ = 8677;
+        lease->cltt_ = 168256;
+        lease->subnet_id_ = 23;
+        lease->fqdn_rev_ = true;
+        lease->fqdn_fwd_ = false;
+        lease->hostname_ = "myhost.example.com.";
+
+        } else if (address == straddress4_[1]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x19);
+        lease->client_id_ = ClientIdPtr(
+            new ClientId(vector<uint8_t>(8, 0x53)));
+        lease->valid_lft_ = 3677;
+        lease->cltt_ = 123456;
+        lease->subnet_id_ = 73;
+        lease->fqdn_rev_ = true;
+        lease->fqdn_fwd_ = true;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else if (address == straddress4_[2]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x2a);
+        lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x64)));
+        lease->valid_lft_ = 5412;
+        lease->cltt_ = 234567;
+        lease->subnet_id_ = 73;                         // Same as lease 1
+        lease->fqdn_rev_ = false;
+        lease->fqdn_fwd_ = false;
+        lease->hostname_ = "";
+
+    } else if (address == straddress4_[3]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x19);      // Same as lease 1
+        lease->client_id_ = ClientIdPtr(
+            new ClientId(vector<uint8_t>(8, 0x75)));
+
+        // The times used in the next tests are deliberately restricted - we
+        // should be able to cope with valid lifetimes up to 0xffffffff.
+        //  However, this will lead to overflows.
+        // @TODO: test overflow conditions when code has been fixed
+        lease->valid_lft_ = 7000;
+        lease->cltt_ = 234567;
+        lease->subnet_id_ = 37;
+        lease->fqdn_rev_ = true;
+        lease->fqdn_fwd_ = true;
+        lease->hostname_ = "otherhost.example.com.";
+
+    } else if (address == straddress4_[4]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x4c);
+        // Same ClientId as straddr4_[1]
+        lease->client_id_ = ClientIdPtr(
+            new ClientId(vector<uint8_t>(8, 0x53)));    // Same as lease 1
+        lease->valid_lft_ = 7736;
+        lease->cltt_ = 222456;
+        lease->subnet_id_ = 85;
+        lease->fqdn_rev_ = true;
+        lease->fqdn_fwd_ = true;
+        lease->hostname_ = "otherhost.example.com.";
+
+    } else if (address == straddress4_[5]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x19);      // Same as lease 1
+        // Same ClientId and IAID as straddress4_1
+        lease->client_id_ = ClientIdPtr(
+            new ClientId(vector<uint8_t>(8, 0x53)));    // Same as lease 1
+        lease->valid_lft_ = 7832;
+        lease->cltt_ = 227476;
+        lease->subnet_id_ = 175;
+        lease->fqdn_rev_ = false;
+        lease->fqdn_fwd_ = false;
+        lease->hostname_ = "otherhost.example.com.";
+        } else if (address == straddress4_[6]) {
+        lease->hwaddr_ = vector<uint8_t>(6, 0x6e);
+        // Same ClientId as straddress4_1
+        lease->client_id_ = ClientIdPtr(
+            new ClientId(vector<uint8_t>(8, 0x53)));    // Same as lease 1
+        lease->valid_lft_ = 1832;
+        lease->cltt_ = 627476;
+        lease->subnet_id_ = 112;
+        lease->fqdn_rev_ = false;
+        lease->fqdn_fwd_ = true;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else if (address == straddress4_[7]) {
+        lease->hwaddr_ = vector<uint8_t>();             // Empty
+        lease->client_id_ = ClientIdPtr();              // Empty
+        lease->valid_lft_ = 7975;
+        lease->cltt_ = 213876;
+        lease->subnet_id_ = 19;
+        lease->fqdn_rev_ = true;
+        lease->fqdn_fwd_ = true;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else {
+        // Unknown address, return an empty pointer.
+        lease.reset();
+
+    }
+
+    return (lease);
+}
+
+/// @brief Initialize Lease6 Fields
+///
+/// Returns a pointer to a Lease6 structure.  Different values are put into
+/// the lease according to the address passed.
+///
+/// This is just a convenience function for the test methods.
+///
+/// @param address Address to use for the initialization
+///
+/// @return Lease6Ptr.  This will not point to anything if the initialization
+///         failed (e.g. unknown address).
+Lease6Ptr
+GenericLeaseMgrTest::initializeLease6(std::string address) {
+    Lease6Ptr lease(new Lease6());
+
+    // Set the address of the lease
+    lease->addr_ = IOAddress(address);
+
+    // Initialize unused fields.
+    lease->t1_ = 0;                             // Not saved
+    lease->t2_ = 0;                             // Not saved
+    lease->fixed_ = false;                      // Unused
+    lease->comments_ = std::string("");         // Unused
+
+    // Set other parameters.  For historical reasons, address 0 is not used.
+    if (address == straddress6_[0]) {
+        lease->type_ = Lease6::LEASE_IA_TA;
+        lease->prefixlen_ = 4;
+        lease->iaid_ = 142;
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x77)));
+        lease->preferred_lft_ = 900;
+        lease->valid_lft_ = 8677;
+        lease->cltt_ = 168256;
+        lease->subnet_id_ = 23;
+        lease->fqdn_fwd_ = true;
+        lease->fqdn_rev_ = true;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else if (address == straddress6_[1]) {
+        lease->type_ = Lease6::LEASE_IA_TA;
+        lease->prefixlen_ = 0;
+        lease->iaid_ = 42;
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
+        lease->preferred_lft_ = 3600;
+        lease->valid_lft_ = 3677;
+        lease->cltt_ = 123456;
+        lease->subnet_id_ = 73;
+        lease->fqdn_fwd_ = false;
+        lease->fqdn_rev_ = true;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else if (address == straddress6_[2]) {
+        lease->type_ = Lease6::LEASE_IA_PD;
+        lease->prefixlen_ = 7;
+        lease->iaid_ = 89;
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x3a)));
+        lease->preferred_lft_ = 1800;
+        lease->valid_lft_ = 5412;
+        lease->cltt_ = 234567;
+        lease->subnet_id_ = 73;                     // Same as lease 1
+        lease->fqdn_fwd_ = false;
+        lease->fqdn_rev_ = false;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else if (address == straddress6_[3]) {
+        lease->type_ = Lease6::LEASE_IA_NA;
+        lease->prefixlen_ = 28;
+        lease->iaid_ = 0xfffffffe;
+        vector<uint8_t> duid;
+        for (uint8_t i = 31; i < 126; ++i) {
+            duid.push_back(i);
+        }
+        lease->duid_ = DuidPtr(new DUID(duid));
+
+        // The times used in the next tests are deliberately restricted - we
+        // should be able to cope with valid lifetimes up to 0xffffffff.
+        //  However, this will lead to overflows.
+        // @TODO: test overflow conditions when code has been fixed
+        lease->preferred_lft_ = 7200;
+        lease->valid_lft_ = 7000;
+        lease->cltt_ = 234567;
+        lease->subnet_id_ = 37;
+        lease->fqdn_fwd_ = true;
+        lease->fqdn_rev_ = false;
+        lease->hostname_ = "myhost.example.com.";
+
+    } else if (address == straddress6_[4]) {
+        // Same DUID and IAID as straddress6_1
+        lease->type_ = Lease6::LEASE_IA_PD;
+        lease->prefixlen_ = 15;
+        lease->iaid_ = 42;
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
+        lease->preferred_lft_ = 4800;
+        lease->valid_lft_ = 7736;
+        lease->cltt_ = 222456;
+        lease->subnet_id_ = 671;
+        lease->fqdn_fwd_ = true;
+        lease->fqdn_rev_ = true;
+        lease->hostname_ = "otherhost.example.com.";
+
+    } else if (address == straddress6_[5]) {
+        // Same DUID and IAID as straddress6_1
+        lease->type_ = Lease6::LEASE_IA_PD;
+        lease->prefixlen_ = 24;
+        lease->iaid_ = 42;                          // Same as lease 4
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
+        // Same as lease 4
+        lease->preferred_lft_ = 5400;
+        lease->valid_lft_ = 7832;
+        lease->cltt_ = 227476;
+        lease->subnet_id_ = 175;
+        lease->fqdn_fwd_ = false;
+        lease->fqdn_rev_ = true;
+        lease->hostname_ = "hostname.example.com.";
+
+    } else if (address == straddress6_[6]) {
+        // Same DUID as straddress6_1
+        lease->type_ = Lease6::LEASE_IA_PD;
+        lease->prefixlen_ = 24;
+        lease->iaid_ = 93;
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
+        // Same as lease 4
+        lease->preferred_lft_ = 5400;
+        lease->valid_lft_ = 1832;
+        lease->cltt_ = 627476;
+        lease->subnet_id_ = 112;
+        lease->fqdn_fwd_ = false;
+        lease->fqdn_rev_ = true;
+        lease->hostname_ = "hostname.example.com.";
+
+    } else if (address == straddress6_[7]) {
+        // Same IAID as straddress6_1
+        lease->type_ = Lease6::LEASE_IA_PD;
+        lease->prefixlen_ = 24;
+        lease->iaid_ = 42;
+        lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0xe5)));
+        lease->preferred_lft_ = 5600;
+        lease->valid_lft_ = 7975;
+        lease->cltt_ = 213876;
+        lease->subnet_id_ = 19;
+        lease->fqdn_fwd_ = false;
+        lease->fqdn_rev_ = true;
+        lease->hostname_ = "hostname.example.com.";
+
+    } else {
+        // Unknown address, return an empty pointer.
+        lease.reset();
+
+    }
+
+    return (lease);
+}
+
+/// @brief Check Leases present and different
+///
+/// Checks a vector of lease pointers and ensures that all the leases
+/// they point to are present and different.  If not, a GTest assertion
+/// will fail.
+///
+/// @param leases Vector of pointers to leases
+template <typename T>
+void GenericLeaseMgrTest::checkLeasesDifferent(const std::vector<T>& leases) const {
+
+    // Check they were created
+    for (int i = 0; i < leases.size(); ++i) {
+        ASSERT_TRUE(leases[i]);
+    }
+
+    // Check they are different
+    for (int i = 0; i < (leases.size() - 1); ++i) {
+        for (int j = (i + 1); j < leases.size(); ++j) {
+            stringstream s;
+            s << "Comparing leases " << i << " & " << j << " for equality";
+            SCOPED_TRACE(s.str());
+            EXPECT_TRUE(*leases[i] != *leases[j]);
+        }
+    }
+}
+
+/// @brief Creates leases for the test
+///
+/// Creates all leases for the test and checks that they are different.
+///
+/// @return vector<Lease4Ptr> Vector of pointers to leases
+vector<Lease4Ptr>
+GenericLeaseMgrTest::createLeases4() {
+
+    // Create leases for each address
+    vector<Lease4Ptr> leases;
+    for (int i = 0; i < straddress4_.size(); ++i) {
+        leases.push_back(initializeLease4(straddress4_[i]));
+    }
+    EXPECT_EQ(8, leases.size());
+
+    // Check all were created and that they are different.
+    checkLeasesDifferent(leases);
+
+    return (leases);
+}
+
+/// @brief Creates leases for the test
+///
+/// Creates all leases for the test and checks that they are different.
+///
+/// @return vector<Lease6Ptr> Vector of pointers to leases
+vector<Lease6Ptr>
+GenericLeaseMgrTest::createLeases6() {
+
+    // Create leases for each address
+    vector<Lease6Ptr> leases;
+    for (int i = 0; i < straddress6_.size(); ++i) {
+        leases.push_back(initializeLease6(straddress6_[i]));
+    }
+    EXPECT_EQ(8, leases.size());
+
+    // Check all were created and that they are different.
+    checkLeasesDifferent(leases);
+
+    return (leases);
+}
+
 };
 };
 };
 };
 };
 };

+ 68 - 0
src/lib/dhcpsrv/tests/test_utils.h

@@ -16,6 +16,8 @@
 #define LIBDHCPSRV_TEST_UTILS_H
 #define LIBDHCPSRV_TEST_UTILS_H
 
 
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/lease_mgr.h>
+#include <gtest/gtest.h>
+#include <vector>
 
 
 namespace isc {
 namespace isc {
 namespace dhcp {
 namespace dhcp {
@@ -41,6 +43,72 @@ detailCompareLease(const Lease6Ptr& first, const Lease6Ptr& second);
 void
 void
 detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second);
 detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second);
 
 
+/// @brief Test Fixture class with utility functions for LeaseMgr backends
+///
+/// It contains utility functions, like dummy lease creation.
+/// All concrete LeaseMgr test classes should be derived from it.
+class GenericLeaseMgrTest : public ::testing::Test {
+public:
+    GenericLeaseMgrTest();
+
+    /// @brief Initialize Lease4 Fields
+    ///
+    /// Returns a pointer to a Lease4 structure.  Different values are put into
+    /// the lease according to the address passed.
+    ///
+    /// This is just a convenience function for the test methods.
+    ///
+    /// @param address Address to use for the initialization
+    ///
+    /// @return Lease4Ptr.  This will not point to anything if the
+    ///         initialization failed (e.g. unknown address).
+    Lease4Ptr initializeLease4(std::string address);
+
+    /// @brief Initialize Lease6 Fields
+    ///
+    /// Returns a pointer to a Lease6 structure.  Different values are put into
+    /// the lease according to the address passed.
+    ///
+    /// This is just a convenience function for the test methods.
+    ///
+    /// @param address Address to use for the initialization
+    ///
+    /// @return Lease6Ptr.  This will not point to anything if the initialization
+    ///         failed (e.g. unknown address).
+    Lease6Ptr initializeLease6(std::string address);
+
+    /// @brief Check Leases present and different
+    ///
+    /// Checks a vector of lease pointers and ensures that all the leases
+    /// they point to are present and different.  If not, a GTest assertion
+    /// will fail.
+    ///
+    /// @param leases Vector of pointers to leases
+    template <typename T>
+        void checkLeasesDifferent(const std::vector<T>& leases) const;
+
+    /// @brief Creates leases for the test
+    ///
+    /// Creates all leases for the test and checks that they are different.
+    ///
+    /// @return vector<Lease4Ptr> Vector of pointers to leases
+    std::vector<Lease4Ptr> createLeases4();
+
+    /// @brief Creates leases for the test
+    ///
+    /// Creates all leases for the test and checks that they are different.
+    ///
+    /// @return vector<Lease6Ptr> Vector of pointers to leases
+    std::vector<Lease6Ptr> createLeases6();
+
+    // Member variables
+    std::vector<std::string>  straddress4_;   ///< String forms of IPv4 addresses
+    std::vector<isc::asiolink::IOAddress> ioaddress4_;  ///< IOAddress forms of IPv4 addresses
+    std::vector<std::string>  straddress6_;   ///< String forms of IPv6 addresses
+    std::vector<isc::asiolink::IOAddress> ioaddress6_;  ///< IOAddress forms of IPv6 addresses
+
+    LeaseMgr*   lmptr_;             ///< Pointer to the lease manager
+};
 
 
 };
 };
 };
 };