diff options
Diffstat (limited to 'src/lib/dhcpsrv/tests/lease_mgr_unittest.cc')
-rw-r--r-- | src/lib/dhcpsrv/tests/lease_mgr_unittest.cc | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc new file mode 100644 index 0000000..00675ec --- /dev/null +++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc @@ -0,0 +1,545 @@ +// Copyright (C) 2012-2022 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <asiolink/io_address.h> +#include <dhcpsrv/lease_mgr.h> +#include <dhcpsrv/memfile_lease_mgr.h> +#include <dhcpsrv/testutils/test_utils.h> +#include <dhcpsrv/tests/generic_lease_mgr_unittest.h> + +#include <gtest/gtest.h> + +#include <iostream> +#include <sstream> + +#include <time.h> + +using namespace std; +using namespace isc; +using namespace isc::asiolink; +using namespace isc::db; +using namespace isc::dhcp; +using namespace isc::dhcp::test; + +// This is a concrete implementation of a Lease database. It does not do +// anything useful and is used for abstract LeaseMgr class testing. +class ConcreteLeaseMgr : public LeaseMgr { +public: + + /// @brief The sole lease manager constructor + /// + /// dbconfig is a generic way of passing parameters. Parameters + /// are passed in the "name=value" format, separated by spaces. + /// Values may be enclosed in double quotes, if needed. + ConcreteLeaseMgr(const DatabaseConnection::ParameterMap&) + : LeaseMgr() + {} + + /// @brief Destructor + virtual ~ConcreteLeaseMgr() + {} + + /// @brief Adds an IPv4 lease. + /// + /// @param lease lease to be added + virtual bool addLease(const Lease4Ptr&) override { + return (false); + } + + /// @brief Adds an IPv6 lease. + /// + /// @param lease lease to be added + virtual bool addLease(const Lease6Ptr&) override { + return (false); + } + + /// @brief Returns existing IPv4 lease for specified IPv4 address. + /// + /// @param addr address of the searched lease + /// + /// @return smart pointer to the lease (or NULL if a lease is not found) + virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&) const override { + return (Lease4Ptr()); + } + + /// @brief Returns existing IPv4 leases for specified hardware address. + /// + /// 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 + /// pointer. + /// + /// @param hwaddr hardware address of the client + /// + /// @return lease collection + virtual Lease4Collection getLease4(const HWAddr&) const override { + return (Lease4Collection()); + } + + /// @brief Returns existing IPv4 leases for specified hardware address + /// and a subnet + /// + /// There can be at most one lease for a given HW address in a single + /// pool, so this method with either return a single lease or NULL. + /// + /// @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 HWAddr&, SubnetID) const override { + return (Lease4Ptr()); + } + + /// @brief Returns existing IPv4 lease for specified client-id + /// + /// @param clientid client identifier + /// + /// @return lease collection + virtual Lease4Collection getLease4(const ClientId&) const override { + return (Lease4Collection()); + } + + /// @brief Returns existing IPv4 lease for specified client-id + /// + /// There can be at most one lease for a given HW address in a single + /// pool, so this method with either return a single lease or NULL. + /// + /// @param clientid client identifier + /// @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&, SubnetID) const override { + return (Lease4Ptr()); + } + + /// @brief Returns all IPv4 leases for the particular subnet identifier. + /// + /// @param subnet_id subnet identifier. + /// + /// @return Lease collection (may be empty if no IPv4 lease found). + virtual Lease4Collection getLeases4(SubnetID) const override { + return (Lease4Collection()); + } + + /// @brief Returns all IPv4 leases for the particular hostname. + /// + /// @param hostname hostname in lower case. + /// + /// @return Lease collection (may be empty if no IPv4 lease found). + virtual Lease4Collection getLeases4(const std::string&) const override { + return (Lease4Collection()); + } + + /// @brief Returns all IPv4 leases. + /// + /// @return Lease collection (may be empty if no IPv4 lease found). + virtual Lease4Collection getLeases4() const override { + return (Lease4Collection()); + } + + /// @brief Returns range of IPv4 leases using paging. + /// + /// This method implements paged browsing of the lease database. The first + /// parameter specifies a page size. The second parameter is optional and + /// specifies the starting address of the range. This address is excluded + /// from the returned range. The IPv4 zero address (default) denotes that + /// the first page should be returned. There is no guarantee about the + /// order of returned leases. + /// + /// The typical usage of this method is as follows: + /// - Get the first page of leases by specifying IPv4 zero address as the + /// beginning of the range. + /// - Last address of the returned range should be used as a starting + /// address for the next page in the subsequent call. + /// - If the number of leases returned is lower than the page size, it + /// indicates that the last page has been retrieved. + /// - If there are no leases returned it indicates that the previous page + /// was the last page. + /// + /// @param lower_bound_address IPv4 address used as lower bound for the + /// returned range. + /// @param page_size maximum size of the page returned. + /// + /// @return Lease collection (may be empty if no IPv4 lease found). + virtual Lease4Collection + getLeases4(const asiolink::IOAddress& /* lower_bound_address */, + const LeasePageSize& /* page_size */) const override { + return (Lease4Collection()); + } + + /// @brief Returns existing IPv6 lease for a given IPv6 address. + /// + /// @param addr address of the searched lease + /// + /// @return smart pointer to the lease (or NULL if a lease is not found) + virtual Lease6Ptr getLease6(Lease::Type /* not used yet */, + const isc::asiolink::IOAddress&) const override { + return (Lease6Ptr()); + } + + /// @brief Returns existing IPv6 lease for a given DUID+IA combination + /// + /// @param duid ignored + /// @param iaid ignored + /// + /// @return whatever is set in leases6_ field + virtual Lease6Collection getLeases6(Lease::Type /* not used yet */, + const DUID&, uint32_t) const override { + return (leases6_); + } + + /// @brief Returns existing IPv6 lease for a given DUID+IA+subnet-id combination + /// + /// @param duid ignored + /// @param iaid ignored + /// @param subnet_id ignored + /// + /// @return whatever is set in leases6_ field + virtual Lease6Collection getLeases6(Lease::Type /* not used yet */, + const DUID&, uint32_t, SubnetID) const override { + return (leases6_); + } + + /// @brief Returns collection of lease for matching DUID + /// + /// @param duid ignored + /// @return whatever is set in leases6_ field + virtual Lease6Collection getLeases6(const DUID&) const override { + return (leases6_); + } + + /// @brief Returns all IPv6 leases for the particular subnet identifier. + /// + /// @param subnet_id subnet identifier. + /// + /// @return Lease collection (may be empty if no IPv6 lease found). + virtual Lease6Collection getLeases6(SubnetID) const override { + return (Lease6Collection()); + } + + /// @brief Returns all IPv6 leases for the particular hostname. + /// + /// @param hostname hostname in lower case. + /// + /// @return Lease collection (may be empty if no IPv6 lease found). + virtual Lease6Collection getLeases6(const std::string&) const override { + return (Lease6Collection()); + } + + /// @brief Returns all IPv6 leases. + /// + /// @return Lease collection (may be empty if no IPv6 lease found). + virtual Lease6Collection getLeases6() const override { + return (Lease6Collection()); + } + + /// @brief Returns range of IPv6 leases using paging. + /// + /// This method implements paged browsing of the lease database. The first + /// parameter specifies a page size. The second parameter is optional and + /// specifies the starting address of the range. This address is excluded + /// from the returned range. The IPv6 zero address (default) denotes that + /// the first page should be returned. There is no guarantee about the + /// order of returned leases. + /// + /// The typical usage of this method is as follows: + /// - Get the first page of leases by specifying IPv6 zero address as the + /// beginning of the range. + /// - Last address of the returned range should be used as a starting + /// address for the next page in the subsequent call. + /// - If the number of leases returned is lower than the page size, it + /// indicates that the last page has been retrieved. + /// - If there are no leases returned it indicates that the previous page + /// was the last page. + /// + /// @param lower_bound_address IPv4 address used as lower bound for the + /// returned range. + /// @param page_size maximum size of the page returned. + /// + /// @return Lease collection (may be empty if no IPv6 lease found). + virtual Lease6Collection + getLeases6(const asiolink::IOAddress& /* lower_bound_address */, + const LeasePageSize& /* page_size */) const override { + return (Lease6Collection()); + }; + + /// @brief Returns expired DHCPv6 leases. + /// + /// This method is not implemented. + virtual void getExpiredLeases6(Lease6Collection&, const size_t) const override { + 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 override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::getExpiredLeases4 is not" + " implemented"); + } + + /// @brief Updates IPv4 lease. + /// + /// @param lease4 The lease to be updated. + /// + /// If no such lease is present, an exception will be thrown. + virtual void updateLease4(const Lease4Ptr&) override {} + + /// @brief Updates IPv4 lease. + /// + /// @param lease4 The lease to be updated. + /// + /// If no such lease is present, an exception will be thrown. + virtual void updateLease6(const Lease6Ptr&) override {} + + /// @brief Deletes an IPv4 lease. + /// + /// @param lease IPv4 lease to be deleted. + /// + /// @return true if deletion was successful, false if no such lease exists. + virtual bool deleteLease(const Lease4Ptr&) override { + return (false); + } + + /// @brief Deletes an IPv6 lease. + /// + /// @param lease IPv6 lease to be deleted. + /// + /// @return true if deletion was successful, false if no such lease exists. + virtual bool deleteLease(const Lease6Ptr&) override { + return (false); + } + + /// @brief Deletes all expired and reclaimed DHCPv4 leases. + /// + /// @param secs Number of seconds since expiration of leases before + /// they can be removed. Leases which have expired later than this + /// time will not be deleted. + virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t) override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::deleteExpiredReclaimedLeases4" + " is not implemented"); + } + + /// @brief Deletes all expired and reclaimed DHCPv6 leases. + /// + /// @param secs Number of seconds since expiration of leases before + /// they can be removed. Leases which have expired later than this + /// time will not be deleted. + virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t) override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::deleteExpiredReclaimedLeases6" + " is not implemented"); + } + + /// @brief Pretends to wipe all IPv4 leases from a subnet + /// @param subnet_id (ignored, but one day may specify the subnet) + virtual size_t wipeLeases4(const SubnetID&) override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::wipeLeases4 not implemented"); + } + + /// @brief Pretends to wipe all IPv4 leases from a subnet + /// @param subnet_id (ignored, but one day may specify the subnet) + virtual size_t wipeLeases6(const SubnetID&) override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::wipeLeases6 not implemented"); + } + + /// @brief Pretends to check if the IPv4 lease limits set in the given user + /// context are exceeded. + virtual std::string + checkLimits4(isc::data::ConstElementPtr const& /* user_context */) const override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::checkLimits4() not implemented"); + } + + /// @brief Pretends to check if the IPv6 lease limits set in the given user + /// context are exceeded. + virtual std::string + checkLimits6(isc::data::ConstElementPtr const& /* user_context */) const override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::checkLimits6() not implemented"); + } + + /// @brief Pretends to check if JSON support is enabled in the database. + /// + /// @return true if there is JSON support, false otherwise + virtual bool isJsonSupported() const override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::isJsonSupported() not implemented"); + } + + /// @brief Pretends to return the class lease count for a given class and lease type. + /// + /// @param client_class client class for which the count is desired + /// @param ltype type of lease for which the count is desired. Defaults to + /// Lease::TYPE_V4. + /// + /// @return number of leases + virtual size_t getClassLeaseCount(const ClientClass& /* client_class */, + const Lease::Type& /* ltype = Lease::TYPE_V4 */) const override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::getClassLeaseCount() not implemented"); + } + + /// @brief Pretends to recount the leases per class for V4 leases. + virtual void recountClassLeases4() override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::recountClassLeases4() not implemented"); + } + + /// @brief Pretends to recount the leases per class for V6 leases. + virtual void recountClassLeases6() override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::recountClassLeases6() not implemented"); + } + + /// @brief Pretends to clear the class-lease count map. + virtual void clearClassLeaseCounts() override { + isc_throw(NotImplemented, "ConcreteLeaseMgr::clearClassLeaseCounts() not implemented"); + } + + /// @brief Returns backend type. + /// + /// Returns the type of the backend (e.g. "mysql", "memfile" etc.) + /// + /// @return Type of the backend. + virtual std::string getType() const override { + return (std::string("concrete")); + } + + /// @brief Returns backend name. + /// + /// If the backend is a database, this is the name of the database or the + /// file. Otherwise it is just the same as the type. + /// + /// @return Name of the backend. + virtual std::string getName() const override { + return (std::string("concrete")); + } + + /// @brief Returns description of the backend. + /// + /// This description may be multiline text that describes the backend. + /// + /// @return Description of the backend. + virtual std::string getDescription() const override { + return (std::string("This is a dummy concrete backend implementation.")); + } + + /// @brief Returns backend version. + virtual std::pair<uint32_t, uint32_t> getVersion() const override { + return (make_pair(uint32_t(0), uint32_t(0))); + } + + /// @brief Commit transactions + virtual void commit() override { + } + + /// @brief Rollback transactions + virtual void rollback() override { + } + + // We need to use it in ConcreteLeaseMgr + using LeaseMgr::getLease6; + + Lease6Collection leases6_; ///< getLease6 methods return this as is +}; + +class LeaseMgrTest : public GenericLeaseMgrTest { +public: + LeaseMgrTest() { + } + + /// @brief Reopen the database + /// + /// No-op implementation. We need to provide concrete implementation, + /// as this is a pure virtual method in GenericLeaseMgrTest. + virtual void reopen(Universe) { + } + +}; + +namespace { + +// This test checks if getLease6() method is working properly for 0 (NULL), +// 1 (return the lease) and more than 1 leases (throw). +TEST_F(LeaseMgrTest, getLease6) { + + DatabaseConnection::ParameterMap pmap; + boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap)); + + vector<Lease6Ptr> leases = createLeases6(); + + mgr->leases6_.clear(); + // For no leases, the function should return NULL pointer + Lease6Ptr lease; + + // the getLease6() is calling getLeases6(), which is a dummy. It returns + // whatever is there in leases6_ field. + EXPECT_NO_THROW(lease = mgr->getLease6(leasetype6_[1], *leases[1]->duid_, + leases[1]->iaid_, + leases[1]->subnet_id_)); + EXPECT_FALSE(lease); + + // For a single lease, the function should return that lease + mgr->leases6_.push_back(leases[1]); + EXPECT_NO_THROW(lease = mgr->getLease6(leasetype6_[1], *leases[1]->duid_, + leases[1]->iaid_, + leases[1]->subnet_id_)); + EXPECT_TRUE(lease); + + EXPECT_NO_THROW(detailCompareLease(lease, leases[1])); + + // Add one more lease. There are 2 now. It should throw + mgr->leases6_.push_back(leases[2]); + + EXPECT_THROW(lease = mgr->getLease6(leasetype6_[1], *leases[1]->duid_, + leases[1]->iaid_, + leases[1]->subnet_id_), + MultipleRecords); +} + +// Verify LeaseStatsQuery default construction +TEST (LeaseStatsQueryTest, defaultCtor) { + LeaseStatsQueryPtr qry; + + // Valid construction, verifiy member values. + ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery())); + ASSERT_EQ(0, qry->getFirstSubnetID()); + ASSERT_EQ(0, qry->getLastSubnetID()); + ASSERT_EQ(LeaseStatsQuery::ALL_SUBNETS, qry->getSelectMode()); +} + +// Verify LeaseStatsQuery single-subnet construction +TEST (LeaseStatsQueryTest, singleSubnetCtor) { + LeaseStatsQueryPtr qry; + + // Invalid values for subnet_id + ASSERT_THROW(qry.reset(new LeaseStatsQuery(0)), BadValue); + + // Valid values should work and set mode accordingly. + ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery(77))); + ASSERT_EQ(77, qry->getFirstSubnetID()); + ASSERT_EQ(0, qry->getLastSubnetID()); + ASSERT_EQ(LeaseStatsQuery::SINGLE_SUBNET, qry->getSelectMode()); +} + +// Verify LeaseStatsQuery subnet-range construction +TEST (LeaseStatsQueryTest, subnetRangeCtor) { + LeaseStatsQueryPtr qry; + + // Either ID set to 0, or a backward range should throw + ASSERT_THROW(qry.reset(new LeaseStatsQuery(0,1)), BadValue); + ASSERT_THROW(qry.reset(new LeaseStatsQuery(1,0)), BadValue); + ASSERT_THROW(qry.reset(new LeaseStatsQuery(2,1)), BadValue); + + // Valid values should work and set mode accordingly. + ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery(1,2))); + ASSERT_EQ(1, qry->getFirstSubnetID()); + ASSERT_EQ(2, qry->getLastSubnetID()); + ASSERT_EQ(LeaseStatsQuery::SUBNET_RANGE, qry->getSelectMode()); +} + +// There's no point in calling any other methods in LeaseMgr, as they +// are purely virtual, so we would only call ConcreteLeaseMgr methods. +// Those methods are just stubs that do not return anything. + +} // namespace |