#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 {
/// 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.
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
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"));
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,
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,
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.
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