Commit 0a14e05f authored by Stephen Morris's avatar Stephen Morris

[2342] Add selection of Lease6 by DUID and IAID

parent 43428694
......@@ -316,7 +316,7 @@ typedef boost::shared_ptr<Lease6> Lease6Ptr;
typedef boost::shared_ptr<const Lease6> ConstLease6Ptr;
/// @brief A collection of IPv6 leases.
typedef std::vector< boost::shared_ptr<Lease6Ptr> > Lease6Collection;
typedef std::vector<Lease6Ptr> Lease6Collection;
/// @brief Abstract Lease Manager
///
......
......@@ -64,7 +64,13 @@ namespace dhcp {
class MySqlLease6Exchange {
public:
/// @brief Constructor
MySqlLease6Exchange() : false_(0), true_(1) {
///
/// Apart from the initialization of false_ and true_, the other
/// initializations are to satisfy cppcheck: none are really needed, as all
/// variables are initialized/set in the methods.
MySqlLease6Exchange() : addr6_length_(0), duid_length_(0), false_(0), true_(1) {
memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
memset(duid_buffer_, 0, sizeof(duid_buffer_));
}
/// @brief Create MYSQL_BIND objects for Lease6 Pointer
......@@ -522,11 +528,16 @@ MySqlLeaseMgr::prepareStatements() {
// Now allocate the statements
prepareStatement(DELETE_LEASE6,
"DELETE FROM lease6 WHERE address = ?");
prepareStatement(GET_LEASE6,
prepareStatement(GET_LEASE6_ADDR,
"SELECT address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len "
"FROM lease6 WHERE address = ?");
prepareStatement(GET_LEASE6_DUID_IAID,
"SELECT address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len "
"FROM lease6 WHERE duid = ? AND iaid = ?");
prepareStatement(GET_VERSION,
"SELECT version, minor FROM schema_version");
prepareStatement(INSERT_LEASE6,
......@@ -636,25 +647,25 @@ MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
// Bind the input parameters to the statement
int status = mysql_stmt_bind_param(statements_[GET_LEASE6_ADDR], inbind);
checkError(status, GET_LEASE6_ADDR, "unable to bind WHERE clause parameter");
// Set up the SELECT clause
MySqlLease6Exchange exchange;
std::vector<MYSQL_BIND> outbind;
exchange.createBindForReceive(outbind);
// Bind the input parameters to the statement
int status = mysql_stmt_bind_param(statements_[GET_LEASE6], inbind);
checkError(status, GET_LEASE6, "unable to bind WHERE clause parameter");
// Bind the output parameters to the statement
status = mysql_stmt_bind_result(statements_[GET_LEASE6], &outbind[0]);
checkError(status, GET_LEASE6, "unable to bind SELECT caluse parameters");
status = mysql_stmt_bind_result(statements_[GET_LEASE6_ADDR], &outbind[0]);
checkError(status, GET_LEASE6_ADDR, "unable to bind SELECT caluse parameters");
// Execute the statement
status = mysql_stmt_execute(statements_[GET_LEASE6]);
checkError(status, GET_LEASE6, "unable to execute");
status = mysql_stmt_execute(statements_[GET_LEASE6_ADDR]);
checkError(status, GET_LEASE6_ADDR, "unable to execute");
// Fetch the data.
status = mysql_stmt_fetch(statements_[GET_LEASE6]);
status = mysql_stmt_fetch(statements_[GET_LEASE6_ADDR]);
Lease6Ptr result;
if (status == 0) {
......@@ -663,11 +674,11 @@ MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
} catch (const isc::BadValue& ex) {
// Free up result set.
(void) mysql_stmt_free_result(statements_[GET_LEASE6]);
(void) mysql_stmt_free_result(statements_[GET_LEASE6_ADDR]);
// Lease type is returned, to rethrow the exception with a bit
// more data.
isc_throw(BadValue, ex.what() << ". Statement is <" <<
text_statements_[GET_LEASE6] << ">");
text_statements_[GET_LEASE6_ADDR] << ">");
}
// As the address is the primary key in the table, we can't return
......@@ -675,23 +686,95 @@ MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
// been returned.
} else if (status == 1) {
checkError(status, GET_LEASE6, "unable to fetch results");
checkError(status, GET_LEASE6_ADDR, "unable to fetch results");
} else {
// We are ignoring truncation for now, so the only other result is
// no data was found. In that case, we return a null Lease6 structure.
// This has already been set, so ther action is a no-op.
// @TODO Handle truncation
// We are ignoring truncation for now, so the only other result is
// no data was found. In that case, we return a null Lease6 structure.
// This has already been set, so the action is a no-op.
}
(void) mysql_stmt_free_result(statements_[GET_LEASE6]);
// Free data structures associated with information returned.
(void) mysql_stmt_free_result(statements_[GET_LEASE6_ADDR]);
return (result);
}
Lease6Collection
MySqlLeaseMgr::getLease6(const DUID& /* duid */, uint32_t /* iaid */) const {
isc_throw(NotImplemented, "MySqlLeaseMgr::getLease6(const DUID&) "
"not implemented yet");
return (Lease6Collection());
MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
// Set up the WHERE clause value
MYSQL_BIND inbind[2];
memset(inbind, 0, sizeof(inbind));
// DUID. The complex casting is needed to obtain the "const" vector of
// uint8_t from the DUID, point to the start of it (discarding the
// "const"ness) and finally casing it to "char*" for the MySQL buffer
// element.
const vector<uint8_t>& duid_vector = duid.getDuid();
unsigned long duid_length = duid_vector.size();
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(
const_cast<uint8_t*>(&duid_vector[0]));
inbind[0].buffer_length = duid_length;
inbind[0].length = &duid_length;
// IAID
inbind[1].buffer_type = MYSQL_TYPE_LONG;
inbind[1].buffer = reinterpret_cast<char*>(&iaid);
inbind[1].is_unsigned = static_cast<my_bool>(1);
// Bind the input parameters to the statement
int status = mysql_stmt_bind_param(statements_[GET_LEASE6_DUID_IAID], inbind);
checkError(status, GET_LEASE6_DUID_IAID, "unable to bind WHERE clause parameter");
// Set up the SELECT clause
MySqlLease6Exchange exchange;
std::vector<MYSQL_BIND> outbind;
exchange.createBindForReceive(outbind);
// Bind the output parameters to the statement
status = mysql_stmt_bind_result(statements_[GET_LEASE6_DUID_IAID], &outbind[0]);
checkError(status, GET_LEASE6_DUID_IAID, "unable to bind SELECT clause parameters");
// Execute the query.
status = mysql_stmt_execute(statements_[GET_LEASE6_DUID_IAID]);
checkError(status, GET_LEASE6_DUID_IAID, "unable to execute");
// Ensure that all the lease information is retrieved in one go to avoid overhead
// of going back and forth between client and server.
status = mysql_stmt_store_result(statements_[GET_LEASE6_DUID_IAID]);
checkError(status, GET_LEASE6_DUID_IAID, "unable to set up for storing all results");
// Fetch the data. There could be multiple rows, so we need to iterate
// until all data has been retrieved.
Lease6Collection result;
while ((status = mysql_stmt_fetch(statements_[GET_LEASE6_DUID_IAID])) == 0) {
try {
Lease6Ptr lease = exchange.getLeaseData();
result.push_back(lease);
} catch (const isc::BadValue& ex) {
// Free up result set.
(void) mysql_stmt_free_result(statements_[GET_LEASE6_DUID_IAID]);
// Rethrow the exception with a bit more data.
isc_throw(BadValue, ex.what() << ". Statement is <" <<
text_statements_[GET_LEASE6_DUID_IAID] << ">");
}
}
// How did the fetch end?
if (status == 1) {
// Error - unable to fecth results
checkError(status, GET_LEASE6_DUID_IAID, "unable to fetch results");
} else if (status == MYSQL_DATA_TRUNCATED) {
// @TODO Handle truncation
;
}
// Free up resources assoicated with the fetched data.
(void) mysql_stmt_free_result(statements_[GET_LEASE6_DUID_IAID]);
return (result);
}
Lease6Ptr
......
......@@ -331,12 +331,13 @@ private:
///
/// The contents of the enum are indexes into the list of SQL statements
enum StatementIndex {
DELETE_LEASE6, // Delete from lease6 by address
GET_LEASE6, // Get lease 6 by address
GET_VERSION, // Obtain version number
INSERT_LEASE6, // Add entry to lease6 table
UPDATE_LEASE6, // Update a Lease6 entry
NUM_STATEMENTS // Number of statements
DELETE_LEASE6, // Delete from lease6 by address
GET_LEASE6_ADDR, // Get lease6 by address
GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID
GET_VERSION, // Obtain version number
INSERT_LEASE6, // Add entry to lease6 table
UPDATE_LEASE6, // Update a Lease6 entry
NUM_STATEMENTS // Number of statements
};
/// @brief Prepare Single Statement
......
......@@ -31,9 +31,14 @@ using namespace std;
namespace {
// IPv6 addresseses
const char* ADDRESS_0 = "2001:db8::0";
const char* ADDRESS_1 = "2001:db8::1";
const char* ADDRESS_2 = "2001:db8::2";
const char* ADDRESS_3 = "2001:db8::3";
const char* ADDRESS_4 = "2001:db8::4";
const char* ADDRESS_5 = "2001:db8::5";
const char* ADDRESS_6 = "2001:db8::6";
const char* ADDRESS_7 = "2001:db8::7";
// Connection strings. Assume:
// Database: keatest
......@@ -98,6 +103,10 @@ validConnectionString() {
VALID_USER, VALID_PASSWORD));
}
// Note: Doxygen "///" not used - even though Doxygen is used to
// document class and methods - to avoid the comments appearing
// in the programming manual.
// @brief Test Fixture Class
//
// Opens the database prior to each test and closes it afterwards.
......@@ -105,45 +114,50 @@ validConnectionString() {
class MySqlLeaseMgrTest : public ::testing::Test {
public:
/// @brief Constructor
///
/// Deletes everything from the database and opens it.
MySqlLeaseMgrTest() : L1_ADDRESS(ADDRESS_1), L2_ADDRESS(ADDRESS_2),
L3_ADDRESS(ADDRESS_3), L1_IOADDRESS(L1_ADDRESS),
L2_IOADDRESS(L2_ADDRESS), L3_IOADDRESS(L3_ADDRESS)
{
// @brief Constructor
//
// Deletes everything from the database and opens it.
MySqlLeaseMgrTest() :
L0_ADDRESS(ADDRESS_0), L0_IOADDRESS(L0_ADDRESS),
L1_ADDRESS(ADDRESS_1), L1_IOADDRESS(L1_ADDRESS),
L2_ADDRESS(ADDRESS_2), L2_IOADDRESS(L2_ADDRESS),
L3_ADDRESS(ADDRESS_3), L3_IOADDRESS(L3_ADDRESS),
L4_ADDRESS(ADDRESS_4), L4_IOADDRESS(L4_ADDRESS),
L5_ADDRESS(ADDRESS_5), L5_IOADDRESS(L5_ADDRESS),
L6_ADDRESS(ADDRESS_6), L6_IOADDRESS(L6_ADDRESS),
L7_ADDRESS(ADDRESS_7), L7_IOADDRESS(L7_ADDRESS)
{
clearAll();
LeaseMgrFactory::create(validConnectionString());
lmptr_ = &(LeaseMgrFactory::instance());
}
/// @brief Destructor
///
/// Rolls back all pending transactions. The deletion of the
/// lmptr_ member variable will close the database. Then
/// reopen it and delete everything created by the test.
// @brief Destructor
//
// Rolls back all pending transactions. The deletion of the
// lmptr_ member variable will close the database. Then
// reopen it and delete everything created by the test.
virtual ~MySqlLeaseMgrTest() {
lmptr_->rollback();
LeaseMgrFactory::destroy();
clearAll();
}
/// @brief Reopen the database
///
/// Closes the database and re-open it. Anything committed should be
/// visible.
// @brief Reopen the database
//
// Closes the database and re-open it. Anything committed should be
// visible.
void reopen() {
LeaseMgrFactory::destroy();
LeaseMgrFactory::create(validConnectionString());
lmptr_ = &(LeaseMgrFactory::instance());
}
/// @brief Clear everything from the database tables
///
/// There is no error checking in this code, as this is just
/// extra checking that the database is clear before the text.
void
clearAll() {
// @brief Clear everything from the database tables
//
// There is no error checking in this code, as this is just
// extra checking that the database is clear before the text.
void clearAll() {
// Initialise
MYSQL handle;
(void) mysql_init(&handle);
......@@ -172,7 +186,6 @@ public:
//
// @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());
......@@ -188,8 +201,18 @@ public:
lease->fqdn_rev_ = false; // Unused
lease->comments_ = std::string(""); // Unused
// Set the other parameters
if (address == L1_ADDRESS) {
// Set the other parameters. For historical reasons, L0_ADDRESS is not used.
if (address == L0_ADDRESS) {
lease->type_ = Lease6::LEASE_IA_TA;
lease->prefixlen_ = 4;
lease->iaid_ = 142;
lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x77)));
lease->preferred_lft_ = 900; // Preferred lifetime
lease->valid_lft_ = 8677; // Actual lifetime
lease->cltt_ = 168256; // Current time of day
lease->subnet_id_ = 23; // Arbitrary number
} else if (address == L1_ADDRESS) {
lease->type_ = Lease6::LEASE_IA_TA;
lease->prefixlen_ = 0;
lease->iaid_ = 42;
......@@ -209,14 +232,13 @@ public:
lease->cltt_ = 234567; // Current time of day
lease->subnet_id_ = 73; // Same as for L1_ADDRESS
} else if (address == L3_ADDRESS) {
lease->type_ = Lease6::LEASE_IA_NA;
lease->prefixlen_ = 28;
lease->iaid_ = 0xfffffffe;
vector<uint8_t> duid;
for (uint8_t i = 0; i < 128; ++i) {
duid.push_back(i + 5);
for (uint8_t i = 31; i < 126; ++i) {
duid.push_back(i);
}
lease->duid_ = boost::shared_ptr<DUID>(new DUID(duid));
......@@ -229,6 +251,50 @@ public:
lease->cltt_ = 234567; // Current time of day
lease->subnet_id_ = 37; // Different from L1 and L2
} else if (address == L4_ADDRESS) {
// Same DUID and IAID as L1_ADDRESS
lease->type_ = Lease6::LEASE_IA_PD;
lease->prefixlen_ = 15;
lease->iaid_ = 42;
lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
lease->preferred_lft_ = 4800; // Preferred lifetime
lease->valid_lft_ = 7736; // Actual lifetime
lease->cltt_ = 222456; // Current time of day
lease->subnet_id_ = 75; // Arbitrary number
} else if (address == L5_ADDRESS) {
// Same DUID and IAID as L1_ADDRESS
lease->type_ = Lease6::LEASE_IA_PD;
lease->prefixlen_ = 24;
lease->iaid_ = 42;
lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
lease->preferred_lft_ = 5400; // Preferred lifetime
lease->valid_lft_ = 7832; // Actual lifetime
lease->cltt_ = 227476; // Current time of day
lease->subnet_id_ = 175; // Arbitrary number
} else if (address == L6_ADDRESS) {
// Same DUID as L1_ADDRESS
lease->type_ = Lease6::LEASE_IA_PD;
lease->prefixlen_ = 24;
lease->iaid_ = 93;
lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
lease->preferred_lft_ = 5400; // Preferred lifetime
lease->valid_lft_ = 1832; // Actual lifetime
lease->cltt_ = 627476; // Current time of day
lease->subnet_id_ = 112; // Arbitrary number
} else if (address == L7_ADDRESS) {
// Same IAID as L1_ADDRESS
lease->type_ = Lease6::LEASE_IA_PD;
lease->prefixlen_ = 24;
lease->iaid_ = 42;
lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xe5)));
lease->preferred_lft_ = 5600; // Preferred lifetime
lease->valid_lft_ = 7975; // Actual lifetime
lease->cltt_ = 213876; // Current time of day
lease->subnet_id_ = 19; // Arbitrary number
} else {
// Unknown address, return an empty pointer.
lease.reset();
......@@ -238,17 +304,69 @@ public:
return (lease);
}
// @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
vector<Lease6Ptr> leases;
leases.push_back(initializeLease6(L0_ADDRESS));
leases.push_back(initializeLease6(L1_ADDRESS));
leases.push_back(initializeLease6(L2_ADDRESS));
leases.push_back(initializeLease6(L3_ADDRESS));
leases.push_back(initializeLease6(L4_ADDRESS));
leases.push_back(initializeLease6(L5_ADDRESS));
leases.push_back(initializeLease6(L6_ADDRESS));
leases.push_back(initializeLease6(L7_ADDRESS));
EXPECT_EQ(8, leases.size());
// Check they were created
for (int i = 0; i < leases.size(); ++i) {
EXPECT_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) {
EXPECT_TRUE(leases[i] != leases[j]);
}
}
return (leases);
}
// Member variables
LeaseMgr* lmptr_; // Pointer to the lease manager
string L1_ADDRESS; // String form of address 1
string L2_ADDRESS; // String form of address 2
string L3_ADDRESS; // String form of address 3
string L0_ADDRESS; // String form of address 1
IOAddress L0_IOADDRESS; // IOAddress form of L1_ADDRESS
string L1_ADDRESS; // String form of address 1
IOAddress L1_IOADDRESS; // IOAddress form of L1_ADDRESS
string L2_ADDRESS; // String form of address 2
IOAddress L2_IOADDRESS; // IOAddress form of L2_ADDRESS
string L3_ADDRESS; // String form of address 3
IOAddress L3_IOADDRESS; // IOAddress form of L3_ADDRESS
string L4_ADDRESS; // String form of address 4
IOAddress L4_IOADDRESS; // IOAddress form of L4_ADDRESS
string L5_ADDRESS; // String form of address 5
IOAddress L5_IOADDRESS; // IOAddress form of L5_ADDRESS
string L6_ADDRESS; // String form of address 6
IOAddress L6_IOADDRESS; // IOAddress form of L6_ADDRESS
string L7_ADDRESS; // String form of address 7
IOAddress L7_IOADDRESS; // IOAddress form of L7_ADDRESS
};
......@@ -382,46 +500,33 @@ detailCompareLease6(const Lease6Ptr& first, const Lease6Ptr& second) {
// Tests where a collection of leases can be returned are in the test
// Lease6Collection.
TEST_F(MySqlLeaseMgrTest, BasicLease6) {
// Define the leases being used for testing.
Lease6Ptr l1 = initializeLease6(L1_ADDRESS);
ASSERT_TRUE(l1);
Lease6Ptr l2 = initializeLease6(L2_ADDRESS);
ASSERT_TRUE(l2);
Lease6Ptr l3 = initializeLease6(L3_ADDRESS);
ASSERT_TRUE(l3);
// Sanity check that the leases are different
ASSERT_TRUE(*l1 != *l2);
ASSERT_TRUE(*l1 != *l3);
ASSERT_TRUE(*l2 != *l3);
// Get the leases to be used for the test.
vector<Lease6Ptr> leases = createLeases6();
// Start the tests. Add three leases to the database, read them back and
// check they are what we think they are.
Lease6Ptr l_returned;
EXPECT_TRUE(lmptr_->addLease(l1));
EXPECT_TRUE(lmptr_->addLease(l2));
EXPECT_TRUE(lmptr_->addLease(l3));
EXPECT_TRUE(lmptr_->addLease(leases[1]));
EXPECT_TRUE(lmptr_->addLease(leases[2]));
EXPECT_TRUE(lmptr_->addLease(leases[3]));
lmptr_->commit();
// Reopen the database to ensure that they actually got stored.
reopen();
l_returned = lmptr_->getLease6(L1_IOADDRESS);
Lease6Ptr l_returned = lmptr_->getLease6(L1_IOADDRESS);
EXPECT_TRUE(l_returned);
detailCompareLease6(l1, l_returned);
detailCompareLease6(leases[1], l_returned);
l_returned = lmptr_->getLease6(L2_IOADDRESS);
EXPECT_TRUE(l_returned);
detailCompareLease6(l2, l_returned);
detailCompareLease6(leases[2], l_returned);
l_returned = lmptr_->getLease6(L3_IOADDRESS);
EXPECT_TRUE(l_returned);
detailCompareLease6(l3, l_returned);
detailCompareLease6(leases[3], l_returned);
// Check that we can't add a second lease with the same address
EXPECT_FALSE(lmptr_->addLease(l1));
EXPECT_FALSE(lmptr_->addLease(leases[1]));
// Delete a lease, check that it's gone, and that we can't delete it
// a second time.
......@@ -433,32 +538,67 @@ TEST_F(MySqlLeaseMgrTest, BasicLease6) {
// Check that the second address is still there.
l_returned = lmptr_->getLease6(L2_IOADDRESS);
EXPECT_TRUE(l_returned);
detailCompareLease6(l2, l_returned);
detailCompareLease6(leases[2], l_returned);
}
// @brief Check GetLease6 methods - Access by DUID/IAID
//
// Adds leases to the database and checks that they can be accessed via
// a combination of DIUID and IAID.
TEST_F(MySqlLeaseMgrTest, GetLease6Extended1) {
// Get the leases to be used for the test.
vector<Lease6Ptr> leases = createLeases6();
EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5
// Add them to the database
for (int i = 0; i < leases.size(); ++i) {
EXPECT_TRUE(lmptr_->addLease(leases[i]));
}
// Get the leases matching the DUID and IAID of lease[1].
Lease6Collection returned = lmptr_->getLease6(*leases[1]->duid_,
leases[1]->iaid_);
// Should be three leases, matching leases[1], [4] and [5].
ASSERT_EQ(3, returned.size());
// Easiest way to check is to look at the addresses.
vector<string> addresses;
for (Lease6Collection::const_iterator i = returned.begin();
i != returned.end(); ++i) {
addresses.push_back((*i)->addr_.toText());
}
sort(addresses.begin(), addresses.end());
EXPECT_EQ(L1_ADDRESS, addresses[0]);
EXPECT_EQ(L4_ADDRESS, addresses[1]);
EXPECT_EQ(L5_ADDRESS, addresses[2]);
}
// @brief Lease6 Update Tests
//
// Checks that we are able to update a lease in the database.
TEST_F(MySqlLeaseMgrTest, UpdateLease6) {
// Define the leases being used for testing.
Lease6Ptr l1 = initializeLease6(L1_ADDRESS);
ASSERT_TRUE(l1);
// Get the leases to be used for the test.
vector<Lease6Ptr> leases = createLeases6();
EXPECT_LE(3, leases.size()); // Expect to access leases 0 through 5
// Add a lease to the database and check that the lease is there.
EXPECT_TRUE(lmptr_->addLease(l1));
EXPECT_TRUE(lmptr_->addLease(leases[1]));
lmptr_->commit();
reopen();
Lease6Ptr l_returned = lmptr_->getLease6(L1_IOADDRESS);
EXPECT_TRUE(l_returned);
detailCompareLease6(l1, l_returned);
detailCompareLease6(leases[1], l_returned);
// Modify some fields in lease 1 (not the address) and update it.
++l1->iaid_;