From: Thomas Markwalder Date: Thu, 12 Apr 2018 11:35:47 +0000 (-0400) Subject: [5585] v4 Memfile support complete X-Git-Tag: trac5488_base^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=04b7d13f186875eb948422e5ea13aa397045a6ed;p=thirdparty%2Fkea.git [5585] v4 Memfile support complete Changed subnetID parms to const refs src/lib/dhcpsrv/memfile_lease_mgr.* Added constructors: - MemfileLeaseStatsQuery(const SubnetID& subnet_id) - MemfileLeaseStatsQuery(const SubnetID& first_subnet_id, const SubnetID& last_subnet_id) - MemfileLeaseStatsQuery4(Lease4Storage& storage4, const SubnetID& subnet_id) - MemfileLeaseStatsQuery4(Lease4Storage& storage4, const SubnetID& first_subnet_id, const SubnetID& last_subnet_id) MemfileLeaseStatsQuery4::start() - altered to set lower/upper iterators based on select mode Memfile_LeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) Memfile_LeaseMgr::startSubnetRangeLeaseStatsQuery4(const SubnetID& first_subnet_id, const SubnetID& last_subnet_id) src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc GenericLeaseMgrTest::testLeaseStatsQuery4() - expanded to cover bad values --- diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc index 2ea733258d..1defefc259 100644 --- a/src/lib/dhcpsrv/lease_mgr.cc +++ b/src/lib/dhcpsrv/lease_mgr.cc @@ -115,16 +115,18 @@ LeaseStatsQuery::LeaseStatsQuery() : first_subnet_id_(0), last_subnet_id_(0), select_mode_(ALL_SUBNETS) { } -LeaseStatsQuery::LeaseStatsQuery(SubnetID subnet_id) +LeaseStatsQuery::LeaseStatsQuery(const SubnetID& subnet_id) : first_subnet_id_(subnet_id), last_subnet_id_(0), select_mode_(SINGLE_SUBNET) { - if (first_subnet_id_ == 0) { - isc_throw(BadValue, "LeaseStatsQuery: subnet_id_ must be > 0"); - } + + if (first_subnet_id_ == 0) { + isc_throw(BadValue, "LeaseStatsQuery: subnet_id_ must be > 0"); + } } -LeaseStatsQuery::LeaseStatsQuery(SubnetID first, SubnetID last) - : first_subnet_id_(first), last_subnet_id_(last), +LeaseStatsQuery::LeaseStatsQuery(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id) + : first_subnet_id_(first_subnet_id), last_subnet_id_(last_subnet_id), select_mode_(SUBNET_RANGE) { if (first_subnet_id_ == 0) { @@ -147,13 +149,13 @@ LeaseMgr::startLeaseStatsQuery4() { } LeaseStatsQueryPtr -LeaseMgr::startSubnetLeaseStatsQuery4(SubnetID /* subnet_id */) { +LeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& /* subnet_id */) { return(LeaseStatsQueryPtr()); } LeaseStatsQueryPtr -LeaseMgr::startSubnetRangeLeaseStatsQuery4(SubnetID /* first */, - SubnetID /* last */) { +LeaseMgr::startSubnetRangeLeaseStatsQuery4(const SubnetID& /* first_subnet_id */, + const SubnetID& /* last_subnet_id */) { return(LeaseStatsQueryPtr()); } @@ -260,13 +262,13 @@ LeaseMgr::startLeaseStatsQuery6() { } LeaseStatsQueryPtr -LeaseMgr::startSubnetLeaseStatsQuery6(SubnetID /* subnet_id */) { +LeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& /* subnet_id */) { return(LeaseStatsQueryPtr()); } LeaseStatsQueryPtr -LeaseMgr::startSubnetRangeLeaseStatsQuery6(SubnetID /* first */, - SubnetID /* last */) { +LeaseMgr::startSubnetRangeLeaseStatsQuery6(const SubnetID& /* first_subnet_id */, + const SubnetID& /* last_subnet_id */) { return(LeaseStatsQueryPtr()); } diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index d4062e22ce..79aec3476e 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -155,17 +155,17 @@ public: /// /// @param subnet_id id of the subnet for which stats are desired /// @throw BadValue if sunbet_id given is 0. - LeaseStatsQuery(SubnetID subnet_id); + LeaseStatsQuery(const SubnetID& subnet_id); /// @brief Constructor to query for the stats for a range of subnets /// /// The query created will return statistics for the inclusive range of /// subnets described by first and last sunbet IDs. /// - /// @param first first subnet in the range of subnets - /// @param last last subnet in the range of subnets + /// @param first_subnet_id first subnet in the range of subnets + /// @param last_subnet_id last subnet in the range of subnets /// @throw BadValue if either value given is 0 or if last <= first. - LeaseStatsQuery(SubnetID first, SubnetID last); + LeaseStatsQuery(const SubnetID& first_subnet_id, const SubnetID& last_subnet_id); /// @brief virtual destructor virtual ~LeaseStatsQuery() {}; @@ -531,7 +531,7 @@ public: /// /// @param subnet_id id of the subnet for which stats are desired /// @return A populated LeaseStatsQuery - virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(SubnetID subnet_id); + virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID& subnet_id); /// @brief Creates and runs the IPv4 lease stats query for a single subnet /// @@ -541,11 +541,11 @@ public: /// range of subnets. Each row of the result set is an LeaseStatRow which /// ordered ascending by subnet ID. /// - /// @param first first subnet in the range of subnets - /// @param last last subnet in the range of subnets + /// @param first_subnet_id first subnet in the range of subnets + /// @param last_subnet_id last subnet in the range of subnets /// @return A populated LeaseStatsQuery - virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(SubnetID first, - SubnetID last); + virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id); /// @brief Recalculates per-subnet and global stats for IPv6 leases /// @@ -588,7 +588,7 @@ public: /// /// @param subnet_id id of the subnet for which stats are desired /// @return A populated LeaseStatsQuery - virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(SubnetID subnet_id); + virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID& subnet_id); /// @brief Creates and runs the IPv6 lease stats query for a single subnet /// @@ -598,11 +598,11 @@ public: /// range of subnets. Each row of the result set is an LeaseStatRow which /// ordered ascending by subnet ID. /// - /// @param first first subnet in the range of subnets - /// @param last last subnet in the range of subnets + /// @param first_subnet_id first subnet in the range of subnets + /// @param last last_subnet_id subnet in the range of subnets /// @return A populated LeaseStatsQuery - virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(SubnetID first, - SubnetID last); + virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id); /// @brief Virtual method which removes specified leases. /// diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index 336fe8be1c..5c2de6e5fb 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -258,10 +258,25 @@ LFCSetup::getExitStatus() const { /// class MemfileLeaseStatsQuery : public LeaseStatsQuery { public: - /// @brief Constructor + /// @brief Constructor for all subnets query /// MemfileLeaseStatsQuery() - : rows_(0), next_pos_(rows_.end()) { + : rows_(0), next_pos_(rows_.end()) { + }; + + /// @brief Constructor for single subnet query + /// + /// @param subnet_id ID of the desired subnet + MemfileLeaseStatsQuery(const SubnetID& subnet_id) + : LeaseStatsQuery(subnet_id), rows_(0), next_pos_(rows_.end()) { + }; + + /// @brief Constructor for subnet range query + /// + /// @param first_subnet_id ID of the first subnet in the desired range + /// @param last_subnet_id ID of the last subnet in the desired range + MemfileLeaseStatsQuery(const SubnetID& first_subnet_id, const SubnetID& last_subnet_id) + : LeaseStatsQuery(first_subnet_id, last_subnet_id), rows_(0), next_pos_(rows_.end()) { }; /// @brief Destructor @@ -311,11 +326,29 @@ protected: /// class MemfileLeaseStatsQuery4 : public MemfileLeaseStatsQuery { public: - /// @brief Constructor + /// @brief Constructor for an all subnets query /// /// @param storage4 A pointer to the v4 lease storage to be counted MemfileLeaseStatsQuery4(Lease4Storage& storage4) - : MemfileLeaseStatsQuery(), storage4_(storage4) { + : MemfileLeaseStatsQuery(), storage4_(storage4) { + }; + + /// @brief Constructor for a single subnet query + /// + /// @param storage4 A pointer to the v4 lease storage to be counted + /// @param subnet_id ID of the desired subnet + MemfileLeaseStatsQuery4(Lease4Storage& storage4, const SubnetID& subnet_id) + : MemfileLeaseStatsQuery(subnet_id), storage4_(storage4) { + }; + + /// @brief Constructor for a subnet range query + /// + /// @param storage4 A pointer to the v4 lease storage to be counted + /// @param first_subnet_id ID of the first subnet in the desired range + /// @param last_subnet_id ID of the last subnet in the desired range + MemfileLeaseStatsQuery4(Lease4Storage& storage4, const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id) + : MemfileLeaseStatsQuery(first_subnet_id, last_subnet_id), storage4_(storage4) { }; /// @brief Destructor @@ -339,14 +372,39 @@ public: const Lease4StorageSubnetIdIndex& idx = storage4_.get(); + // Set lower and upper bounds based on select mode + Lease4StorageSubnetIdIndex::const_iterator lower; + Lease4StorageSubnetIdIndex::const_iterator upper; + switch (getSelectMode()) { + case ALL_SUBNETS: + lower = idx.begin(); + upper = idx.end(); + break; + + case SINGLE_SUBNET: + lower = idx.lower_bound(getFirstSubnetID()); + upper = idx.upper_bound(getFirstSubnetID()); + break; + + case SUBNET_RANGE: + lower = idx.lower_bound(getFirstSubnetID()); + upper = idx.upper_bound(getLastSubnetID()); + break; + } + + // Return an empty set if there are no rows. + if (lower == upper) { + return; + } + // Iterate over the leases in order by subnet, accumulating per // subnet counts for each state of interest. As we finish each // subnet, add the appropriate rows to our result set. SubnetID cur_id = 0; int64_t assigned = 0; int64_t declined = 0; - for(Lease4StorageSubnetIdIndex::const_iterator lease = idx.begin(); - lease != idx.end(); ++lease) { + for(Lease4StorageSubnetIdIndex::const_iterator lease = lower; + lease != upper; ++lease) { // If we've hit the next subnet, add rows for the current subnet // and wipe the accumulators if ((*lease)->subnet_id_ != cur_id) { @@ -371,15 +429,11 @@ public: } } - // Make the rows for last subnet, unless there were no rows - if (idx.begin() != idx.end()) { - rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DEFAULT, - assigned)); - rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DECLINED, - declined)); - } + // Make the rows for last subnet + rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DEFAULT, assigned)); + rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DECLINED, declined)); - // Set the next row position to the beginning of the rows. + // Reset the next row position back to the beginning of the rows. next_pos_ = rows_.begin(); } @@ -1367,6 +1421,22 @@ Memfile_LeaseMgr::startLeaseStatsQuery4() { return(query); } +LeaseStatsQueryPtr +Memfile_LeaseMgr::startSubnetLeaseStatsQuery4(const SubnetID& subnet_id) { + LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_, subnet_id)); + query->start(); + return(query); +} + +LeaseStatsQueryPtr +Memfile_LeaseMgr::startSubnetRangeLeaseStatsQuery4(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id) { + LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_, first_subnet_id, + last_subnet_id)); + query->start(); + return(query); +} + LeaseStatsQueryPtr Memfile_LeaseMgr::startLeaseStatsQuery6() { LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_)); @@ -1374,6 +1444,24 @@ Memfile_LeaseMgr::startLeaseStatsQuery6() { return(query); } +#if 0 +LeaseStatsQueryPtr +Memfile_LeaseMgr::startSubnetLeaseStatsQuery6(const SubnetID& subnet_id) { + LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_, subnet_id)); + query->start(); + return(query); +} + +LeaseStatsQueryPtr +Memfile_LeaseMgr::startSubnetRangeLeaseStatsQuery6(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id) { + LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage6_, first_subnet_id, + last_subnet_id)); + query->start(); + return(query); +} +#endif + size_t Memfile_LeaseMgr::wipeLeases4(const SubnetID& subnet_id) { LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_WIPE_LEASES4) .arg(subnet_id); diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h index 81586566a8..98d9395e58 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -638,13 +638,35 @@ public: /// @brief Creates and runs the IPv4 lease stats query /// - /// It creates an instance of a MemfileLeaseStatsQuery4 and then - /// invokes its start method in which the query constructs its + /// It creates an instance of a MemfileLeaseStatsQuery4 for an all subnets + /// query and then invokes its start method in which the query constructs its /// statistical data result set. The query object is then returned. /// /// @return The populated query as a pointer to an LeaseStatsQuery virtual LeaseStatsQueryPtr startLeaseStatsQuery4(); + /// @brief Creates and runs the IPv4 lease stats query for a single subnet + /// + /// It creates an instance of a MemfileLeaseStatsQuery4 for a single subnet + /// query and then invokes its start method in which the query constructs its + /// statistical data result set. The query object is then returned. + /// + /// @param subnet_id id of the subnet for which stats are desired + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID& subnet_id); + + /// @brief Creates and runs the IPv4 lease stats query for a single subnet + /// + /// It creates an instance of a MemfileLeaseStatsQuery4 for a subnet range + /// query and then invokes its start method in which the query constructs its + /// statistical data result set. The query object is then returned. + /// + /// @param first_subnet_id first subnet in the range of subnets + /// @param last_subnet_id last subnet in the range of subnets + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id); + /// @brief Creates and runs the IPv6 lease stats query /// /// It creates an instance of a MemfileLeaseStatsQuery6 and then @@ -654,6 +676,30 @@ public: /// @return The populated query as a pointer to an LeaseStatsQuery. virtual LeaseStatsQueryPtr startLeaseStatsQuery6(); +#if 0 + /// @brief Creates and runs the IPv6 lease stats query for a single subnet + /// + /// It creates an instance of a MemfileLeaseStatsQuery6 for a single subnet + /// query and then invokes its start method in which the query constructs its + /// statistical data result set. The query object is then returned. + /// + /// @param subnet_id id of the subnet for which stats are desired + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID& subnet_id); + + /// @brief Creates and runs the IPv6 lease stats query for a single subnet + /// + /// It creates an instance of a MemfileLeaseStatsQuery4 for a subnet range + /// query and then invokes its start method in which the query constructs its + /// statistical data result set. The query object is then returned. + /// + /// @param first_subnet_id first subnet in the range of subnets + /// @param last_subnet_id last subnet in the range of subnets + /// @return A populated LeaseStatsQuery + virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID& first_subnet_id, + const SubnetID& last_subnet_id); +#endif + /// @name Protected methods used for %Lease File Cleanup. /// The following methods are protected so as they can be accessed and /// tested by unit tests. diff --git a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc index 41950543d7..a9f3f6253a 100644 --- a/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc @@ -2905,6 +2905,23 @@ GenericLeaseMgrTest::testLeaseStatsQuery4() { ASSERT_NO_THROW(CfgMgr::instance().commit()); + // Make sure invalid values throw. + LeaseStatsQueryPtr query; + ASSERT_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(0), BadValue); + ASSERT_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(0,1), BadValue); + ASSERT_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(1,0), BadValue); + ASSERT_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(10,1), BadValue); + + // Start tests with an empty expected row set. + RowSet expected_rows; + + // Before we add leases, test an empty return for get all subnets + { + SCOPED_TRACE("GET ALL WITH NO LEASES"); + ASSERT_NO_THROW(query = lmptr_->startLeaseStatsQuery4()); + checkQueryAgainstRowSet(query, expected_rows); + } + // Now let's insert some leases into subnet 1. // Two leases in the default state, i.e. assigned. // One lease in declined state. @@ -2928,39 +2945,55 @@ GenericLeaseMgrTest::testLeaseStatsQuery4() { makeLease4("192.0.3.2", subnet_id); makeLease4("192.0.3.3", subnet_id, Lease::STATE_DECLINED); - LeaseStatsQueryPtr query; - RowSet expected_rows; + // Test single subnet for non-matching subnet + { + SCOPED_TRACE("NO MATCHING SUBNET"); + ASSERT_NO_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(777)); + checkQueryAgainstRowSet(query, expected_rows); + } - // Test a non-matching single subnet - ASSERT_NO_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(777)); - checkQueryAgainstRowSet(query, expected_rows); + // Test an empty range + { + SCOPED_TRACE("EMPTY SUBNET RANGE"); + ASSERT_NO_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(777, 900)); + checkQueryAgainstRowSet(query, expected_rows); + } // Test a single subnet - // Add expected row for Subnet 2 - expected_rows.insert(LeaseStatsRow(2, Lease::STATE_DEFAULT, 0)); - expected_rows.insert(LeaseStatsRow(2, Lease::STATE_DECLINED, 1)); - // Start the query - ASSERT_NO_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(2)); - // Verify contents - checkQueryAgainstRowSet(query, expected_rows); + { + SCOPED_TRACE("SINGLE SUBNET"); + // Add expected row for Subnet 2 + expected_rows.insert(LeaseStatsRow(2, Lease::STATE_DEFAULT, 0)); + expected_rows.insert(LeaseStatsRow(2, Lease::STATE_DECLINED, 1)); + // Start the query + ASSERT_NO_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(2)); + // Verify contents + checkQueryAgainstRowSet(query, expected_rows); + } // Test a range of subnets - // Add expected rows for Subnet 3 - expected_rows.insert(LeaseStatsRow(3, Lease::STATE_DEFAULT, 2)); - expected_rows.insert(LeaseStatsRow(3, Lease::STATE_DECLINED, 1)); - // Start the query - ASSERT_NO_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(2,3)); - // Verify contents - checkQueryAgainstRowSet(query, expected_rows); + { + SCOPED_TRACE("SUBNET RANGE"); + // Add expected rows for Subnet 3 + expected_rows.insert(LeaseStatsRow(3, Lease::STATE_DEFAULT, 2)); + expected_rows.insert(LeaseStatsRow(3, Lease::STATE_DECLINED, 1)); + // Start the query + ASSERT_NO_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(2,3)); + // Verify contents + checkQueryAgainstRowSet(query, expected_rows); + } // Test all subnets - // Add expected rows for Subnet 1 - expected_rows.insert(LeaseStatsRow(1, Lease::STATE_DEFAULT, 2)); - expected_rows.insert(LeaseStatsRow(1, Lease::STATE_DECLINED, 1)); - // Start the query - ASSERT_NO_THROW(query = lmptr_->startLeaseStatsQuery4()); - // Verify contents - checkQueryAgainstRowSet(query, expected_rows); + { + SCOPED_TRACE("ALL SUBNETS"); + // Add expected rows for Subnet 1 + expected_rows.insert(LeaseStatsRow(1, Lease::STATE_DEFAULT, 2)); + expected_rows.insert(LeaseStatsRow(1, Lease::STATE_DECLINED, 1)); + // Start the query + ASSERT_NO_THROW(query = lmptr_->startLeaseStatsQuery4()); + // Verify contents + checkQueryAgainstRowSet(query, expected_rows); + } } }; // namespace test diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc index 7f015f0028..28e5c97e9b 100644 --- a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc @@ -372,6 +372,7 @@ TEST_F(LeaseMgrTest, getLease6) { 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()); @@ -382,7 +383,10 @@ TEST (LeaseStatsQueryTest, defaultCtor) { 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());