Commit 6c4cc8c9 authored by Shawn Routhier's avatar Shawn Routhier

[trac3667] Complete logging work and add soem stats

Complete the current working on using the basic logging system
for messages from LFC

Add lease_stats to provide a class to gather statistics
about reading and writing leases to files.  Currently this
is used by the CSV file code and output by LFC.  The
information counted is: number of attempts, number of leases
and number of errors generated during reads and writes.
parent c781d47b
......@@ -64,7 +64,7 @@ LFCController::launch(int argc, char* argv[], const bool test_mode) {
// If we aren't running in test mode initialize the logging
// system with the defaults.
if (!test_mode)
initLogger(lfc_app_name_, WARN, 0, NULL, false);
initLogger(lfc_app_name_, INFO, 0, NULL, false);
try {
parseArgs(argc, argv);
......@@ -345,6 +345,17 @@ LFCController::processLeases() const {
LeaseFileType lf_output(getOutputFile());
LeaseFileLoader::write<LeaseObjectType>(lf_output, storage);
// If desired log the stats
LOG_INFO(lfc_logger, LFC_READ_MESSAGE)
.arg(lf_prev.getReadLeases() + lf_copy.getReadLeases())
.arg(lf_prev.getReads() + lf_copy.getReads())
.arg(lf_prev.getReadErrs() + lf_copy.getReadErrs());
LOG_INFO(lfc_logger, LFC_WRITE_MESSAGE)
.arg(lf_output.getWriteLeases())
.arg(lf_output.getWrites())
.arg(lf_output.getWriteErrs());
// Once we've finished the output file move it to the complete file
if (rename(getOutputFile().c_str(), getFinishFile().c_str()) != 0) {
isc_throw(RunTimeFail, "Unable to move output (" << output_file_
......
......@@ -32,7 +32,17 @@ lease files.
This message is issued just before LFC starts rotating the
lease files - removing the old and replacing them with the new.
% LFC_FAILURE_MESSAGE LFC failed: %1
% LFC_FAILURE_MESSAGE : %1
This message is issued if LFC detected a failure when trying
to manipulate the files. It includes a more specifc error string.
% LFC_READ_MESSAGE Leases: %1, attempts: %2, errors: %3.
This message print out the number of leases that were read, the
number of attempts to read leases and the number of errors
encountered while reading.
% LFC_WRITE_MESSAGE Leases: %1, attempts: %2, errors: %3.
This message print out the number of leases that were written, the
number of attempts to write leases and the number of errors
encountered while writing.
......@@ -570,10 +570,10 @@ TEST_F(LFCControllerTest, launch6) {
string b_3 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,"
"300,1000,6,150,0,8,0,0,0,,\n";
string c_1 = "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,200,8,0,2,"
"16,64,0,0,,\n";
string c_2 = "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,400,8,0,2,"
"16,64,0,0,,\n";
string c_1 = "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
"100,200,8,0,2,16,64,0,0,,\n";
string c_2 = "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
"100,400,8,0,2,16,64,0,0,,\n";
string d_1 = "2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,"
"200,600,8,100,0,7,0,1,1,host.example.com,\n";
......
......@@ -85,6 +85,7 @@ libkea_dhcpsrv_la_SOURCES += lease.cc lease.h
libkea_dhcpsrv_la_SOURCES += lease_file_loader.h
libkea_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
libkea_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
libkea_dhcpsrv_la_SOURCES += lease_stats.h
libkea_dhcpsrv_la_SOURCES += logging.cc logging.h
libkea_dhcpsrv_la_SOURCES += logging_info.cc logging_info.h
libkea_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-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
......@@ -26,10 +26,25 @@ CSVLeaseFile4::CSVLeaseFile4(const std::string& filename)
}
void
CSVLeaseFile4::append(const Lease4& lease) const {
CSVLeaseFile4::open() {
// Call the base class to open the file
CSVFile::open();
// and clear any statistics we may have
clearStatistics();
}
void
CSVLeaseFile4::append(const Lease4& lease) {
// Bump the number of write attempts
++writes_;
CSVRow row(getColumnCount());
row.writeAt(getColumnIndex("address"), lease.addr_.toText());
if (!lease.hwaddr_) {
// Bump the error counter
++write_errs_;
isc_throw(BadValue, "Lease4 must have hardware address specified.");
}
row.writeAt(getColumnIndex("hwaddr"), lease.hwaddr_->toText(false));
......@@ -43,11 +58,24 @@ CSVLeaseFile4::append(const Lease4& lease) const {
row.writeAt(getColumnIndex("fqdn_fwd"), lease.fqdn_fwd_);
row.writeAt(getColumnIndex("fqdn_rev"), lease.fqdn_rev_);
row.writeAt(getColumnIndex("hostname"), lease.hostname_);
CSVFile::append(row);
try {
CSVFile::append(row);
} catch (const std::exception& ex) {
// Catch any errors so we can bump the error counter than rethrow it
++write_errs_;
throw;
}
// Bump the number of leases written
++write_leases_;
}
bool
CSVLeaseFile4::next(Lease4Ptr& lease) {
// Bump the number of read attempts
++reads_;
// Read the CSV row and try to create a lease from the values read.
// This may easily result in exception. We don't want this function
// to throw exceptions, so we catch them all and rather return the
......@@ -88,12 +116,19 @@ CSVLeaseFile4::next(Lease4Ptr& lease) {
readHostname(row)));
} catch (std::exception& ex) {
// bump the read error count
++read_errs_;
// The lease might have been created, so let's set it back to NULL to
// signal that lease hasn't been parsed.
lease.reset();
setReadMsg(ex.what());
return (false);
}
// bump the number of leases read
++read_leases_;
return (true);
}
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-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
......@@ -19,6 +19,7 @@
#include <dhcp/duid.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease_stats.h>
#include <util/csv_file.h>
#include <stdint.h>
#include <string>
......@@ -38,7 +39,7 @@ namespace dhcp {
/// validation (see http://kea.isc.org/ticket/2405). However, when #2405
/// is implemented, the @c next function may need to be updated to use the
/// validation capablity of @c Lease4.
class CSVLeaseFile4 : public isc::util::CSVFile {
class CSVLeaseFile4 : public isc::util::CSVFile, public LeaseFileStats {
public:
/// @brief Constructor.
......@@ -48,6 +49,13 @@ public:
/// @param filename Name of the lease file.
CSVLeaseFile4(const std::string& filename);
/// @brief Opens a lease file.
///
/// This function is used to clear the statistics while
/// calling the base class open. It doesn't throw any
/// exceptions of its own but the base class may.
void open();
/// @brief Appends the lease record to the CSV file.
///
/// This function doesn't throw exceptions itself. In theory, exceptions
......@@ -56,7 +64,7 @@ public:
/// error.
///
/// @param lease Structure representing a DHCPv4 lease.
void append(const Lease4& lease) const;
void append(const Lease4& lease);
/// @brief Reads next lease from the CSV file.
///
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-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
......@@ -27,7 +27,19 @@ CSVLeaseFile6::CSVLeaseFile6(const std::string& filename)
}
void
CSVLeaseFile6::append(const Lease6& lease) const {
CSVLeaseFile6::open() {
// Call the base class to open the file
CSVFile::open();
// and clear any statistics we may have
clearStatistics();
}
void
CSVLeaseFile6::append(const Lease6& lease) {
// Bump the number of write attempts
++writes_;
CSVRow row(getColumnCount());
row.writeAt(getColumnIndex("address"), lease.addr_.toText());
row.writeAt(getColumnIndex("duid"), lease.duid_->toText());
......@@ -46,11 +58,23 @@ CSVLeaseFile6::append(const Lease6& lease) const {
// We may not have hardware information
row.writeAt(getColumnIndex("hwaddr"), lease.hwaddr_->toText(false));
}
CSVFile::append(row);
try {
CSVFile::append(row);
} catch (const std::exception& ex) {
// Catch any errors so we can bump the error counter than rethrow it
++write_errs_;
throw;
}
// Bump the number of leases written
++write_leases_;
}
bool
CSVLeaseFile6::next(Lease6Ptr& lease) {
// Bump the number of read attempts
++reads_;
// Read the CSV row and try to create a lease from the values read.
// This may easily result in exception. We don't want this function
// to throw exceptions, so we catch them all and rather return the
......@@ -77,12 +101,19 @@ CSVLeaseFile6::next(Lease6Ptr& lease) {
lease->hostname_ = readHostname(row);
} catch (std::exception& ex) {
// bump the read error count
++read_errs_;
// The lease might have been created, so let's set it back to NULL to
// signal that lease hasn't been parsed.
lease.reset();
setReadMsg(ex.what());
return (false);
}
// bump the number of leases read
++read_leases_;
return (true);
}
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-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
......@@ -19,6 +19,7 @@
#include <dhcp/duid.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease_stats.h>
#include <util/csv_file.h>
#include <stdint.h>
#include <string>
......@@ -37,7 +38,7 @@ namespace dhcp {
/// validation (see http://kea.isc.org/ticket/2405). However, when #2405
/// is implemented, the @c next function may need to be updated to use the
/// validation capablity of @c Lease6.
class CSVLeaseFile6 : public isc::util::CSVFile {
class CSVLeaseFile6 : public isc::util::CSVFile, public LeaseFileStats {
public:
/// @brief Constructor.
......@@ -47,6 +48,13 @@ public:
/// @param filename Name of the lease file.
CSVLeaseFile6(const std::string& filename);
/// @brief Opens a lease file.
///
/// This function is used to clear the statistics while
/// calling the base class open. It doesn't throw any
/// exceptions of its own but the base class may.
void open();
/// @brief Appends the lease record to the CSV file.
///
/// This function doesn't throw exceptions itself. In theory, exceptions
......@@ -55,7 +63,7 @@ public:
/// error.
///
/// @param lease Structure representing a DHCPv6 lease.
void append(const Lease6& lease) const;
void append(const Lease6& lease);
/// @brief Reads next lease from the CSV file.
///
......
......@@ -43,8 +43,6 @@ namespace dhcp {
/// with the @c Lease4Storage and @c Lease6Storage to process the DHCPv4
/// and DHCPv6 leases respectively.
///
/// @todo Add a method which dumps all leases from the storage to a
/// specified lease file.
class LeaseFileLoader {
public:
......@@ -184,7 +182,7 @@ public:
/// @param storage A reference to the container from which leases
/// should be written.
///
/// @tparam LeasePtrType A @c Lease4 or @c Lease6.
/// @tparam LeaseObjectType A @c Lease4 or @c Lease6.
/// @tparam LeaseFileType A @c CSVLeaseFile4 or @c CSVLeaseFile6.
/// @tparam StorageType A @c Lease4Storage or @c Lease6Storage.
template<typename LeaseObjectType, typename LeaseFileType,
......
// Copyright (C) 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef LEASE_STATS_H
#define LEASE_STATS_H
namespace isc {
namespace dhcp {
/// @brief Provides statistics for leases.
///
/// This class provides a common space for statistics that we wish
/// to keep about leases. Currently this is foe use with lease files
/// but it may be exannded in the future.
class LeaseFileStats {
public:
/// @brief Constructor
///
/// Initializes the stats variables to zeros
LeaseFileStats() {
clearStatistics();
}
/// @brief Destructor
~LeaseFileStats() {
}
/// @brief Gets the number of attempts to read a lease
uint32_t getReads() {
return (reads_);
}
/// @brief Gets the number of leases read
uint32_t getReadLeases() {
return (read_leases_);
}
/// @brief Gets the number of errors when reading leases
uint32_t getReadErrs() {
return (read_errs_);
}
/// @brief Gets the number of attempts to write a lease
uint32_t getWrites() {
return (writes_);
}
/// @brief Gets the number of leases written
uint32_t getWriteLeases() {
return (write_leases_);
}
/// @brief Gets the number of errors when writting leases
uint32_t getWriteErrs() {
return (write_errs_);
}
/// @brief Clears the statistics
void clearStatistics() {
reads_ = 0;
read_leases_ = 0;
read_errs_ = 0;
writes_ = 0;
write_leases_ = 0;
write_errs_ = 0;
}
protected:
/// @brief Number of attempts to read a lease (calls to next), reset to 0 on open
uint32_t reads_;
/// @brief Number of leases read, reset to 0 on open
uint32_t read_leases_;
/// @brief Number of errors when reading, reset to 0 on open
uint32_t read_errs_;
/// @brief Number of attempts to write a lease, reset to 0 on open
uint32_t writes_;
/// @brief Number of lease written, reset to 0 on open
uint32_t write_leases_;
/// @brief Number of errors when writing , reset to 0 on open
uint32_t write_errs_;
private:
};
} // namespace isc::dhcp
} // namesapce isc
#endif // LEASE_STATS_H
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-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
......@@ -57,6 +57,19 @@ public:
/// @brief Creates the lease file to be parsed by unit tests.
void writeSampleFile() const;
/// @brief Checks the stats for the file
void checkStats(CSVLeaseFile4& lease_file,
uint32_t reads, uint32_t read_leases,
uint32_t read_errs, uint32_t writes,
uint32_t write_leases, uint32_t write_errs) const {
EXPECT_EQ(lease_file.getReads(), reads);
EXPECT_EQ(lease_file.getReadLeases(), read_leases);
EXPECT_EQ(lease_file.getReadErrs(), read_errs);
EXPECT_EQ(lease_file.getWrites(), writes);
EXPECT_EQ(lease_file.getWriteLeases(), write_leases);
EXPECT_EQ(lease_file.getWriteErrs(), write_errs);
}
/// @brief Name of the test lease file.
std::string filename_;
......@@ -104,10 +117,14 @@ TEST_F(CSVLeaseFile4Test, parse) {
boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
ASSERT_NO_THROW(lf->open());
// Verify the counters are cleared
checkStats(*lf, 0, 0, 0, 0, 0, 0);
Lease4Ptr lease;
// Reading first read should be successful.
EXPECT_TRUE(lf->next(lease));
ASSERT_TRUE(lease);
checkStats(*lf, 1, 1, 0, 0, 0, 0);
// Verify that the lease attributes are correct.
EXPECT_EQ("192.0.2.1", lease->addr_.toText());
......@@ -123,11 +140,14 @@ TEST_F(CSVLeaseFile4Test, parse) {
// Second lease is malformed - HW address is empty.
EXPECT_FALSE(lf->next(lease));
checkStats(*lf, 2, 1, 1, 0, 0, 0);
// Even though parsing previous lease failed, reading the next lease should be
// successful.
EXPECT_TRUE(lf->next(lease));
ASSERT_TRUE(lease);
checkStats(*lf, 3, 2, 1, 0, 0, 0);
// Verify that the third lease is correct.
EXPECT_EQ("192.0.3.15", lease->addr_.toText());
HWAddr hwaddr3(*lease->hwaddr_);
......@@ -145,11 +165,12 @@ TEST_F(CSVLeaseFile4Test, parse) {
// lease pointer should be NULL.
EXPECT_TRUE(lf->next(lease));
EXPECT_FALSE(lease);
checkStats(*lf, 4, 2, 1, 0, 0, 0);
// We should be able to do it again.
EXPECT_TRUE(lf->next(lease));
EXPECT_FALSE(lease);
checkStats(*lf, 5, 2, 1, 0, 0, 0);
}
// This test checks creation of the lease file and writing leases.
......@@ -157,6 +178,10 @@ TEST_F(CSVLeaseFile4Test, recreate) {
boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
ASSERT_NO_THROW(lf->recreate());
ASSERT_TRUE(io_.exists());
// Verify the counters are cleared
checkStats(*lf, 0, 0, 0, 0, 0, 0);
// Create first lease, with NULL client id.
Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
hwaddr0_,
......@@ -164,12 +189,16 @@ TEST_F(CSVLeaseFile4Test, recreate) {
200, 50, 80, 0, 8, true, true,
"host.example.com"));
ASSERT_NO_THROW(lf->append(*lease));
checkStats(*lf, 0, 0, 0, 1, 1, 0);
// Create second lease, with non-NULL client id.
lease.reset(new Lease4(IOAddress("192.0.3.10"),
hwaddr1_,
CLIENTID0, sizeof(CLIENTID0),
100, 60, 90, 0, 7));
ASSERT_NO_THROW(lf->append(*lease));
checkStats(*lf, 0, 0, 0, 2, 2, 0);
// Close the lease file.
lf->close();
// Check that the contents of the csv file are correct.
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-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
......@@ -63,6 +63,19 @@ public:
/// @brief Create lease file that can be parsed by unit tests.
void writeSampleFile() const;
/// @brief Checks the stats for the file
void checkStats(CSVLeaseFile6& lease_file,
uint32_t reads, uint32_t read_leases,
uint32_t read_errs, uint32_t writes,
uint32_t write_leases, uint32_t write_errs) const {
EXPECT_EQ(lease_file.getReads(), reads);
EXPECT_EQ(lease_file.getReadLeases(), read_leases);
EXPECT_EQ(lease_file.getReadErrs(), read_errs);
EXPECT_EQ(lease_file.getWrites(), writes);
EXPECT_EQ(lease_file.getWriteLeases(), write_leases);
EXPECT_EQ(lease_file.getWriteErrs(), write_errs);
}
/// @brief Name of the test lease file.
std::string filename_;
......@@ -105,10 +118,14 @@ TEST_F(CSVLeaseFile6Test, parse) {
boost::scoped_ptr<CSVLeaseFile6> lf(new CSVLeaseFile6(filename_));
ASSERT_NO_THROW(lf->open());
// Verify the counters are cleared
checkStats(*lf, 0, 0, 0, 0, 0, 0);
Lease6Ptr lease;
// Reading first read should be successful.
EXPECT_TRUE(lf->next(lease));
ASSERT_TRUE(lease);
checkStats(*lf, 1, 1, 0, 0, 0, 0);
// Verify that the lease attributes are correct.
EXPECT_EQ("2001:db8:1::1", lease->addr_.toText());
......@@ -127,11 +144,14 @@ TEST_F(CSVLeaseFile6Test, parse) {
// Second lease is malformed - DUID is empty.
EXPECT_FALSE(lf->next(lease));
checkStats(*lf, 2, 1, 1, 0, 0, 0);
// Even, parsing previous lease failed, reading the next lease should be
// successful.
EXPECT_TRUE(lf->next(lease));
ASSERT_TRUE(lease);
checkStats(*lf, 3, 2, 1, 0, 0, 0);
// Verify that the third lease is correct.
EXPECT_EQ("2001:db8:2::10", lease->addr_.toText());
ASSERT_TRUE(lease->duid_);
......@@ -150,6 +170,8 @@ TEST_F(CSVLeaseFile6Test, parse) {
// Reading the fourth lease should be successful.
EXPECT_TRUE(lf->next(lease));
ASSERT_TRUE(lease);
checkStats(*lf, 4, 3, 1, 0, 0, 0);
// Verify that the lease is correct.
EXPECT_EQ("3000:1::", lease->addr_.toText());
ASSERT_TRUE(lease->duid_);
......@@ -169,11 +191,12 @@ TEST_F(CSVLeaseFile6Test, parse) {
// lease pointer should be NULL.
EXPECT_TRUE(lf->next(lease));
EXPECT_FALSE(lease);
checkStats(*lf, 5, 3, 1, 0, 0, 0);
// We should be able to do it again.
EXPECT_TRUE(lf->next(lease));
EXPECT_FALSE(lease);
checkStats(*lf, 6, 3, 1, 0, 0, 0);
}
// This test checks creation of the lease file and writing leases.
......@@ -182,12 +205,16 @@ TEST_F(CSVLeaseFile6Test, recreate) {
ASSERT_NO_THROW(lf->recreate());
ASSERT_TRUE(io_.exists());
// Verify the counters are cleared
checkStats(*lf, 0, 0, 0, 0, 0, 0);
Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
makeDUID(DUID0, sizeof(DUID0)),
7, 100, 200, 50, 80, 8, true, true,
"host.example.com"));
lease->cltt_ = 0;
ASSERT_NO_THROW(lf->append(*lease));
checkStats(*lf, 0, 0, 0, 1, 1, 0);
lease.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:2::10"),
makeDUID(DUID1, sizeof(DUID1)),
......@@ -195,6 +222,7 @@ TEST_F(CSVLeaseFile6Test, recreate) {
"", HWAddrPtr(), 128));
lease->cltt_ = 0;
ASSERT_NO_THROW(lf->append(*lease));
checkStats(*lf, 0, 0, 0, 2, 2, 0);
lease.reset(new Lease6(Lease::TYPE_PD, IOAddress("3000:1:1::"),
makeDUID(DUID0, sizeof(DUID0)),
......@@ -202,6 +230,7 @@ TEST_F(CSVLeaseFile6Test, recreate) {
"", HWAddrPtr(), 64));
lease->cltt_ = 0;
ASSERT_NO_THROW(lf->append(*lease));
checkStats(*lf, 0, 0, 0, 3, 3, 0);
EXPECT_EQ("address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,"
"lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr\n"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment