Browse Source

[2342] Add selection of Lease6 by DUID and IAID

Stephen Morris 12 years ago
parent
commit
0a14e05f42

+ 1 - 1
src/lib/dhcp/lease_mgr.h

@@ -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
 ///

+ 105 - 22
src/lib/dhcp/mysql_lease_mgr.cc

@@ -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

+ 7 - 6
src/lib/dhcp/mysql_lease_mgr.h

@@ -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

+ 216 - 78
src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc

@@ -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_;
-    l1->type_ = Lease6::LEASE_IA_PD;
-    l1->valid_lft_ *= 2;
-    lmptr_->updateLease6(l1);
+    ++leases[1]->iaid_;
+    leases[1]->type_ = Lease6::LEASE_IA_PD;
+    leases[1]->valid_lft_ *= 2;
+    lmptr_->updateLease6(leases[1]);
     lmptr_->commit();
     reopen();
 
@@ -466,31 +606,29 @@ TEST_F(MySqlLeaseMgrTest, UpdateLease6) {
     l_returned.reset();
     l_returned = lmptr_->getLease6(L1_IOADDRESS);
     EXPECT_TRUE(l_returned);
-    detailCompareLease6(l1, l_returned);
+    detailCompareLease6(leases[1], l_returned);
 
     // Alter the lease again and check.
-    ++l1->iaid_;
-    l1->type_ = Lease6::LEASE_IA_TA;
-    l1->cltt_ += 6;
-    l1->prefixlen_ = 93;
-    lmptr_->updateLease6(l1);
+    ++leases[1]->iaid_;
+    leases[1]->type_ = Lease6::LEASE_IA_TA;
+    leases[1]->cltt_ += 6;
+    leases[1]->prefixlen_ = 93;
+    lmptr_->updateLease6(leases[1]);
 
     l_returned.reset();
     l_returned = lmptr_->getLease6(L1_IOADDRESS);
     EXPECT_TRUE(l_returned);
-    detailCompareLease6(l1, l_returned);
+    detailCompareLease6(leases[1], l_returned);
 
     // Check we can do an update without changing data.
-    lmptr_->updateLease6(l1);
+    lmptr_->updateLease6(leases[1]);
     l_returned.reset();
     l_returned = lmptr_->getLease6(L1_IOADDRESS);
     EXPECT_TRUE(l_returned);
-    detailCompareLease6(l1, l_returned);
+    detailCompareLease6(leases[1], l_returned);
 
-    // Try updating a non-existent lease.
-    Lease6Ptr l2 = initializeLease6(L2_ADDRESS);
-    ASSERT_TRUE(l2);
-    EXPECT_THROW(lmptr_->updateLease6(l2), isc::dhcp::NoSuchLease);
+    // Try updating a lease not in the database.
+    EXPECT_THROW(lmptr_->updateLease6(leases[2]), isc::dhcp::NoSuchLease);
 }
 
 }; // end of anonymous namespace