Browse Source

[3965] Implemented functions to retrieve expired leases.

Marcin Siodelski 9 years ago
parent
commit
6d3b534e02

+ 27 - 1
src/lib/dhcpsrv/lease_mgr.h

@@ -291,7 +291,6 @@ public:
     virtual Lease6Collection getLeases6(Lease::Type type, const DUID& duid,
                                         uint32_t iaid, SubnetID subnet_id) const = 0;
 
-
     /// @brief returns zero or one IPv6 lease for a given duid+iaid+subnet_id
     ///
     /// This function is mostly intended to be used in unit-tests during the
@@ -318,6 +317,33 @@ public:
     Lease6Ptr getLease6(Lease::Type type, const DUID& duid,
                         uint32_t iaid, SubnetID subnet_id) const;
 
+    /// @brief Returns a collection of expired DHCPv6 leases.
+    ///
+    /// This method returns at most @c max_leases expired leases. The leases
+    /// returned haven't been reclaimed, i.e. the database query must exclude
+    /// reclaimed leases from the results returned.
+    ///
+    /// @param [out] expired_leases A container to which expired leases returned
+    /// by the database backend are added.
+    /// @param max_leases A maximum number of leases to be returned. If this
+    /// value is set to 0, all expired (but not reclaimed) leases are returned.
+    virtual void getExpiredLeases6(Lease6Collection& expired_leases,
+                                   const size_t max_leases) const = 0;
+
+
+    /// @brief Returns a collection of expired DHCPv4 leases.
+    ///
+    /// This method returns at most @c max_leases expired leases. The leases
+    /// returned haven't been reclaimed, i.e. the database query must exclude
+    /// reclaimed leases from the results returned.
+    ///
+    /// @param [out] expired_leases A container to which expired leases returned
+    /// by the database backend are added.
+    /// @param max_leases A maximum number of leases to be returned. If this
+    /// value is set to 0, all expired (but not reclaimed) leases are returned.
+    virtual void getExpiredLeases4(Lease4Collection& expired_leases,
+                                   const size_t max_leases) const = 0;
+
     /// @brief Updates IPv4 lease.
     ///
     /// @param lease4 The lease to be updated.

+ 59 - 6
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -515,11 +515,59 @@ Memfile_LeaseMgr::getLeases6(Lease::Type type,
 }
 
 void
+Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
+                                    const size_t max_leases) const {
+    // Obtain the index which segragates leases by state and time.
+    const Lease6StorageExpirationIndex& index = storage6_.get<ExpirationIndexTag>();
+
+    // Retrieve leases which are not reclaimed and which haven't expired. The
+    // 'less-than' operator will be used for both components of the index. So,
+    // for the 'state' 'false' is less than 'true'. Also the leases with
+    // expiration time lower than current time will be returned.
+    Lease6StorageExpirationIndex::const_iterator ub =
+        index.upper_bound(boost::make_tuple(false, time_t(NULL)));
+
+    // Copy only the number of leases indicated by the max_leases parameter.
+    for (Lease6StorageExpirationIndex::const_iterator lease = index.begin();
+         (lease != ub) && ((max_leases == 0) || (std::distance(index.begin(), lease) <
+                                                 max_leases));
+         ++lease) {
+        expired_leases.push_back(Lease6Ptr(new Lease6(**lease)));
+    }
+}
+
+void
+Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
+                                    const size_t max_leases) const {
+    // Obtain the index which segragates leases by state and time.
+    const Lease4StorageExpirationIndex& index = storage4_.get<ExpirationIndexTag>();
+
+    // Retrieve leases which are not reclaimed and which haven't expired. The
+    // 'less-than' operator will be used for both components of the index. So,
+    // for the 'state' 'false' is less than 'true'. Also the leases with
+    // expiration time lower than current time will be returned.
+    Lease4StorageExpirationIndex::const_iterator ub =
+        index.upper_bound(boost::make_tuple(false, time_t(NULL)));
+
+    // Copy only the number of leases indicated by the max_leases parameter.
+    for (Lease4StorageExpirationIndex::const_iterator lease = index.begin();
+         (lease != ub) && ((max_leases == 0) || (std::distance(index.begin(), lease) <
+                                                 max_leases));
+         ++lease) {
+        expired_leases.push_back(Lease4Ptr(new Lease4(**lease)));
+    }
+}
+
+void
 Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
 
-    Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
+    // Obtain 'by address' index.
+    Lease4StorageAddressIndex& index = storage4_.get<AddressIndexTag>();
+
+    // Lease must exist if it is to be updated.
+    Lease4StorageAddressIndex::const_iterator lease_it = index.find(lease->addr_);
     if (lease_it == storage4_.end()) {
         isc_throw(NoSuchLease, "failed to update the lease with address "
                   << lease->addr_ << " - no such lease");
@@ -532,7 +580,8 @@ Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
         lease_file4_->append(*lease);
     }
 
-    **lease_it = *lease;
+    // Use replace() to re-index leases.
+    index.replace(lease_it, Lease4Ptr(new Lease4(*lease)));
 }
 
 void
@@ -540,8 +589,12 @@ Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
 
-    Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
-    if (lease_it == storage6_.end()) {
+    // Obtain 'by address' index.
+    Lease6StorageAddressIndex& index = storage6_.get<AddressIndexTag>();
+
+    // Lease must exist if it is to be updated.
+    Lease6StorageAddressIndex::const_iterator lease_it = index.find(lease->addr_);
+    if (lease_it == index.end()) {
         isc_throw(NoSuchLease, "failed to update the lease with address "
                   << lease->addr_ << " - no such lease");
     }
@@ -553,7 +606,8 @@ Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
         lease_file6_->append(*lease);
     }
 
-    **lease_it = *lease;
+    // Use replace() to re-index leases.
+    index.replace(lease_it, Lease6Ptr(new Lease6(*lease)));
 }
 
 bool
@@ -871,6 +925,5 @@ void Memfile_LeaseMgr::lfcExecute(boost::shared_ptr<LeaseFileType>& lease_file)
     }
 }
 
-
 } // end of namespace isc::dhcp
 } // end of namespace isc

+ 27 - 0
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -259,6 +259,33 @@ public:
                                         uint32_t iaid,
                                         SubnetID subnet_id) const;
 
+    /// @brief Returns a collection of expired DHCPv6 leases.
+    ///
+    /// This method returns at most @c max_leases expired leases. The leases
+    /// returned haven't been reclaimed, i.e. the database query must exclude
+    /// reclaimed leases from the results returned.
+    ///
+    /// @param [out] expired_leases A container to which expired leases returned
+    /// by the database backend are added.
+    /// @param max_leases A maximum number of leases to be returned. If this
+    /// value is set to 0, all expired (but not reclaimed) leases are returned.
+    virtual void getExpiredLeases6(Lease6Collection& expired_leases,
+                                   const size_t max_leases) const;
+
+
+    /// @brief Returns a collection of expired DHCPv4 leases.
+    ///
+    /// This method returns at most @c max_leases expired leases. The leases
+    /// returned haven't been reclaimed, i.e. the database query must exclude
+    /// reclaimed leases from the results returned.
+    ///
+    /// @param [out] expired_leases A container to which expired leases returned
+    /// by the database backend are added.
+    /// @param max_leases A maximum number of leases to be returned. If this
+    /// value is set to 0, all expired (but not reclaimed) leases are returned.
+    virtual void getExpiredLeases4(Lease4Collection& expired_leases,
+                                   const size_t max_leases) const;
+
     /// @brief Updates IPv4 lease.
     ///
     /// @warning This function does not validate the pointer to the lease.

+ 71 - 3
src/lib/dhcpsrv/memfile_lease_storage.h

@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef INMEMORY_LEASE_STORAGE_H
-#define INMEMORY_LEASE_STORAGE_H
+#ifndef MEMFILE_LEASE_STORAGE_H
+#define MEMFILE_LEASE_STORAGE_H
 
 #include <asiolink/io_address.h>
 #include <dhcpsrv/lease.h>
@@ -31,6 +31,17 @@
 namespace isc {
 namespace dhcp {
 
+
+/// @brief Tag for indexes by address.
+struct AddressIndexTag { };
+
+/// @brief Tag for indexes by expiration time.
+struct ExpirationIndexTag { };
+
+/// @name Multi index containers holding DHCPv4 and DHCPv6 leases.
+///
+//@{
+
 /// @brief A multi index container holding DHCPv6 leases.
 ///
 /// The leases in the container may be accessed using different indexes:
@@ -44,6 +55,7 @@ typedef boost::multi_index_container<
         // This index sorts leases by IPv6 addresses represented as
         // IOAddress objects.
         boost::multi_index::ordered_unique<
+            boost::multi_index::tag<AddressIndexTag>,
             boost::multi_index::member<Lease, isc::asiolink::IOAddress, &Lease::addr_>
         >,
 
@@ -62,6 +74,24 @@ typedef boost::multi_index_container<
                 boost::multi_index::member<Lease6, uint32_t, &Lease6::iaid_>,
                 boost::multi_index::member<Lease6, Lease::Type, &Lease6::type_>
             >
+        >,
+
+        // Specification of the third index starts here.
+        boost::multi_index::ordered_non_unique<
+            boost::multi_index::tag<ExpirationIndexTag>,
+            // This is a composite index that will be used to search for
+            // the expired leases. Depending on the value of the first component
+            // of the search key, the reclaimed or not reclaimed leases will can
+            // be searched.
+            boost::multi_index::composite_key<
+                Lease6,
+                // The boolean value specifying if lease is reclaimed or not.
+                boost::multi_index::const_mem_fun<Lease, bool,
+                                                  &Lease::stateExpiredReclaimed>,
+                // Lease expiration time.
+                boost::multi_index::const_mem_fun<Lease, int64_t,
+                                                  &Lease::getExpirationTime>
+            >
         >
      >
 > Lease6Storage; // Specify the type name of this container.
@@ -82,6 +112,7 @@ typedef boost::multi_index_container<
         // This index sorts leases by IPv4 addresses represented as
         // IOAddress objects.
         boost::multi_index::ordered_unique<
+            boost::multi_index::tag<AddressIndexTag>,
             // The IPv4 address are held in addr_ members that belong to
             // Lease class.
             boost::multi_index::member<Lease, isc::asiolink::IOAddress, &Lease::addr_>
@@ -141,11 +172,48 @@ typedef boost::multi_index_container<
                 // The subnet id is accessed through the subnet_id_ member.
                 boost::multi_index::member<Lease, SubnetID, &Lease::subnet_id_>
             >
+        >,
+
+        // Specification of the fifth index starts here.
+        boost::multi_index::ordered_non_unique<
+            boost::multi_index::tag<ExpirationIndexTag>,
+            // This is a composite index that will be used to search for
+            // the expired leases. Depending on the value of the first component
+            // of the search key, the reclaimed or not reclaimed leases will can
+            // be searched.
+            boost::multi_index::composite_key<
+                Lease4,
+                // The boolean value specifying if lease is reclaimed or not.
+                boost::multi_index::const_mem_fun<Lease, bool,
+                                                  &Lease::stateExpiredReclaimed>,
+                // Lease expiration time.
+                boost::multi_index::const_mem_fun<Lease, int64_t,
+                                                  &Lease::getExpirationTime>
+            >
         >
     >
 > Lease4Storage; // Specify the type name for this container.
 
+//@}
+
+/// @name Indexes used by the multi index containers
+///
+//@{
+
+/// @brief DHCPv6 lease storage index by address.
+typedef Lease6Storage::index<AddressIndexTag>::type Lease6StorageAddressIndex;
+
+/// @brief DHCPv6 lease storage index by expiration time.
+typedef Lease6Storage::index<ExpirationIndexTag>::type Lease6StorageExpirationIndex;
+
+/// @brief DHCPv4 lease storage index by address.
+typedef Lease4Storage::index<AddressIndexTag>::type Lease4StorageAddressIndex;
+
+/// @brief DHCPv4 lease storage index by exiration time.
+typedef Lease4Storage::index<ExpirationIndexTag>::type Lease4StorageExpirationIndex;
+
+//@}
 } // end of isc::dhcp namespace
 } // end of isc namespace
 
-#endif // INMEMORY_LEASE_STORAGE_H
+#endif // MEMFILE_LEASE_STORAGE_H

+ 240 - 0
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc

@@ -1657,6 +1657,246 @@ GenericLeaseMgrTest::testVersion(int major, int minor) {
     EXPECT_EQ(minor, lmptr_->getVersion().second);
 }
 
+void
+GenericLeaseMgrTest::testGetExpiredLeases4() {
+    // Get the leases to be used for the test.
+    vector<Lease4Ptr> leases = createLeases4();
+    // Make sure we have at least 6 leases there.
+    ASSERT_GE(leases.size(), 6);
+
+    // Use the same current time for all leases.
+    time_t current_time = time_t(NULL);
+
+    // Add them to the database
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Mark every other lease as expired.
+        if (i % 2 == 0) {
+            // Set client last transmission time to the value older than the
+            // valid lifetime to make it expired. The expiration time also
+            // depends on the lease index, so as we can later check that the
+            // leases are ordered by the expiration time.
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - 10 - i;
+
+        } else {
+            // Set current time as cltt for remaining leases. These leases are
+            // not expired.
+            leases[i]->cltt_ = current_time;
+        }
+        ASSERT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Retrieve expired leases.
+    Lease4Collection expired_leases;
+    lmptr_->getExpiredLeases4(expired_leases, 1000);
+    // Leases with even indexes should be returned as expired.
+    ASSERT_EQ(static_cast<size_t>(leases.size() / 2), expired_leases.size());
+
+    // The expired leases should be returned from the most to least expired.
+    // This matches the reverse order to which they have been added.
+    for (Lease4Collection::reverse_iterator lease = expired_leases.rbegin();
+         lease != expired_leases.rend(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.rbegin(), lease));
+        // Multiple current index by two, because only leases with even indexes
+        // should have been returned.
+        EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_);
+    }
+
+    // Update current time for the next test.
+    current_time = time_t(NULL);
+    // Also, remove expired leases collected during the previous test.
+    expired_leases.clear();
+
+    // This time let's reverse the expiration time and see if they will be returned
+    // in the correct order.
+    for (int i = 0; i < leases.size(); ++i) {
+        // Update the time of expired leases with even indexes.
+        if (i % 2 == 0) {
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - 1000 + i;
+
+        } else {
+            // Make sure remaining leases remain unexpired.
+            leases[i]->cltt_ = current_time + 100;
+        }
+        ASSERT_NO_THROW(lmptr_->updateLease4(leases[i]));
+    }
+
+    // Retrieve expired leases again. The limit of 0 means return all expired
+    // leases.
+    lmptr_->getExpiredLeases4(expired_leases, 0);
+    // The same leases should be returned.
+    ASSERT_EQ(static_cast<size_t>(leases.size() / 2), expired_leases.size());
+
+    // This time leases should be returned in the non-reverse order.
+    for (Lease4Collection::iterator lease = expired_leases.begin();
+         lease != expired_leases.end(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.begin(), lease));
+        EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_);
+    }
+
+    // Remember expired leases returned.
+    std::vector<Lease4Ptr> saved_expired_leases = expired_leases;
+
+    // Remove expired leases again. 
+    expired_leases.clear();
+
+    // Limit the number of leases to be returned to 2.
+    lmptr_->getExpiredLeases4(expired_leases, 2);
+
+    // Make sure we have exactly 2 leases returned.
+    ASSERT_EQ(2, expired_leases.size());
+
+    // Test that most expired leases have been returned.
+    for (Lease4Collection::iterator lease = expired_leases.begin();
+         lease != expired_leases.end(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.begin(), lease));
+        EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_);
+    }
+
+    // Mark every other expired lease as reclaimed.
+    for (int i = 0; i < saved_expired_leases.size(); ++i) {
+        if (i % 2 != 0) {
+            saved_expired_leases[i]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+        }
+        ASSERT_NO_THROW(lmptr_->updateLease4(saved_expired_leases[i]));
+    }
+
+    expired_leases.clear();
+
+    // This the returned leases should exclude reclaimed ones. So the number
+    // of returned leases should be roughly half of the expired leases.
+    lmptr_->getExpiredLeases4(expired_leases, 0);
+    ASSERT_EQ(static_cast<size_t>(saved_expired_leases.size() / 2),
+              expired_leases.size());
+
+    // Make sure that returned leases are those that are not reclaimed, i.e.
+    // those that have even index.
+    for (Lease4Collection::iterator lease = expired_leases.begin();
+         lease != expired_leases.end(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.begin(), lease));
+        EXPECT_EQ(saved_expired_leases[2 * index]->addr_, (*lease)->addr_);
+    }
+}
+
+void
+GenericLeaseMgrTest::testGetExpiredLeases6() {
+    // Get the leases to be used for the test.
+    vector<Lease6Ptr> leases = createLeases6();
+    // Make sure we have at least 6 leases there.
+    ASSERT_GE(leases.size(), 6);
+
+    // Use the same current time for all leases.
+    time_t current_time = time_t(NULL);
+
+    // Add them to the database
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Mark every other lease as expired.
+        if (i % 2 == 0) {
+            // Set client last transmission time to the value older than the
+            // valid lifetime to make it expired. The expiration time also
+            // depends on the lease index, so as we can later check that the
+            // leases are ordered by the expiration time.
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - 10 - i;
+
+        } else {
+            // Set current time as cltt for remaining leases. These leases are
+            // not expired.
+            leases[i]->cltt_ = current_time;
+        }
+        ASSERT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Retrieve expired leases.
+    Lease6Collection expired_leases;
+    lmptr_->getExpiredLeases6(expired_leases, 1000);
+    // Leases with even indexes should be returned as expired.
+    ASSERT_EQ(static_cast<size_t>(leases.size() / 2), expired_leases.size());
+
+    // The expired leases should be returned from the most to least expired.
+    // This matches the reverse order to which they have been added.
+    for (Lease6Collection::reverse_iterator lease = expired_leases.rbegin();
+         lease != expired_leases.rend(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.rbegin(), lease));
+        // Multiple current index by two, because only leases with even indexes
+        // should have been returned.
+        EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_);
+    }
+
+    // Update current time for the next test.
+    current_time = time_t(NULL);
+    // Also, remove expired leases collected during the previous test.
+    expired_leases.clear();
+
+    // This time let's reverse the expiration time and see if they will be returned
+    // in the correct order.
+    for (int i = 0; i < leases.size(); ++i) {
+        // Update the time of expired leases with even indexes.
+        if (i % 2 == 0) {
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - 1000 + i;
+
+        } else {
+            // Make sure remaining leases remain unexpired.
+            leases[i]->cltt_ = current_time + 100;
+        }
+        ASSERT_NO_THROW(lmptr_->updateLease6(leases[i]));
+    }
+
+    // Retrieve expired leases again. The limit of 0 means return all expired
+    // leases.
+    lmptr_->getExpiredLeases6(expired_leases, 0);
+    // The same leases should be returned.
+    ASSERT_EQ(static_cast<size_t>(leases.size() / 2), expired_leases.size());
+
+    // This time leases should be returned in the non-reverse order.
+    for (Lease6Collection::iterator lease = expired_leases.begin();
+         lease != expired_leases.end(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.begin(), lease));
+        EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_);
+    }
+
+    // Remember expired leases returned.
+    std::vector<Lease6Ptr> saved_expired_leases = expired_leases;
+
+    // Remove expired leases again. 
+    expired_leases.clear();
+
+    // Limit the number of leases to be returned to 2.
+    lmptr_->getExpiredLeases6(expired_leases, 2);
+
+    // Make sure we have exactly 2 leases returned.
+    ASSERT_EQ(2, expired_leases.size());
+
+    // Test that most expired leases have been returned.
+    for (Lease6Collection::iterator lease = expired_leases.begin();
+         lease != expired_leases.end(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.begin(), lease));
+        EXPECT_EQ(leases[2 * index]->addr_, (*lease)->addr_);
+    }
+
+    // Mark every other expired lease as reclaimed.
+    for (int i = 0; i < saved_expired_leases.size(); ++i) {
+        if (i % 2 != 0) {
+            saved_expired_leases[i]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+        }
+        ASSERT_NO_THROW(lmptr_->updateLease6(saved_expired_leases[i]));
+    }
+
+    expired_leases.clear();
+
+    // This the returned leases should exclude reclaimed ones. So the number
+    // of returned leases should be roughly half of the expired leases.
+    lmptr_->getExpiredLeases6(expired_leases, 0);
+    ASSERT_EQ(static_cast<size_t>(saved_expired_leases.size() / 2),
+              expired_leases.size());
+
+    // Make sure that returned leases are those that are not reclaimed, i.e.
+    // those that have even index.
+    for (Lease6Collection::iterator lease = expired_leases.begin();
+         lease != expired_leases.end(); ++lease) {
+        int index = static_cast<int>(std::distance(expired_leases.begin(), lease));
+        EXPECT_EQ(saved_expired_leases[2 * index]->addr_, (*lease)->addr_);
+    }
+}
+
 
 }; // namespace test
 }; // namespace dhcp

+ 20 - 0
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h

@@ -265,6 +265,26 @@ public:
     /// @param minor Expected minor version to be reported.
     void testVersion(int major, int minor);
 
+    /// @brief Checks that the expired DHCPv4 leases can be retrieved.
+    ///
+    /// This test checks the following:
+    /// - all expired and not reclaimed leases are retured
+    /// - number of leases returned can be limited
+    /// - leases are returned in the order from the most expired to the
+    ///   least expired
+    /// - reclaimed leases are not returned.
+    void testGetExpiredLeases4();
+
+    /// @brief Checks that the expired DHCPv6 leases can be retrieved.
+    ///
+    /// This test checks the following:
+    /// - all expired and not reclaimed leases are retured
+    /// - number of leases returned can be limited
+    /// - leases are returned in the order from the most expired to the
+    ///   least expired
+    /// - reclaimed leases are not returned.
+    void testGetExpiredLeases6();
+
     /// @brief String forms of IPv4 addresses
     std::vector<std::string>  straddress4_;
 

+ 18 - 1
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -173,6 +173,23 @@ public:
         return (leases6_);
     }
 
+
+    /// @brief Returns expired DHCPv6 leases.
+    ///
+    /// This method is not implemented.
+    virtual void getExpiredLeases6(Lease6Collection&, const size_t) const {
+        isc_throw(NotImplemented, "ConcreteLeaseMgr::getExpiredLeases6 is not"
+                  " implemented");
+    }
+
+    /// @brief Returns expired DHCPv4 leases.
+    ///
+    /// This method is not implemented.
+    virtual void getExpiredLeases4(Lease4Collection&, const size_t) const {
+        isc_throw(NotImplemented, "ConcreteLeaseMgr::getExpiredLeases4 is not"
+                  " implemented");
+    }
+
     /// @brief Updates IPv4 lease.
     ///
     /// @param lease4 The lease to be updated.

+ 24 - 0
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -881,6 +881,30 @@ TEST_F(MemfileLeaseMgrTest, getLeases6DuidSize) {
     testGetLeases6DuidSize();
 }
 
+/// @brief Check that the expired DHCPv4 leases can be retrieved.
+///
+/// This test adds a number of leases to the lease database and marks
+/// some of them as expired. Then it queries for expired leases and checks
+/// whether only expired leases are returned, and that they are returned in
+/// the order from most to least expired. It also checks that the lease
+/// which is marked as 'reclaimed' is not returned.
+TEST_F(MemfileLeaseMgrTest, getExpiredLeases4) {
+    startBackend(V4);
+    testGetExpiredLeases4();
+}
+
+/// @brief Check that the expired DHCPv6 leases can be retrieved.
+///
+/// This test adds a number of leases to the lease database and marks
+/// some of them as expired. Then it queries for expired leases and checks
+/// whether only expired leases are returned, and that they are returned in
+/// the order from most to least expired. It also checks that the lease
+/// which is marked as 'reclaimed' is not returned.
+TEST_F(MemfileLeaseMgrTest, getExpiredLeases6) {
+    startBackend(V6);
+    testGetExpiredLeases6();
+}
+
 /// @brief Check that getLease6 methods discriminate by lease type.
 ///
 /// Adds six leases, two per lease type all with the same duid and iad but