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
 	libdhcpsrv: Added support to MySQL lease database backend to
 	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);
 
     // 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
     l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
     EXPECT_FALSE(l);
 
     // 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
     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
 (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
 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

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

@@ -28,7 +28,8 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
 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,
               DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
 
@@ -40,7 +41,8 @@ bool Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
     return (true);
 }
 
-bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
+bool
+Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
 
@@ -52,7 +54,8 @@ bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
     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,
               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,
               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,
               DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
         .arg(hwaddr.toText());
@@ -90,21 +105,65 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr,
         idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
     // Lease was not found. Return empty pointer to the caller.
     if (lease == idx.end()) {
-        return Lease4Ptr();
+        return (Lease4Ptr());
     }
 
     // Lease was found. Return it to the caller.
     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,
               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,
               DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
               .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));
     // Lease was not found. Return empty pointer to the caller.
     if (lease == idx.end()) {
-        return Lease4Ptr();
+        return (Lease4Ptr());
     }
     // Lease was found. Return it to the caller.
     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,
               DHCPSRV_MEMFILE_GET_IAID_DUID).arg(iaid).arg(duid.toText());
 
     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,
               DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
               .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)));
 }
 
-void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
+void
+Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
 
@@ -182,7 +243,8 @@ void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& 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,
               DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
 
@@ -194,7 +256,8 @@ void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& 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,
               DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
     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"
                         "It does not offer any useful lease management and its only\n"
                         "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.
     ///
-    /// @todo Not implemented yet
     /// @param lease lease to be added
     virtual bool addLease(const Lease4Ptr& lease);
 
@@ -75,8 +74,6 @@ public:
 
     /// @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
     /// clients or clients with multiple static/fixed/reserved leases there
     /// 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
     ///
-    /// @todo Not implemented yet
-    ///
     /// @param clientid client identifier
     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
     ///
     /// This function returns a copy of the lease. The modification in the
@@ -145,7 +155,7 @@ public:
     /// @return collection of IPv6 leases
     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
     /// 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.
                     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.

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

@@ -18,7 +18,7 @@
 #include <dhcp/duid.h>
 #include <dhcpsrv/lease_mgr.h>
 #include <dhcpsrv/memfile_lease_mgr.h>
-
+#include <dhcpsrv/tests/test_utils.h>
 #include <gtest/gtest.h>
 
 #include <iostream>
@@ -28,10 +28,11 @@ using namespace std;
 using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
+using namespace isc::dhcp::test;
 
 namespace {
 // empty class for now, but may be extended once Addr6 becomes bigger
-class MemfileLeaseMgrTest : public ::testing::Test {
+class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
 public:
     MemfileLeaseMgrTest() {
     }
@@ -130,6 +131,83 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
     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

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

@@ -20,6 +20,7 @@
 #include <dhcpsrv/tests/test_utils.h>
 #include <exceptions/exceptions.h>
 
+
 #include <gtest/gtest.h>
 
 #include <algorithm>
@@ -39,18 +40,6 @@ namespace {
 // This holds statements to create and destroy the schema.
 #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.
 // Database: keatest
 // Host: localhost
@@ -155,26 +144,12 @@ void createSchema() {
 /// Opens the database prior to each test and closes it afterwards.
 /// All pending transactions are deleted prior to closure.
 
-class MySqlLeaseMgrTest : public ::testing::Test {
+class MySqlLeaseMgrTest : public GenericLeaseMgrTest {
 public:
     /// @brief Constructor
     ///
     /// Deletes everything from the database and opens it.
     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.
         destroySchema();
@@ -214,361 +189,6 @@ public:
         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
@@ -1051,11 +671,6 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
                                              leases[1]->subnet_id_),
                  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)

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

@@ -13,12 +13,29 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include "test_utils.h"
+#include <asiolink/io_address.h>
 #include <gtest/gtest.h>
+#include <sstream>
+
+using namespace std;
+using namespace isc::asiolink;
 
 namespace isc {
 namespace dhcp {
 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
 detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second) {
     // 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_);
 }
 
+
+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
 
 #include <dhcpsrv/lease_mgr.h>
+#include <gtest/gtest.h>
+#include <vector>
 
 namespace isc {
 namespace dhcp {
@@ -41,6 +43,72 @@ detailCompareLease(const Lease6Ptr& first, const Lease6Ptr& second);
 void
 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
+};
 
 };
 };