]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2869] Checkpoint: start new UTs
authorFrancis Dupont <fdupont@isc.org>
Fri, 26 May 2023 00:38:34 +0000 (02:38 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 6 Jul 2023 20:11:33 +0000 (22:11 +0200)
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/tests/mysql_lease_extended_info_unittest.cc
src/lib/dhcpsrv/tests/pgsql_lease_extended_info_unittest.cc

index 257913ab65880de6a8cc04bcbdb867971859ecaa..e124fc8dd2604b72a7a2c638f4f42e5231a0e951 100644 (file)
@@ -314,7 +314,7 @@ PgSqlTaggedStatement tagged_statements[] = {
 
     // GET_LEASE6_ADDR_ANY
     { 1, { OID_VARCHAR },
-      "get_lease6_addr_nay",
+      "get_lease6_addr_any",
       "SELECT address, duid, valid_lifetime, "
         "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
         "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
@@ -3593,8 +3593,8 @@ PgSqlLeaseMgr::getLeases6ByRelayId(const DUID& relay_id,
         PsqlBindArray bind_array;
 
         // Bind the lease address.
-        std::vector<uint8_t> addr_data = addr.toBytes();
-        bind_array.add(addr_data);
+        std::string addr_str = addr.toText();
+        bind_array.add(addr_str);
 
         // Get the lease.
         Lease6Ptr lease;
@@ -3728,8 +3728,8 @@ PgSqlLeaseMgr::getLeases6ByRemoteId(const OptionBuffer& remote_id,
         PsqlBindArray bind_array;
 
         // Bind the lease address.
-        std::vector<uint8_t> addr_data = addr.toBytes();
-        bind_array.add(addr_data);
+        std::string addr_str = addr.toText();
+        bind_array.add(addr_str);
 
         // Get the lease.
         Lease6Ptr lease;
index fda21951b1563ed6f4d40ce46c7c0cf54d8d11a4..0c2d7fc404766b59f346daad85aa2e5be9d26ea4 100644 (file)
@@ -48,6 +48,31 @@ const vector<string> DUIDS = {
     "BBBBBBBB", "$$$$$$$$", "^^^^^^^^", "\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5"
 };
 
+/// @brief A derivation of the lease manager exposing protected methods.
+class NakedMySqlLeaseMgr : public MySqlLeaseMgr {
+public:
+    /// @brief Constructor.
+    ///
+    /// Creates an instance of the lease manager.
+    ///
+    /// @param parameters Parameter map.
+    NakedMySqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
+        : MySqlLeaseMgr(parameters) {
+    }
+
+    /// @brief Destructor.
+    virtual ~NakedMySqlLeaseMgr() {
+    }
+
+    /// @brief Exposes protected methods.
+    using MySqlLeaseMgr::deleteExtendedInfo6;
+    using MySqlLeaseMgr::addRelayId6;
+    using MySqlLeaseMgr::addRemoteId6;
+};
+
+/// @brief Type of unique pointers to naked lease manager.
+typedef unique_ptr<NakedMySqlLeaseMgr> NakedMySqlLeaseMgrPtr;
+
 /// @brief Test fixture class for extended info tests.
 class MySqlExtendedInfoTest : public ::testing::Test {
 public:
@@ -56,19 +81,8 @@ public:
         // Ensure we have the proper schema with no transient data.
         createMySQLSchema();
 
-        // Connect to the database.
-        try {
-            LeaseMgrFactory::create(validMySQLConnectionString());
-        } catch (...) {
-            std::cerr << "*** ERROR: unable to open database. The test\n"
-                         "*** environment is broken and must be fixed before\n"
-                         "*** the MySQL tests will run correctly.\n"
-                         "*** The reason for the problem is described in the\n"
-                         "*** accompanying exception output.\n";
-            throw;
-        }
-
-        lease_mgr_ = &(LeaseMgrFactory::instance());
+        pmap_ = DatabaseConnection::parse(validMySQLConnectionString());
+        lease_mgr_.reset();
         leases4.clear();
         leases6.clear();
         MultiThreadingMgr::instance().setMode(false);
@@ -77,14 +91,15 @@ public:
 
     /// @brief Destructor.
     ~MySqlExtendedInfoTest() {
-        LeaseMgrFactory::destroy();
-        // If data wipe enabled, delete transient data otherwise destroy
-        // the schema.
-        destroyMySQLSchema();
-
+        pmap_.clear();
+        lease_mgr_.reset();
         leases4.clear();
         leases6.clear();
         MultiThreadingMgr::instance().setMode(false);
+
+        // If data wipe enabled, delete transient data otherwise destroy
+        // the schema.
+        destroyMySQLSchema();
     }
 
     /// @brief Create and set v4 leases.
@@ -129,6 +144,23 @@ public:
         ASSERT_EQ(ADDRESS6.size(), leases6.size());
     }
 
+    /// @brief Start lease manager.
+    ///
+    /// @param enable When true enable extended info tables.
+    void start(bool enable) {
+        // Do not set unused pmap_["universe"].
+        if (enable) {
+            pmap_["extended-info-tables"] = "true";
+        }
+
+        ASSERT_NO_THROW(lease_mgr_.reset(new NakedMySqlLeaseMgr(pmap_)));
+        if (enable) {
+            EXPECT_TRUE(lease_mgr_->getExtendedInfoTablesEnabled());
+        } else {
+            EXPECT_FALSE(lease_mgr_->getExtendedInfoTablesEnabled());
+        }
+    }
+
     /// @brief Create a vector of uint8_t from a string.
     ///
     /// @param content A not empty string holding the content.
@@ -156,11 +188,23 @@ public:
     void testUpgradeExtendedInfo4(const CfgConsistency::ExtendedInfoSanity& check,
                                   const LeasePageSize& page_size);
 
+    /// @brief Test initLease6 with tables.
+    void testEnableTables();
+
+    /// @brief Test getLeases6ByRelayId.
+    void testGetLeases6ByRelayId();
+
+    /// @brief Test getLeases6ByRemoteId.
+    void testGetLeases6ByRemoteId();
+
     /// @brief Test getLeases6ByLink.
     void testGetLeases6ByLink();
 
+    /// @brief Parameter map.
+    DatabaseConnection::ParameterMap pmap_;
+
     /// @brief Lease manager.
-    LeaseMgr* lease_mgr_;
+    NakedMySqlLeaseMgrPtr lease_mgr_;
 
     /// @brief V4 leases.
     Lease4Collection leases4;
@@ -172,9 +216,32 @@ public:
     time_t now_;
 };
 
+/// @brief Verifies that the lease manager can start.
+TEST_F(MySqlExtendedInfoTest, startFalse) {
+    start(false);
+}
+
+/// @brief Verifies that the lease manager can start with MT.
+TEST_F(MySqlExtendedInfoTest, startFalseMultiThreading) {
+    MultiThreadingTest mt(true);
+    start(false);
+}
+
+/// @brief Verifies that the lease manager can start with tables.
+TEST_F(MySqlExtendedInfoTest, startTrue) {
+    start(true);
+}
+
+/// @brief Verifies that the lease manager can start with tables and MT.
+TEST_F(MySqlExtendedInfoTest, startTrueMultiThreading) {
+    MultiThreadingTest mt(true);
+    start(true);
+}
+
 /// @brief Verifies that the lease manager can add the v4 leases.
 void
 MySqlExtendedInfoTest::testInitLease4() {
+    start(false);
     initLease4();
     EXPECT_EQ(8, leases4.size());
     IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
@@ -209,6 +276,7 @@ TEST_F(MySqlExtendedInfoTest, initLease4MultiThreading) {
 void
 MySqlExtendedInfoTest::testGetLeases4ByRelayId() {
     // Lease manager is created with empty tables.
+    start(false);
     initLease4(false);
 
     // Create leases.
@@ -438,6 +506,7 @@ TEST_F(MySqlExtendedInfoTest, getLeases4ByRelayIdMultiThreading) {
 void
 MySqlExtendedInfoTest::testGetLeases4ByRemoteId() {
     // Lease manager is created with empty tables.
+    start(false);
     initLease4(true);
 
     // Update leases.
@@ -662,6 +731,7 @@ void
 MySqlExtendedInfoTest::testUpgradeExtendedInfo4(const CfgConsistency::ExtendedInfoSanity& check,
                                                 const LeasePageSize& page_size) {
     // Lease manager is created with empty tables.
+    start(false);
     initLease4(false);
 
     // Create leases.
@@ -1006,6 +1076,7 @@ TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfo4_1) {
 /// @brief Verifies that the lease manager can add the v6 leases.
 void
 MySqlExtendedInfoTest::testInitLease6() {
+    start(false);
     initLease6();
     EXPECT_EQ(8, leases6.size());
     Lease6Collection got;
@@ -1034,10 +1105,370 @@ TEST_F(MySqlExtendedInfoTest, initLease6MultiThreading) {
     testInitLease6();
 }
 
+/// @brief Verifies that the lease manager can add the v6 leases with tables.
+void
+MySqlExtendedInfoTest::testEnableTables() {
+    start(true);
+    initLease6();
+    EXPECT_EQ(8, leases6.size());
+    Lease6Collection got;
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6());
+    ASSERT_EQ(leases6.size(), got.size());
+    for (size_t i = 0; i < leases6.size(); ++i) {
+        ConstElementPtr expected = leases6[i]->toElement();
+        LeasePtr lease = got[i];
+        ASSERT_TRUE(lease);
+        EXPECT_TRUE(expected->equals(*lease->toElement()))
+            << "expected: " << expected->str() << "\n"
+            << "got: " << lease->toElement()->str() << "\n";
+    }
+}
+
+TEST_F(MySqlExtendedInfoTest, enableTables) {
+    testEnableTables();
+}
+
+TEST_F(MySqlExtendedInfoTest, enableTablesMultiThreading) {
+    MultiThreadingTest mt(true);
+    testEnableTables();
+}
+
+/// @brief Verifies that getLeases6ByRelayId works as expected.
+void
+MySqlExtendedInfoTest::testGetLeases6ByRelayId() {
+    // Lease manager is created with empty tables.
+    start(true);
+    initLease6();
+    EXPECT_EQ(0, lease_mgr_->byRelayId6size());
+
+    // Create parameter values.
+    IOAddress lease_addr0(ADDRESS6[0]);
+    IOAddress lease_addr1(ADDRESS6[1]);
+    IOAddress lease_addr2(ADDRESS6[2]);
+    IOAddress link_addr(ADDRESS6[4]);
+    IOAddress other_link_addr("2001:db8:1::4");
+    IOAddress zero = IOAddress::IPV6_ZERO_ADDRESS();
+    vector<uint8_t> relay_id_data0 = createFromString(DUIDS[0]);
+    DUID relay_id0(relay_id_data0);
+    vector<uint8_t> relay_id_data1 = createFromString(DUIDS[1]);
+    DUID relay_id1(relay_id_data1);
+    vector<uint8_t> relay_id_data2 = createFromString(DUIDS[2]);
+    DUID relay_id2(relay_id_data2);
+
+    // Fill the table.
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data0));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data0));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data1));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr1, relay_id_data0));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr1, relay_id_data1));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr2, relay_id_data1));
+    EXPECT_EQ(6, lease_mgr_->byRelayId6size());
+
+    Lease6Collection got;
+    // Unknown relay id #2, no link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id2,
+                                                          zero,
+                                                          0,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    EXPECT_EQ(0, got.size());
+
+    // Unknown relay id #2, link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id2,
+                                                          link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    EXPECT_EQ(0, got.size());
+
+    // Relay id #0, other link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id0,
+                                                          other_link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    EXPECT_EQ(0, got.size());
+
+    // Relay id #0, no link: 3 entries but 2 addresses.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id0,
+                                                          zero,
+                                                          0,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    ASSERT_EQ(2, got.size());
+    Lease6Ptr lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Relay id #1, no link, partial: 2 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          zero,
+                                                          0,
+                                                          zero,
+                                                          LeasePageSize(2)));
+    ASSERT_EQ(2, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Relay id #1, no link, partial from previous: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          zero,
+                                                          0,
+                                                          lease->addr_,
+                                                          LeasePageSize(2)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Add another entry for last tests.
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data1));
+    EXPECT_EQ(7, lease_mgr_->byRelayId6size());
+
+    // Relay id #1, link: 3 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    ASSERT_EQ(3, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+    lease = got[2];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Relay id #1, link, initial partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+
+    // Relay id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          lease->addr_,
+                                                          LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Relay id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          lease->addr_,
+                                                          LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Relay id #1, link, final partial: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          lease->addr_,
+                                                          LeasePageSize(1)));
+    EXPECT_EQ(0, got.size());
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases6ByRelayId) {
+    testGetLeases6ByRelayId();
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases6ByRelayIdMultiThreading) {
+    MultiThreadingTest mt(true);
+    testGetLeases6ByRelayId();
+}
+
+/// @brief Verifies that getLeases6ByRemoteId works as expected.
+void
+MySqlExtendedInfoTest::testGetLeases6ByRemoteId() {
+    // Lease manager is created with empty tables.
+    start(true);
+    initLease6();
+    EXPECT_EQ(0, lease_mgr_->byRemoteId6size());
+
+    // Create parameter values.
+    IOAddress lease_addr0(ADDRESS6[0]);
+    IOAddress lease_addr1(ADDRESS6[1]);
+    IOAddress lease_addr2(ADDRESS6[2]);
+    IOAddress link_addr(ADDRESS6[4]);
+    IOAddress other_link_addr("2001:db8:1::4");
+    IOAddress zero = IOAddress::IPV6_ZERO_ADDRESS();
+    vector<uint8_t> remote_id0 = createFromString(DUIDS[0]);
+    vector<uint8_t> remote_id1 = createFromString(DUIDS[1]);
+    vector<uint8_t> remote_id2 = createFromString(DUIDS[2]);
+
+    // Fill the table.
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id0));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id0));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id1));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr1, remote_id0));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr1, remote_id1));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr2, remote_id1));
+    EXPECT_EQ(6, lease_mgr_->byRemoteId6size());
+
+    Lease6Collection got;
+    // Unknown remote id #2, no link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id2,
+                                                           zero,
+                                                           0,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    EXPECT_EQ(0, got.size());
+
+    // Unknown remote id #2, link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id2,
+                                                           link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    EXPECT_EQ(0, got.size());
+
+    // Remote id #0, other link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id0,
+                                                           other_link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    EXPECT_EQ(0, got.size());
+
+    // Remote id #0, no link: 3 entries but 2 addresses.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id0,
+                                                           zero,
+                                                           0,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    ASSERT_EQ(2, got.size());
+    Lease6Ptr lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Remote id #1, no link, partial: 2 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           zero,
+                                                           0,
+                                                           zero,
+                                                           LeasePageSize(2)));
+    ASSERT_EQ(2, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Remote id #1, no link, partial from previous: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           zero,
+                                                           0,
+                                                           lease->addr_,
+                                                           LeasePageSize(2)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Add another entry for last tests.
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id1));
+    EXPECT_EQ(7, lease_mgr_->byRemoteId6size());
+
+    // Remote id #1, link: 3 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    ASSERT_EQ(3, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+    lease = got[2];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Remote id #1, link, initial partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+
+    // Remote id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           lease->addr_,
+                                                           LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Remote id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           lease->addr_,
+                                                           LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Remote id #1, link, final partial: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           lease->addr_,
+                                                           LeasePageSize(1)));
+    EXPECT_EQ(0, got.size());
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases6ByRemoteId) {
+    testGetLeases6ByRemoteId();
+}
+
+TEST_F(MySqlExtendedInfoTest, getLeases6ByRemoteIdMultiThreading) {
+    MultiThreadingTest mt(true);
+    testGetLeases6ByRemoteId();
+}
+
 /// @brief Verifies that getLeases6ByLink works as expected.
 void
 MySqlExtendedInfoTest::testGetLeases6ByLink() {
     // Lease manager is created with empty tables.
+    start(false);
     initLease6();
 
     // Create parameter values.
index b6547169f8acfe75fe439ab7cf57c556821ee897..c447dfee7457d40839a87457ce01e27b61136b8e 100644 (file)
@@ -48,6 +48,31 @@ const vector<string> DUIDS = {
     "BBBBBBBB", "$$$$$$$$", "^^^^^^^^", "\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5"
 };
 
+/// @brief A derivation of the lease manager exposing protected methods.
+class NakedPgSqlLeaseMgr : public PgSqlLeaseMgr {
+public:
+    /// @brief Constructor.
+    ///
+    /// Creates an instance of the lease manager.
+    ///
+    /// @param parameters Parameter map.
+    NakedPgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
+        : PgSqlLeaseMgr(parameters) {
+    }
+
+    /// @brief Destructor.
+    virtual ~NakedPgSqlLeaseMgr() {
+    }
+
+    /// @brief Exposes protected methods.
+    using PgSqlLeaseMgr::deleteExtendedInfo6;
+    using PgSqlLeaseMgr::addRelayId6;
+    using PgSqlLeaseMgr::addRemoteId6;
+};
+
+/// @brief Type of unique pointers to naked lease manager.
+typedef unique_ptr<NakedPgSqlLeaseMgr> NakedPgSqlLeaseMgrPtr;
+
 /// @brief Test fixture class for extended info tests.
 class PgSqlExtendedInfoTest : public ::testing::Test {
 public:
@@ -56,19 +81,8 @@ public:
         // Ensure we have the proper schema with no transient data.
         createPgSQLSchema();
 
-        // Connect to the database.
-        try {
-            LeaseMgrFactory::create(validPgSQLConnectionString());
-        } catch (...) {
-            std::cerr << "*** ERROR: unable to open database. The test\n"
-                         "*** environment is broken and must be fixed before\n"
-                         "*** the PostgreSQL tests will run correctly.\n"
-                         "*** The reason for the problem is described in the\n"
-                         "*** accompanying exception output.\n";
-            throw;
-        }
-
-        lease_mgr_ = &(LeaseMgrFactory::instance());
+        pmap_ = DatabaseConnection::parse(validPgSQLConnectionString());
+        lease_mgr_.reset();
         leases4.clear();
         leases6.clear();
         MultiThreadingMgr::instance().setMode(false);
@@ -77,14 +91,15 @@ public:
 
     /// @brief Destructor.
     ~PgSqlExtendedInfoTest() {
-        LeaseMgrFactory::destroy();
-        // If data wipe enabled, delete transient data otherwise destroy
-        // the schema.
-        destroyPgSQLSchema();
-
+        pmap_.clear();
+        lease_mgr_.reset();
         leases4.clear();
         leases6.clear();
         MultiThreadingMgr::instance().setMode(false);
+
+        // If data wipe enabled, delete transient data otherwise destroy
+        // the schema.
+        destroyPgSQLSchema();
     }
 
     /// @brief Create and set v4 leases.
@@ -129,6 +144,23 @@ public:
         ASSERT_EQ(ADDRESS6.size(), leases6.size());
     }
 
+    /// @brief Start lease manager.
+    ///
+    /// @param enable When true enable extended info tables.
+    void start(bool enable) {
+        // Do not set unused pmap_["universe"].
+        if (enable) {
+            pmap_["extended-info-tables"] = "true";
+        }
+
+        ASSERT_NO_THROW(lease_mgr_.reset(new NakedPgSqlLeaseMgr(pmap_)));
+        if (enable) {
+            EXPECT_TRUE(lease_mgr_->getExtendedInfoTablesEnabled());
+        } else {
+            EXPECT_FALSE(lease_mgr_->getExtendedInfoTablesEnabled());
+        }
+    }
+
     /// @brief Create a vector of uint8_t from a string.
     ///
     /// @param content A not empty string holding the content.
@@ -156,11 +188,23 @@ public:
     void testUpgradeExtendedInfo4(const CfgConsistency::ExtendedInfoSanity& check,
                                   const LeasePageSize& page_size);
 
+    /// @brief Test initLease6 with tables.
+    void testEnableTables();
+
+    /// @brief Test getLeases6ByRelayId.
+    void testGetLeases6ByRelayId();
+
+    /// @brief Test getLeases6ByRemoteId.
+    void testGetLeases6ByRemoteId();
+
     /// @brief Test getLeases6ByLink.
     void testGetLeases6ByLink();
 
+    /// @brief Parameter map.
+    DatabaseConnection::ParameterMap pmap_;
+
     /// @brief Lease manager.
-    LeaseMgr* lease_mgr_;
+    NakedPgSqlLeaseMgrPtr lease_mgr_;
 
     /// @brief V4 leases.
     Lease4Collection leases4;
@@ -172,9 +216,32 @@ public:
     time_t now_;
 };
 
+/// @brief Verifies that the lease manager can start.
+TEST_F(PgSqlExtendedInfoTest, startFalse) {
+    start(false);
+}
+
+/// @brief Verifies that the lease manager can start with MT.
+TEST_F(PgSqlExtendedInfoTest, startFalseMultiThreading) {
+    MultiThreadingTest mt(true);
+    start(false);
+}
+
+/// @brief Verifies that the lease manager can start with tables.
+TEST_F(PgSqlExtendedInfoTest, startTrue) {
+    start(true);
+}
+
+/// @brief Verifies that the lease manager can start with tables and MT.
+TEST_F(PgSqlExtendedInfoTest, startTrueMultiThreading) {
+    MultiThreadingTest mt(true);
+    start(true);
+}
+
 /// @brief Verifies that the lease manager can add the v4 leases.
 void
 PgSqlExtendedInfoTest::testInitLease4() {
+    start(false);
     initLease4();
     EXPECT_EQ(8, leases4.size());
     IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
@@ -209,6 +276,7 @@ TEST_F(PgSqlExtendedInfoTest, initLease4MultiThreading) {
 void
 PgSqlExtendedInfoTest::testGetLeases4ByRelayId() {
     // Lease manager is created with empty tables.
+    start(false);
     initLease4(false);
 
     // Create leases.
@@ -438,6 +506,7 @@ TEST_F(PgSqlExtendedInfoTest, getLeases4ByRelayIdMultiThreading) {
 void
 PgSqlExtendedInfoTest::testGetLeases4ByRemoteId() {
     // Lease manager is created with empty tables.
+    start(false);
     initLease4(true);
 
     // Update leases.
@@ -662,6 +731,7 @@ void
 PgSqlExtendedInfoTest::testUpgradeExtendedInfo4(const CfgConsistency::ExtendedInfoSanity& check,
                                                 const LeasePageSize& page_size) {
     // Lease manager is created with empty tables.
+    start(false);
     initLease4(false);
 
     // Create leases.
@@ -1006,6 +1076,7 @@ TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfo4_1) {
 /// @brief Verifies that the lease manager can add the v6 leases.
 void
 PgSqlExtendedInfoTest::testInitLease6() {
+    start(false);
     initLease6();
     EXPECT_EQ(8, leases6.size());
     Lease6Collection got;
@@ -1034,10 +1105,370 @@ TEST_F(PgSqlExtendedInfoTest, initLease6MultiThreading) {
     testInitLease6();
 }
 
+/// @brief Verifies that the lease manager can add the v6 leases with tables.
+void
+PgSqlExtendedInfoTest::testEnableTables() {
+    start(true);
+    initLease6();
+    EXPECT_EQ(8, leases6.size());
+    Lease6Collection got;
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6());
+    ASSERT_EQ(leases6.size(), got.size());
+    for (size_t i = 0; i < leases6.size(); ++i) {
+        ConstElementPtr expected = leases6[i]->toElement();
+        LeasePtr lease = got[i];
+        ASSERT_TRUE(lease);
+        EXPECT_TRUE(expected->equals(*lease->toElement()))
+            << "expected: " << expected->str() << "\n"
+            << "got: " << lease->toElement()->str() << "\n";
+    }
+}
+
+TEST_F(PgSqlExtendedInfoTest, enableTables) {
+    testEnableTables();
+}
+
+TEST_F(PgSqlExtendedInfoTest, enableTablesMultiThreading) {
+    MultiThreadingTest mt(true);
+    testEnableTables();
+}
+
+/// @brief Verifies that getLeases6ByRelayId works as expected.
+void
+PgSqlExtendedInfoTest::testGetLeases6ByRelayId() {
+    // Lease manager is created with empty tables.
+    start(true);
+    initLease6();
+    EXPECT_EQ(0, lease_mgr_->byRelayId6size());
+
+    // Create parameter values.
+    IOAddress lease_addr0(ADDRESS6[0]);
+    IOAddress lease_addr1(ADDRESS6[1]);
+    IOAddress lease_addr2(ADDRESS6[2]);
+    IOAddress link_addr(ADDRESS6[4]);
+    IOAddress other_link_addr("2001:db8:1::4");
+    IOAddress zero = IOAddress::IPV6_ZERO_ADDRESS();
+    vector<uint8_t> relay_id_data0 = createFromString(DUIDS[0]);
+    DUID relay_id0(relay_id_data0);
+    vector<uint8_t> relay_id_data1 = createFromString(DUIDS[1]);
+    DUID relay_id1(relay_id_data1);
+    vector<uint8_t> relay_id_data2 = createFromString(DUIDS[2]);
+    DUID relay_id2(relay_id_data2);
+
+    // Fill the table.
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data0));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data0));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data1));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr1, relay_id_data0));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr1, relay_id_data1));
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr2, relay_id_data1));
+    EXPECT_EQ(6, lease_mgr_->byRelayId6size());
+
+    Lease6Collection got;
+    // Unknown relay id #2, no link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id2,
+                                                          zero,
+                                                          0,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    EXPECT_EQ(0, got.size());
+
+    // Unknown relay id #2, link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id2,
+                                                          link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    EXPECT_EQ(0, got.size());
+
+    // Relay id #0, other link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id0,
+                                                          other_link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    EXPECT_EQ(0, got.size());
+
+    // Relay id #0, no link: 3 entries but 2 addresses.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id0,
+                                                          zero,
+                                                          0,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    ASSERT_EQ(2, got.size());
+    Lease6Ptr lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Relay id #1, no link, partial: 2 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          zero,
+                                                          0,
+                                                          zero,
+                                                          LeasePageSize(2)));
+    ASSERT_EQ(2, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Relay id #1, no link, partial from previous: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          zero,
+                                                          0,
+                                                          lease->addr_,
+                                                          LeasePageSize(2)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Add another entry for last tests.
+    EXPECT_NO_THROW(lease_mgr_->addRelayId6(lease_addr0, relay_id_data1));
+    EXPECT_EQ(7, lease_mgr_->byRelayId6size());
+
+    // Relay id #1, link: 3 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(100)));
+    ASSERT_EQ(3, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+    lease = got[2];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Relay id #1, link, initial partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          zero,
+                                                          LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+
+    // Relay id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          lease->addr_,
+                                                          LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Relay id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          lease->addr_,
+                                                          LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Relay id #1, link, final partial: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRelayId(relay_id1,
+                                                          link_addr,
+                                                          64,
+                                                          lease->addr_,
+                                                          LeasePageSize(1)));
+    EXPECT_EQ(0, got.size());
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases6ByRelayId) {
+    testGetLeases6ByRelayId();
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases6ByRelayIdMultiThreading) {
+    MultiThreadingTest mt(true);
+    testGetLeases6ByRelayId();
+}
+
+/// @brief Verifies that getLeases6ByRemoteId works as expected.
+void
+PgSqlExtendedInfoTest::testGetLeases6ByRemoteId() {
+    // Lease manager is created with empty tables.
+    start(true);
+    initLease6();
+    EXPECT_EQ(0, lease_mgr_->byRemoteId6size());
+
+    // Create parameter values.
+    IOAddress lease_addr0(ADDRESS6[0]);
+    IOAddress lease_addr1(ADDRESS6[1]);
+    IOAddress lease_addr2(ADDRESS6[2]);
+    IOAddress link_addr(ADDRESS6[4]);
+    IOAddress other_link_addr("2001:db8:1::4");
+    IOAddress zero = IOAddress::IPV6_ZERO_ADDRESS();
+    vector<uint8_t> remote_id0 = createFromString(DUIDS[0]);
+    vector<uint8_t> remote_id1 = createFromString(DUIDS[1]);
+    vector<uint8_t> remote_id2 = createFromString(DUIDS[2]);
+
+    // Fill the table.
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id0));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id0));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id1));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr1, remote_id0));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr1, remote_id1));
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr2, remote_id1));
+    EXPECT_EQ(6, lease_mgr_->byRemoteId6size());
+
+    Lease6Collection got;
+    // Unknown remote id #2, no link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id2,
+                                                           zero,
+                                                           0,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    EXPECT_EQ(0, got.size());
+
+    // Unknown remote id #2, link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id2,
+                                                           link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    EXPECT_EQ(0, got.size());
+
+    // Remote id #0, other link: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id0,
+                                                           other_link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    EXPECT_EQ(0, got.size());
+
+    // Remote id #0, no link: 3 entries but 2 addresses.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id0,
+                                                           zero,
+                                                           0,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    ASSERT_EQ(2, got.size());
+    Lease6Ptr lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Remote id #1, no link, partial: 2 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           zero,
+                                                           0,
+                                                           zero,
+                                                           LeasePageSize(2)));
+    ASSERT_EQ(2, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Remote id #1, no link, partial from previous: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           zero,
+                                                           0,
+                                                           lease->addr_,
+                                                           LeasePageSize(2)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Add another entry for last tests.
+    EXPECT_NO_THROW(lease_mgr_->addRemoteId6(lease_addr0, remote_id1));
+    EXPECT_EQ(7, lease_mgr_->byRemoteId6size());
+
+    // Remote id #1, link: 3 entries.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(10)));
+    ASSERT_EQ(3, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+    lease = got[1];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+    lease = got[2];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Remote id #1, link, initial partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           zero,
+                                                           LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr0, lease->addr_);
+
+    // Remote id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           lease->addr_,
+                                                           LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr1, lease->addr_);
+
+    // Remote id #1, link, next partial: 1 entry.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           lease->addr_,
+                                                           LeasePageSize(1)));
+    ASSERT_EQ(1, got.size());
+    lease = got[0];
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(lease_addr2, lease->addr_);
+
+    // Remote id #1, link, final partial: nothing.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases6ByRemoteId(remote_id1,
+                                                           link_addr,
+                                                           64,
+                                                           lease->addr_,
+                                                           LeasePageSize(1)));
+    EXPECT_EQ(0, got.size());
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases6ByRemoteId) {
+    testGetLeases6ByRemoteId();
+}
+
+TEST_F(PgSqlExtendedInfoTest, getLeases6ByRemoteIdMultiThreading) {
+    MultiThreadingTest mt(true);
+    testGetLeases6ByRemoteId();
+}
+
 /// @brief Verifies that getLeases6ByLink works as expected.
 void
 PgSqlExtendedInfoTest::testGetLeases6ByLink() {
     // Lease manager is created with empty tables.
+    start(false);
     initLease6();
 
     // Create parameter values.