Browse Source

[4323] Implemented tests for use of alternate host data source.

Marcin Siodelski 8 years ago
parent
commit
a5eef18830
3 changed files with 333 additions and 55 deletions
  1. 7 3
      src/lib/dhcpsrv/host_mgr.cc
  2. 1 1
      src/lib/dhcpsrv/host_mgr.h
  3. 325 51
      src/lib/dhcpsrv/tests/host_mgr_unittest.cc

+ 7 - 3
src/lib/dhcpsrv/host_mgr.cc

@@ -47,7 +47,7 @@ HostMgr::create(const std::string& access) {
         HostDataSourceFactory::create(access);
     } else {
         // Ok, no parameters were specified. We should destroy the existing
-        // insteance.
+        // instance.
         HostDataSourceFactory::destroy();
     }
 
@@ -214,8 +214,12 @@ HostMgr::get6(const SubnetID& subnet_id,
 }
 
 void
-HostMgr::add(const HostPtr&) {
-    isc_throw(isc::NotImplemented, "HostMgr::add is not implemented");
+HostMgr::add(const HostPtr& host) {
+    if (!alternate_source_) {
+        isc_throw(NoHostDataSourceManager, "unable to add new host because there is "
+                  "no alternate host data source present");
+    }
+    alternate_source_->add(host);
 }
 
 } // end of isc::dhcp namespace

+ 1 - 1
src/lib/dhcpsrv/host_mgr.h

@@ -53,7 +53,7 @@ namespace dhcp {
 /// reservations specified in the configuration file) can't be disabled.
 ///
 /// @todo Implement alternate host data sources: MySQL, PostgreSQL, etc.
-class HostMgr : public boost::noncopyable, BaseHostDataSource {
+class HostMgr : public boost::noncopyable, public BaseHostDataSource {
 public:
 
     /// @brief Creates new instance of the @c HostMgr.

+ 325 - 51
src/lib/dhcpsrv/tests/host_mgr_unittest.cc

@@ -9,12 +9,23 @@
 #include <dhcp/hwaddr.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/host.h>
+#include <dhcpsrv/host_data_source_factory.h>
 #include <dhcpsrv/host_mgr.h>
+
+#if defined HAVE_MYSQL
+#include <dhcpsrv/testutils/mysql_schema.h>
+#endif
+
+#if defined HAVE_PGSQL
+#include <dhcpsrv/testutils/pgsql_schema.h>
+#endif
+
 #include <gtest/gtest.h>
 #include <vector>
 
 using namespace isc;
 using namespace isc::dhcp;
+using namespace isc::dhcp::test;
 using namespace isc::asiolink;
 
 namespace {
@@ -37,6 +48,85 @@ protected:
     /// in the @c CfgMgr.
     CfgHostsPtr getCfgHosts() const;
 
+    /// @brief Inserts IPv4 reservation into the host data source.
+    ///
+    /// @param data_source Reference to the data source to which the reservation
+    /// should be inserted.
+    /// @param hwaddr Pointer to the hardware address to be associated with the
+    /// reservation.
+    /// @param subnet_id IPv4 subnet id.
+    /// @param address IPv4 address to be reserved.
+    void addHost4(BaseHostDataSource& data_source,
+                  const HWAddrPtr& hwaddr,
+                  const SubnetID& subnet_id,
+                  const IOAddress& address);
+
+    /// @brief Inserts IPv6 reservation into the host data source.
+    ///
+    /// @param data_source Reference to the data source to which the reservation
+    /// should be inserted.
+    /// @param duid Pointer to the DUID to be associated with the reservation.
+    /// @param subnet_id IPv6 subnet id.
+    /// @param address IPv6 address/prefix to be reserved.
+    /// @param prefix_len Prefix length. The default value is 128 which
+    /// indicates that the reservation is for an IPv6 address rather than a
+    /// prefix.
+    void addHost6(BaseHostDataSource& data_source,
+                  const DuidPtr& duid,
+                  const SubnetID& subnet_id,
+                  const IOAddress& address,
+                  const uint8_t prefix_len = 128);
+
+    /// @brief This test verifies that HostMgr returns all reservations for the
+    /// specified HW address.
+    ///
+    /// If reservations are added to different host data sources, it is expected
+    /// that the @c HostMgr will retrieve reservations from both of them.
+    ///
+    /// @param data_source1 Host data source to which first reservation is
+    /// inserted.
+    /// @param data_source2 Host data source to which second reservation is
+    /// inserted.
+    void testGetAll(BaseHostDataSource& data_source1,
+                    BaseHostDataSource& data_source2);
+
+    /// @brief This test verifies that it is possible to retrieve IPv4
+    /// reservation for the particular host using HostMgr.
+    ///
+    /// If reservations are added to different host data sources, it is expected
+    /// that the @c HostMgr will retrieve reservations from both of them.
+    ///
+    /// @param data_source1 Host data source to which first reservation is
+    /// inserted.
+    /// @param data_source2 Host data source to which second reservation is
+    /// inserted.
+    void testGetAll4(BaseHostDataSource& data_source1,
+                     BaseHostDataSource& data_source2);
+
+    /// @brief This test verifies that it is possible to retrieve an IPv4
+    /// reservation for the particular host using HostMgr.
+    ///
+    /// @param data_source Host data source to which reservation is inserted and
+    /// from which it will be retrieved.
+    void testGet4(BaseHostDataSource& data_source);
+
+    /// @brief This test verifies that it is possible to retrieve an IPv6
+    /// reservation for the particular host using HostMgr.
+    ///
+    /// @param data_source Host data source to which reservation is inserted and
+    /// from which it will be retrieved.
+    void testGet6(BaseHostDataSource& data_source);
+
+    /// @brief This test verifies that it is possible to retrieve an IPv6
+    /// prefix reservation for the particular host using HostMgr.
+    ///
+    /// @param data_source1 Host data source to which first reservation is
+    /// inserted.
+    /// @param data_source2 Host data source to which second reservation is
+    /// inserted.
+    void testGet6ByPrefix(BaseHostDataSource& data_source1,
+                          BaseHostDataSource& data_source2);
+
     /// @brief HW addresses to be used by the tests.
     std::vector<HWAddrPtr> hwaddrs_;
     /// @brief DUIDs to be used by the tests.
@@ -79,22 +169,43 @@ HostMgrTest::getCfgHosts() const {
     return (CfgMgr::instance().getStagingCfg()->getCfgHosts());
 }
 
-/// This test verifies that HostMgr returns all reservations for the
-/// specified HW address. The reservations are defined in the server's
-/// configuration.
-TEST_F(HostMgrTest, getAll) {
+void
+HostMgrTest::addHost4(BaseHostDataSource& data_source,
+                      const HWAddrPtr& hwaddr,
+                      const SubnetID& subnet_id,
+                      const IOAddress& address) {
+    data_source.add(HostPtr(new Host(hwaddr->toText(false),
+                                     "hw-address", subnet_id, SubnetID(0),
+                                     address)));
+}
+
+void
+HostMgrTest::addHost6(BaseHostDataSource& data_source,
+                      const DuidPtr& duid,
+                      const SubnetID& subnet_id,
+                      const IOAddress& address,
+                      const uint8_t prefix_len) {
+    HostPtr new_host(new Host(duid->toText(), "duid", SubnetID(1),
+                              subnet_id, IOAddress::IPV4_ZERO_ADDRESS()));
+    new_host->addReservation(IPv6Resrv(prefix_len == 128 ? IPv6Resrv::TYPE_NA :
+                                       IPv6Resrv::TYPE_PD,
+                                       address, prefix_len));
+    data_source.add(new_host);
+}
+
+
+void
+HostMgrTest::testGetAll(BaseHostDataSource& data_source1,
+                        BaseHostDataSource& data_source2) {
     // Initially, no reservations should be present.
     ConstHostCollection hosts = HostMgr::instance().getAll(hwaddrs_[0]);
     ASSERT_TRUE(hosts.empty());
 
     // Add two reservations for the same HW address. They differ by the IP
     // address reserved and the IPv4 subnet.
-    getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false),
-                                        "hw-address", SubnetID(1), SubnetID(0),
-                                        IOAddress("192.0.2.5"))));
-    getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false),
-                                        "hw-address", SubnetID(10), SubnetID(0),
-                                        IOAddress("192.0.3.10"))));
+    addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+    addHost4(data_source2, hwaddrs_[0], SubnetID(10), IOAddress("192.0.3.10"));
+
     CfgMgr::instance().commit();
 
     // If there non-matching HW address is specified, nothing should be
@@ -136,24 +247,18 @@ TEST_F(HostMgrTest, getAll) {
         ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10"
             " not found using getAll method";
     }
-
 }
 
-// This test verifies that it is possible to gather all reservations for the
-// specified IPv4 address from the HostMgr. The reservations are specified in
-// the server's configuration.
-TEST_F(HostMgrTest, getAll4) {
+void
+HostMgrTest::testGetAll4(BaseHostDataSource& data_source1,
+                         BaseHostDataSource& data_source2) {
     ConstHostCollection hosts =
         HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
     ASSERT_TRUE(hosts.empty());
 
-    getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false),
-                                        "hw-address", SubnetID(1), SubnetID(0),
-                                        IOAddress("192.0.2.5"))));
+    addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+    addHost4(data_source2, hwaddrs_[1], SubnetID(10), IOAddress("192.0.2.5"));
 
-    getCfgHosts()->add(HostPtr(new Host(hwaddrs_[1]->toText(false),
-                                        "hw-address", SubnetID(10), SubnetID(0),
-                                        IOAddress("192.0.2.5"))));
     CfgMgr::instance().commit();
 
     hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
@@ -167,17 +272,13 @@ TEST_F(HostMgrTest, getAll4) {
     EXPECT_NE(hosts[0]->getIPv4SubnetID(), hosts[1]->getIPv4SubnetID());
 }
 
-// This test verifies that it is possible to retrieve a reservation for the
-// particular host using HostMgr. The reservation is specified in the server's
-// configuration.
-TEST_F(HostMgrTest, get4) {
+void
+HostMgrTest::testGet4(BaseHostDataSource& data_source) {
     ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), hwaddrs_[0]);
     ASSERT_FALSE(host);
 
-    getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false),
-                                        "hw-address",
-                                        SubnetID(1), SubnetID(2),
-                                        IOAddress("192.0.2.5"))));
+    addHost4(data_source, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+
     CfgMgr::instance().commit();
 
     host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR,
@@ -188,18 +289,13 @@ TEST_F(HostMgrTest, get4) {
     EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
 }
 
-// This test verifies that it is possible to retrieve IPv6 reservations for
-// the particular host using HostMgr. The reservation is specified in the
-// server's configuration.
-TEST_F(HostMgrTest, get6) {
+void
+HostMgrTest::testGet6(BaseHostDataSource& data_source) {
     ConstHostPtr host = HostMgr::instance().get6(SubnetID(2), duids_[0]);
     ASSERT_FALSE(host);
 
-    HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1),
-                              SubnetID(2), IOAddress("0.0.0.0")));
-    new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
-                                       IOAddress("2001:db8:1::1")));
-    getCfgHosts()->add(new_host);
+    addHost6(data_source, duids_[0], SubnetID(2), IOAddress("2001:db8:1::1"));
+
     CfgMgr::instance().commit();
 
     host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID,
@@ -210,25 +306,18 @@ TEST_F(HostMgrTest, get6) {
                                                IOAddress("2001:db8:1::1"))));
 }
 
-// This test verifies that it is possible to retrieve the reservation of the
-// particular IPv6 prefix using HostMgr.
-TEST_F(HostMgrTest, get6ByPrefix) {
+void
+HostMgrTest::testGet6ByPrefix(BaseHostDataSource& data_source1,
+                              BaseHostDataSource& data_source2) {
     ConstHostPtr host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64);
     ASSERT_FALSE(host);
 
     // Add a host with a reservation for a prefix 2001:db8:1::/64.
-    HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1),
-                              SubnetID(2), IOAddress("0.0.0.0")));
-    new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
-                                       IOAddress("2001:db8:1::"), 64));
-    getCfgHosts()->add(new_host);
+    addHost6(data_source1, duids_[0], SubnetID(2), IOAddress("2001:db8:1::"), 64);
 
     // Add another host having a reservation for prefix 2001:db8:1:0:6::/72.
-    new_host.reset(new Host(duids_[1]->toText(), "duid", SubnetID(2),
-                            SubnetID(3), IOAddress::IPV4_ZERO_ADDRESS()));
-    new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
-                                       IOAddress("2001:db8:1:0:6::"), 72));
-    getCfgHosts()->add(new_host);
+    addHost6(data_source2, duids_[1], SubnetID(3), IOAddress("2001:db8:1:0:6::"), 72);
+
     CfgMgr::instance().commit();
 
     // Retrieve first reservation.
@@ -254,4 +343,189 @@ TEST_F(HostMgrTest, get6ByPrefix) {
     EXPECT_FALSE(host);
 }
 
+/// This test verifies that HostMgr returns all reservations for the
+/// specified HW address. The reservations are defined in the server's
+/// configuration.
+TEST_F(HostMgrTest, getAll) {
+    testGetAll(*getCfgHosts(), *getCfgHosts());
+}
+
+// This test verifies that it is possible to gather all reservations for the
+// specified IPv4 address from the HostMgr. The reservations are specified in
+// the server's configuration.
+TEST_F(HostMgrTest, getAll4) {
+    testGetAll4(*getCfgHosts(), *getCfgHosts());
+}
+
+// This test verifies that it is possible to retrieve a reservation for the
+// particular host using HostMgr. The reservation is specified in the server's
+// configuration.
+TEST_F(HostMgrTest, get4) {
+    testGet4(*getCfgHosts());
+}
+
+// This test verifies that it is possible to retrieve IPv6 reservations for
+// the particular host using HostMgr. The reservation is specified in the
+// server's configuration.
+TEST_F(HostMgrTest, get6) {
+    testGet6(*getCfgHosts());
+}
+
+// This test verifies that it is possible to retrieve the reservation of the
+// particular IPv6 prefix using HostMgr.
+TEST_F(HostMgrTest, get6ByPrefix) {
+    testGet6ByPrefix(*getCfgHosts(), *getCfgHosts());
+}
+
+// The following tests require MySQL enabled.
+#if defined HAVE_MYSQL
+
+/// @brief Test fixture class for validating @c HostMgr using
+/// MySQL as alternate host data source.
+class MySQLHostMgrTest : public HostMgrTest {
+protected:
+
+    /// @brief Build MySQL schema for a test.
+    virtual void SetUp();
+
+    /// @brief Rollback and drop MySQL schema after the test.
+    virtual void TearDown();
+};
+
+void
+MySQLHostMgrTest::SetUp() {
+    HostMgrTest::SetUp();
+
+    // Ensure schema is the correct one.
+    destroyMySQLSchema();
+    createMySQLSchema();
+
+    // Connect to the database
+    try {
+        HostMgr::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;
+    }
+}
+
+void
+MySQLHostMgrTest::TearDown() {
+    HostDataSourceFactory::getHostDataSourcePtr()->rollback();
+    HostDataSourceFactory::destroy();
+    destroyMySQLSchema();
+}
+
+// This test verifies that reservations for a particular client can
+// be retrieved from the confguration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getAll) {
+    testGetAll(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that IPv4 reservations for a particular client can
+// be retrieved from the configuration file and a database simulatneously.
+TEST_F(MySQLHostMgrTest, getAll4) {
+    testGetAll4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that the IPv4 reservation can be retrieved from a
+// database.
+TEST_F(MySQLHostMgrTest, get4) {
+    testGet4(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 reservation can be retrieved from a
+// database.
+TEST_F(MySQLHostMgrTest, get6) {
+    testGet6(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 prefix reservation can be retrieved
+// from a configuration file and a database.
+TEST_F(MySQLHostMgrTest, get6ByPrefix) {
+    testGet6ByPrefix(*getCfgHosts(), HostMgr::instance());
+}
+
+#endif
+
+
+// The following tests require PostgreSQL enabled.
+#if defined HAVE_PGSQL
+
+/// @brief Test fixture class for validating @c HostMgr using
+/// PostgreSQL as alternate host data source.
+class PostgreSQLHostMgrTest : public HostMgrTest {
+protected:
+
+    /// @brief Prepares the class for a test.
+    virtual void SetUp();
+
+    virtual void TearDown();
+
+};
+
+void
+PostgreSQLHostMgrTest::SetUp() {
+    HostMgrTest::SetUp();
+
+    // Ensure schema is the correct one.
+    destroyPgSQLSchema();
+    createPgSQLSchema();
+
+    // Connect to the database
+    try {
+        HostMgr::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;
+    }
+}
+
+void
+PostgreSQLHostMgrTest::TearDown() {
+    HostDataSourceFactory::getHostDataSourcePtr()->rollback();
+    HostDataSourceFactory::destroy();
+    destroyPgSQLSchema();
+}
+
+// This test verifies that reservations for a particular client can
+// be retrieved from the confguration file and a database simultaneously.
+TEST_F(PostgreSQLHostMgrTest, getAll) {
+    testGetAll(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that IPv4 reservations for a particular client can
+// be retrieved from the configuration file and a database simulatneously.
+TEST_F(PostgreSQLHostMgrTest, getAll4) {
+    testGetAll4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that the IPv4 reservation can be retrieved from a
+// database.
+TEST_F(PostgreSQLHostMgrTest, get4) {
+    testGet4(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 reservation can be retrieved from a
+// database.
+TEST_F(PostgreSQLHostMgrTest, get6) {
+    testGet6(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 prefix reservation can be retrieved
+// from a configuration file and a database.
+TEST_F(PostgreSQLHostMgrTest, get6ByPrefix) {
+    testGet6ByPrefix(*getCfgHosts(), HostMgr::instance());
+}
+
+#endif
+
 } // end of anonymous namespace