testMultipleHosts6();
}
+/// @brief Test fixture class for validating @c HostMgr using
+/// CQL as alternate host data source.
+class CQLHostMgrTest : public HostMgrTest {
+protected:
+
+ /// @brief Build CQL schema for a test.
+ virtual void SetUp();
+
+ /// @brief Rollback and drop CQL schema after the test.
+ virtual void TearDown();
+};
+
+void
+CQLHostMgrTest::SetUp() {
+ HostMgrTest::SetUp();
+
+ // Ensure we have the proper schema with no transient data.
+ db::test::createCqlSchema();
+
+ // Connect to the database
+ try {
+ HostMgr::addBackend(db::test::validCqlConnectionString());
+ } catch (...) {
+ std::cerr << "*** ERROR: unable to open database. The test\n"
+ "*** environment is broken and must be fixed before\n"
+ "*** the CQL tests will run correctly.\n"
+ "*** The reason for the problem is described in the\n"
+ "*** accompanying exception output.\n";
+ throw;
+ }
+}
+
+void
+CQLHostMgrTest::TearDown() {
+ HostMgr::instance().getHostDataSource()->rollback();
+ HostMgr::delBackend("cql");
+
+ // If data wipe enabled, delete transient data otherwise destroy the schema
+ db::test::destroyCqlSchema();
+}
+
+// This test verifies that reservations for a particular client can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getAll) {
+ testGetAll(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getAll4BySubnet) {
+ testGetAll4BySubnet(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getAll6BySubnet) {
+ testGetAll6BySubnet(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname can be
+// retrieved from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getAllbyHostname) {
+ testGetAllbyHostname(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname and
+// DHCPv4 subnet can be retrieved from the configuration file and a
+// database simultaneously.
+TEST_F(CQLHostMgrTest, getAllbyHostnameSubnet4) {
+ testGetAllbyHostnameSubnet4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname and
+// DHCPv6 subnet can be retrieved from the configuration file and a
+// database simultaneously.
+TEST_F(CQLHostMgrTest, getAllbyHostnameSubnet6) {
+ testGetAllbyHostnameSubnet6(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved by pages from the configuration file and a database
+// simultaneously.
+TEST_F(CQLHostMgrTest, getPage4) {
+ testGetPage4(true);
+}
+
+// This test verifies that all v4 reservations be retrieved by pages
+// from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getPage4All) {
+ testGetPage4All(true);
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved by pages from the configuration file and a database
+// simultaneously.
+TEST_F(CQLHostMgrTest, getPage6) {
+ testGetPage6(true);
+}
+
+// This test verifies that all v6 reservations be retrieved by pages
+// from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getPage6All) {
+ testGetPage6All(true);
+}
+
+// This test verifies that IPv4 reservations for a particular client can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(CQLHostMgrTest, getAll4) {
+ testGetAll4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that the IPv4 reservation can be retrieved from a
+// database.
+TEST_F(CQLHostMgrTest, get4) {
+ testGet4(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 reservation can be retrieved from a
+// database.
+TEST_F(CQLHostMgrTest, get6) {
+ testGet6(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 prefix reservation can be retrieved
+// from a configuration file and a database.
+TEST_F(CQLHostMgrTest, get6ByPrefix) {
+ testGet6ByPrefix(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that it is possible to control whether the reserved
+// IP addresses are unique or non unique via the HostMgr.
+TEST_F(CQLHostMgrTest, setIPReservationsUnique) {
+ EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(true));
+ // This is currently not supported for Cassandra.
+ EXPECT_FALSE(HostMgr::instance().setIPReservationsUnique(false));
+}
+
} // namespace
ASSERT_NO_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")));
access = invalidConnectString();
+ // by adding an invalid access will cause the manager factory to throw
+ // resulting in failure to recreate the manager
CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
// Now close the sql socket out from under backend client
access = invalidConnectString();
access += extra;
+ // by adding an invalid access will cause the manager factory to throw
+ // resulting in failure to recreate the manager
CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
// Now close the sql socket out from under backend client
access = invalidConnectString();
access += extra;
+ // by adding an invalid access will cause the manager factory to throw
+ // resulting in failure to recreate the manager
CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setLeaseDbAccessString(access);
// Now close the sql socket out from under backend client
#include <dhcpsrv/host.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/host_mgr.h>
-#include <dhcpsrv/testutils/test_utils.h>
-#include <testutils/multi_threading_utils.h>
-#include <util/multi_threading_mgr.h>
-
-#if defined HAVE_MYSQL
-#include <mysql/testutils/mysql_schema.h>
-#endif
-
-#if defined HAVE_PGSQL
-#include <pgsql/testutils/pgsql_schema.h>
-#endif
-
-#if defined HAVE_CQL
-#include <cql/testutils/cql_schema.h>
-#endif
+#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
#include <gtest/gtest.h>
#include <vector>
using namespace isc;
using namespace isc::db;
-using namespace isc::db::test;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::asiolink;
-using namespace isc::test;
-namespace ph = std::placeholders;
namespace {
-/// @brief Test fixture class for @c HostMgr class.
-class HostMgrTest : public ::testing::Test {
-protected:
-
- /// @brief Prepares the class for a test.
- ///
- /// This method crates a handful of unique HW address and DUID objects
- /// for use in unit tests. These objects are held in the @c hwaddrs_ and
- /// @c duids_ members respectively.
- ///
- /// This method also resets the @c CfgMgr configuration and re-creates
- /// the @c HostMgr object.
- virtual void SetUp();
-
- /// @brief Convenience method returning a pointer to the @c CfgHosts object
- /// 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 HostMgr returns all reservations for the
- /// specified DHCPv4 subnet.
- ///
- /// 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 testGetAll4BySubnet(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified DHCPv6 subnet.
- ///
- /// 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 testGetAll6BySubnet(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified hostname.
- ///
- /// 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 testGetAllbyHostname(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified hostname and DHCPv4 subnet.
- ///
- /// 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 testGetAllbyHostnameSubnet4(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified hostname and DHCPv6 subnet.
- ///
- /// 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 testGetAllbyHostnameSubnet6(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified DHCPv4 subnet by pages.
- ///
- /// If reservations are added to different host data sources, it is expected
- /// that the @c HostMgr will retrieve reservations from both of them.
- ///
- /// @param use_database True when the second reservation is inserted
- /// in a database.
- void testGetPage4(bool use_database);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified DHCPv6 subnet by pages.
- ///
- /// If reservations are added to different host data sources, it is expected
- /// that the @c HostMgr will retrieve reservations from both of them.
- ///
- /// @param use_database True when the second reservation is inserted
- /// in a database.
- void testGetPage6(bool use_database);
-
- /// @brief This test verifies that HostMgr returns all reservations
- /// by pages.
- ///
- /// If reservations are added to different host data sources, it is expected
- /// that the @c HostMgr will retrieve reservations from both of them.
- ///
- /// @param use_database True when the second reservation is inserted
- /// in a database.
- void testGetPage4All(bool use_database);
-
- /// @brief This test verifies that HostMgr returns all reservations
- /// by pages.
- ///
- /// If reservations are added to different host data sources, it is expected
- /// that the @c HostMgr will retrieve reservations from both of them.
- ///
- /// @param use_database True when the second reservation is inserted
- /// in a database.
- void testGetPage6All(bool use_database);
-
- /// @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 negative
- /// cached reservation with and only with get4Any.
- void testGet4Any();
-
- /// @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 negative
- /// cached reservation with and only with get6Any.
- void testGet6Any();
-
- /// @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 This test verifies that HostMgr returns all reservations for the
- /// specified DHCPv4 subnet and IPv4 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 testGetAll4BySubnetIP(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2);
-
- /// @brief This test verifies that HostMgr returns all reservations for the
- /// specified DHCPv6 subnet and IPv6 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 testGetAll6BySubnetIP(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.
- std::vector<DuidPtr> duids_;
-};
-
-void
-// cppcheck-suppress unusedFunction
-HostMgrTest::SetUp() {
- // Remove all configuration which may be dangling from the previous test.
- CfgMgr::instance().clear();
- // Recreate HostMgr instance. It drops any previous state.
- HostMgr::create();
- // Create HW addresses from the template.
- const uint8_t mac_template[] = {
- 0x01, 0x02, 0x0A, 0xBB, 0x03, 0x00
- };
- for (uint8_t i = 0; i < 10; ++i) {
- std::vector<uint8_t> vec(mac_template,
- mac_template + sizeof(mac_template));
- vec[vec.size() - 1] = i;
- HWAddrPtr hwaddr(new HWAddr(vec, HTYPE_ETHER));
- hwaddrs_.push_back(hwaddr);
- }
- // Create DUIDs from the template.
- const uint8_t duid_template[] = {
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00
- };
- for (uint8_t i = 0; i < 10; ++i) {
- std::vector<uint8_t> vec(duid_template,
- duid_template + sizeof(mac_template));
- vec[vec.size() - 1] = i;
- DuidPtr duid(new DUID(vec));
- duids_.push_back(duid);
- }
-}
-
-CfgHostsPtr
-HostMgrTest::getCfgHosts() const {
- return (CfgMgr::instance().getStagingCfg()->getCfgHosts());
-}
-
-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, SUBNET_ID_UNUSED,
- 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(Host::IDENT_HWADDR,
- &hwaddrs_[1]->hwaddr_[0],
- hwaddrs_[1]->hwaddr_.size());
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations for the same HW address. They differ by the IP
- // address reserved and the IPv4 subnet.
- 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
- // returned.
- hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
- &hwaddrs_[1]->hwaddr_[0],
- hwaddrs_[1]->hwaddr_.size());
- ASSERT_TRUE(hosts.empty());
-
- // For the correct HW address, there should be two reservations.
- hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_EQ(2, hosts.size());
-
- // We don't know the order in which the reservations are returned so
- // we have to match with any of the two reservations returned.
-
- // Look for the first reservation.
- bool found = false;
- for (unsigned i = 0; i < 2; ++i) {
- if (hosts[0]->getIPv4Reservation() == IOAddress("192.0.2.5")) {
- ASSERT_EQ(1, hosts[0]->getIPv4SubnetID());
- found = true;
- }
- }
- if (!found) {
- ADD_FAILURE() << "Reservation for the IPv4 address 192.0.2.5"
- " not found using getAll method";
- }
-
- // Look for the second reservation.
- found = false;
- for (unsigned i = 0; i < 2; ++i) {
- if (hosts[1]->getIPv4Reservation() == IOAddress("192.0.3.10")) {
- ASSERT_EQ(10, hosts[1]->getIPv4SubnetID());
- found = true;
- }
- }
- if (!found) {
- ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10"
- " not found using getAll method";
- }
-}
-
-void
-HostMgrTest::testGetAll4BySubnet(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Initially, no reservations should be present.
- ConstHostCollection hosts = HostMgr::instance().getAll4(SubnetID(1));
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations for the same subnet.
- addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
- addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.6"));
-
- CfgMgr::instance().commit();
-
- // If there non-matching subnet is specified, nothing should be returned.
- hosts = HostMgr::instance().getAll4(SubnetID(100));
- ASSERT_TRUE(hosts.empty());
-
- // For the correct subnet, there should be two reservations.
- hosts = HostMgr::instance().getAll4(SubnetID(1));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
-
- // Make sure that two different hosts were returned.
- EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
- EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
-}
-
-void
-HostMgrTest::testGetAll6BySubnet(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Initially, no reservations should be present.
- ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1));
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations for the same subnet.
- addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
- addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::6"));
-
- CfgMgr::instance().commit();
-
- // If there non-matching subnet is specified, nothing should be returned.
- hosts = HostMgr::instance().getAll6(SubnetID(100));
- ASSERT_TRUE(hosts.empty());
-
- // For the correct subnet, there should be two reservations.
- hosts = HostMgr::instance().getAll6(SubnetID(1));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
-
- // Make sure that two different hosts were returned.
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
- EXPECT_TRUE(hosts[1]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-}
-
-void
-HostMgrTest::testGetAllbyHostname(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Initially, no reservations should be present.
- ConstHostCollection hosts =
- HostMgr::instance().getAllbyHostname("host");
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations with the same hostname.
- HostPtr host1(new Host(hwaddrs_[0]->toText(false), "hw-address",
- SubnetID(1), SUBNET_ID_UNUSED,
- IOAddress("192.0.2.5")));
- host1->setHostname("Host");
- data_source1.add(host1);
- HostPtr host2(new Host(hwaddrs_[1]->toText(false), "hw-address",
- SubnetID(10), SUBNET_ID_UNUSED,
- IOAddress("192.0.3.10")));
- host2->setHostname("hosT");
- data_source2.add(host2);
-
- CfgMgr::instance().commit();
-
- // If there non-matching hostname is specified, nothing should be
- // returned.
- hosts = HostMgr::instance().getAllbyHostname("foobar");
- EXPECT_TRUE(hosts.empty());
-
- // For the correct hostname, there should be two reservations.
- hosts = HostMgr::instance().getAllbyHostname("host");
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ(10, hosts[1]->getIPv4SubnetID());
-
- // Make sure that hostname is correct including its case.
- EXPECT_EQ("Host", hosts[0]->getHostname());
- EXPECT_EQ("hosT", hosts[1]->getHostname());
-}
-
-void
-HostMgrTest::testGetAllbyHostnameSubnet4(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Initially, no reservations should be present.
- ConstHostCollection hosts =
- HostMgr::instance().getAllbyHostname4("host", SubnetID(1));
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations with the same hostname.
- HostPtr host1(new Host(hwaddrs_[0]->toText(false), "hw-address",
- SubnetID(1), SUBNET_ID_UNUSED,
- IOAddress("192.0.2.5")));
- host1->setHostname("Host");
- data_source1.add(host1);
- HostPtr host2(new Host(hwaddrs_[1]->toText(false), "hw-address",
- SubnetID(1), SUBNET_ID_UNUSED,
- IOAddress("192.0.2.6")));
- host2->setHostname("hosT");
- data_source2.add(host2);
-
- CfgMgr::instance().commit();
-
- // If there non-matching hostname is specified, nothing should be
- // returned.
- hosts = HostMgr::instance().getAllbyHostname4("foobar", SubnetID(1));
- EXPECT_TRUE(hosts.empty());
-
- // If there non-matching subnet is specified, nothing should be
- // returned.
- hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(10));
- EXPECT_TRUE(hosts.empty());
-
- // For the correct hostname, there should be two reservations.
- hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
-
- // Make sure that two different hosts were returned.
- EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
- EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
-
- // Make sure that hostname is correct including its case.
- EXPECT_EQ("Host", hosts[0]->getHostname());
- EXPECT_EQ("hosT", hosts[1]->getHostname());
-}
-
-void
-HostMgrTest::testGetAllbyHostnameSubnet6(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Initially, no reservations should be present.
- ConstHostCollection hosts =
- HostMgr::instance().getAllbyHostname6("host", SubnetID(1));
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations with the same hostname.
- HostPtr host1(new Host(duids_[0]->toText(), "duid",
- SubnetID(1), SubnetID(1),
- IOAddress::IPV4_ZERO_ADDRESS()));
- host1->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
- IOAddress("2001:db8:1::5"), 128));
- host1->setHostname("Host");
- data_source1.add(host1);
- HostPtr host2(new Host(duids_[1]->toText(), "duid",
- SubnetID(1), SubnetID(1),
- IOAddress::IPV4_ZERO_ADDRESS()));
- host2->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
- IOAddress("2001:db8:1::6"), 128));
- host2->setHostname("hosT");
- data_source2.add(host2);
-
- CfgMgr::instance().commit();
-
- // If there non-matching hostname is specified, nothing should be
- // returned.
- hosts = HostMgr::instance().getAllbyHostname6("foobar", SubnetID(1));
- EXPECT_TRUE(hosts.empty());
-
- // If there non-matching subnet is specified, nothing should be
- // returned.
- hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(10));
- EXPECT_TRUE(hosts.empty());
-
- // For the correct hostname, there should be two reservations.
- hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
-
- // Make sure that two different hosts were returned.
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
- EXPECT_TRUE(hosts[1]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Make sure that hostname is correct including its case.
- EXPECT_EQ("Host", hosts[0]->getHostname());
- EXPECT_EQ("hosT", hosts[1]->getHostname());
-}
-
-void
-HostMgrTest::testGetPage4(bool use_database) {
- BaseHostDataSource& data_source1 = *getCfgHosts();
- BaseHostDataSource& data_source2 = HostMgr::instance();
-
- // Initially, no reservations should be present.
- size_t idx(0);
- HostPageSize page_size(10);
- ConstHostCollection hosts =
- HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
- ASSERT_TRUE(hosts.empty());
- if (use_database) {
- EXPECT_EQ(2, idx);
- } else {
- EXPECT_EQ(1, idx);
- }
-
- // Add two reservations for the same subnet.
- addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
- addHost4(use_database ? data_source2 : data_source1,
- hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.6"));
-
- CfgMgr::instance().commit();
-
- // If there non-matching subnet is specified, nothing should be returned.
- idx = 0;
- hosts = HostMgr::instance().getPage4(SubnetID(100), idx, 0, page_size);
- ASSERT_TRUE(hosts.empty());
-
- // For the correct subnet, there should be two reservations.
- idx = 0;
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
- if (use_database) {
- ASSERT_EQ(1, hosts.size());
- } else {
- ASSERT_EQ(2, hosts.size());
- }
-
- // Make sure that returned values are correct.
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
- if (!use_database) {
- EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
-
- // Check it was the last page.
- uint64_t hid = hosts[1]->getHostId();
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 1;
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-
- if (use_database) {
- uint64_t hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- ASSERT_EQ(0, idx);
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size);
- ASSERT_EQ(1, hosts.size());
- ASSERT_NE(0, idx);
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
-
- // Alternate way to use the database.
- idx = 1;
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
- ASSERT_EQ(1, hosts.size());
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
-
- // Check it was the last page.
- hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 2;
- hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-}
-
-void
-HostMgrTest::testGetPage6(bool use_database) {
- BaseHostDataSource& data_source1 = *getCfgHosts();
- BaseHostDataSource& data_source2 = HostMgr::instance();
-
- // Initially, no reservations should be present.
- size_t idx(0);
- HostPageSize page_size(10);
- ConstHostCollection hosts =
- HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
- ASSERT_TRUE(hosts.empty());
- if (use_database) {
- EXPECT_EQ(2, idx);
- } else {
- EXPECT_EQ(1, idx);
- }
-
- // Add two reservations for the same subnet.
- addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
- addHost6(use_database ? data_source2 : data_source1,
- duids_[1], SubnetID(1), IOAddress("2001:db8:1::6"));
-
- CfgMgr::instance().commit();
-
- // If there non-matching subnet is specified, nothing should be returned.
- idx = 0;
- hosts = HostMgr::instance().getPage6(SubnetID(100), idx, 0, page_size);
- ASSERT_TRUE(hosts.empty());
-
- // For the correct subnet, there should be two reservations.
- idx = 0;
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
- if (use_database) {
- ASSERT_EQ(1, hosts.size());
- } else {
- ASSERT_EQ(2, hosts.size());
- }
-
- // Make sure that returned values are correct.
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
- if (!use_database) {
- EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[1]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Check it was the last page.
- uint64_t hid = hosts[1]->getHostId();
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 1;
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-
- if (use_database) {
- uint64_t hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- ASSERT_EQ(0, idx);
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size);
- ASSERT_EQ(1, hosts.size());
- ASSERT_NE(0, idx);
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Alternate way to use the database.
- idx = 1;
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
- ASSERT_EQ(1, hosts.size());
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Check it was the last page.
- hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 2;
- hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-}
-
-void
-HostMgrTest::testGetPage4All(bool use_database) {
- BaseHostDataSource& data_source1 = *getCfgHosts();
- BaseHostDataSource& data_source2 = HostMgr::instance();
-
- // Initially, no reservations should be present.
- size_t idx(0);
- HostPageSize page_size(10);
- ConstHostCollection hosts =
- HostMgr::instance().getPage4(idx, 0, page_size);
- ASSERT_TRUE(hosts.empty());
- if (use_database) {
- EXPECT_EQ(2, idx);
- } else {
- EXPECT_EQ(1, idx);
- }
-
- // Add two reservations.
- addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
- addHost4(use_database ? data_source2 : data_source1,
- hwaddrs_[1], SubnetID(2), IOAddress("192.0.2.6"));
-
- CfgMgr::instance().commit();
-
- // There should be two reservations.
- idx = 0;
- hosts = HostMgr::instance().getPage4(idx, 0, page_size);
- if (use_database) {
- ASSERT_EQ(1, hosts.size());
- } else {
- ASSERT_EQ(2, hosts.size());
- }
-
- // Make sure that returned values are correct.
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
- if (!use_database) {
- EXPECT_EQ(2, hosts[1]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
-
- // Check it was the last page.
- uint64_t hid = hosts[1]->getHostId();
- hosts = HostMgr::instance().getPage4(idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 1;
- hosts = HostMgr::instance().getPage4(idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-
- if (use_database) {
- uint64_t hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- ASSERT_EQ(0, idx);
- hosts = HostMgr::instance().getPage4(idx, hid, page_size);
- ASSERT_EQ(1, hosts.size());
- ASSERT_NE(0, idx);
- EXPECT_EQ(2, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
-
- // Alternate way to use the database.
- idx = 1;
- hosts = HostMgr::instance().getPage4(idx, 0, page_size);
- ASSERT_EQ(1, hosts.size());
- EXPECT_EQ(2, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
-
- // Check it was the last page.
- hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- hosts = HostMgr::instance().getPage4(idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 2;
- hosts = HostMgr::instance().getPage4(idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-}
-
-void
-HostMgrTest::testGetPage6All(bool use_database) {
- BaseHostDataSource& data_source1 = *getCfgHosts();
- BaseHostDataSource& data_source2 = HostMgr::instance();
-
- // Initially, no reservations should be present.
- size_t idx(0);
- HostPageSize page_size(10);
- ConstHostCollection hosts =
- HostMgr::instance().getPage6(idx, 0, page_size);
- ASSERT_TRUE(hosts.empty());
- if (use_database) {
- EXPECT_EQ(2, idx);
- } else {
- EXPECT_EQ(1, idx);
- }
-
- // Add two reservations.
- addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
- addHost6(use_database ? data_source2 : data_source1,
- duids_[1], SubnetID(2), IOAddress("2001:db8:1::6"));
-
- CfgMgr::instance().commit();
-
- // There should be two reservations.
- idx = 0;
- hosts = HostMgr::instance().getPage6(idx, 0, page_size);
- if (use_database) {
- ASSERT_EQ(1, hosts.size());
- } else {
- ASSERT_EQ(2, hosts.size());
- }
-
- // Make sure that returned values are correct.
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
- if (!use_database) {
- EXPECT_EQ(2, hosts[1]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[1]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Check it was the last page.
- uint64_t hid = hosts[1]->getHostId();
- hosts = HostMgr::instance().getPage6(idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 1;
- hosts = HostMgr::instance().getPage6(idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-
- if (use_database) {
- uint64_t hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- ASSERT_EQ(0, idx);
- hosts = HostMgr::instance().getPage6(idx, hid, page_size);
- ASSERT_EQ(1, hosts.size());
- ASSERT_NE(0, idx);
- EXPECT_EQ(2, hosts[0]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Alternate way to use the database.
- idx = 1;
- hosts = HostMgr::instance().getPage6(idx, 0, page_size);
- ASSERT_EQ(1, hosts.size());
- EXPECT_EQ(2, hosts[0]->getIPv6SubnetID());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
-
- // Check it was the last page.
- hid = hosts[0]->getHostId();
- ASSERT_NE(0, hid);
- hosts = HostMgr::instance().getPage6(idx, hid, page_size);
- ASSERT_EQ(0, hosts.size());
- idx = 2;
- hosts = HostMgr::instance().getPage6(idx, 0, page_size);
- ASSERT_EQ(0, hosts.size());
- }
-}
-
-void
-HostMgrTest::testGetAll4(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Initially, no hosts should be present.
- ConstHostCollection hosts =
- HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
- ASSERT_TRUE(hosts.empty());
-
- // Add two hosts to different data sources.
- addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
- addHost4(data_source2, hwaddrs_[1], SubnetID(10), IOAddress("192.0.2.5"));
-
- CfgMgr::instance().commit();
-
- // Retrieve all hosts, This should return hosts from both sources
- // in a single container.
- hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that IPv4 address is correct.
- EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
- EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText());
-
- // Make sure that two different hosts were returned.
- EXPECT_NE(hosts[0]->getIPv4SubnetID(), hosts[1]->getIPv4SubnetID());
-}
-
-void
-HostMgrTest::testGet4(BaseHostDataSource& data_source) {
- // Initially, no host should be present.
- ConstHostPtr host =
- HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_FALSE(host);
-
- // Add new host to the database.
- addHost4(data_source, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
-
- CfgMgr::instance().commit();
-
- // Retrieve the host from the database and expect that the parameters match.
- host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_TRUE(host);
- EXPECT_EQ(1, host->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
-}
-
-void
-HostMgrTest::testGet4Any() {
- // Initially, no host should be present.
- ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- ASSERT_FALSE(host);
- HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- ASSERT_FALSE(host);
-
- // Add new host to the database.
- HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1),
- SUBNET_ID_UNUSED, IOAddress("192.0.2.5")));
- // Abuse of the server's configuration.
- getCfgHosts()->add(new_host);
-
- CfgMgr::instance().commit();
-
- // Retrieve the host from the database and expect that the parameters match.
- host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- ASSERT_TRUE(host);
- EXPECT_EQ(1, host->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
-
- // Set the negative cache flag on the host.
- new_host->setNegative(true);
-
- // get4 is not supposed to get it.
- host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- EXPECT_FALSE(host);
-
- // But get4Any should.
- host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- ASSERT_TRUE(host);
- EXPECT_EQ(1, host->getIPv4SubnetID());
- EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
- EXPECT_TRUE(host->getNegative());
-
- // To be sure. Note we use the CfgHosts source so only this
- // get4 overload works.
- host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- EXPECT_FALSE(host);
-}
-
-void
-HostMgrTest::testGet6(BaseHostDataSource& data_source) {
- // Initially, no host should be present.
- ConstHostPtr host =
- HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- ASSERT_FALSE(host);
-
- // Add new host to the database.
- addHost6(data_source, duids_[0], SubnetID(2), IOAddress("2001:db8:1::1"));
-
- CfgMgr::instance().commit();
-
- // Retrieve the host from the database and expect that the parameters match.
- host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID,
- &duids_[0]->getDuid()[0],
- duids_[0]->getDuid().size());
- ASSERT_TRUE(host);
- EXPECT_EQ(2, host->getIPv6SubnetID());
- EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
- IOAddress("2001:db8:1::1"))));
-}
-
-void
-HostMgrTest::testGet6Any() {
- // Initially, no host should be present.
- ConstHostPtr host = HostMgr::instance().get6(SubnetID(2),
- Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_FALSE(host);
- host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_FALSE(host);
-
- // Add new host to the database.
- HostPtr new_host(new Host(hwaddrs_[0]->toText(false), "hw-address",
- SubnetID(1), SubnetID(2),
- IOAddress::IPV4_ZERO_ADDRESS()));
- new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
- IOAddress("2001:db8:1::1"), 128));
- // Abuse of the server's configuration.
- getCfgHosts()->add(new_host);
-
- CfgMgr::instance().commit();
-
- // Retrieve the host from the database and expect that the parameters match.
- host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_TRUE(host);
- EXPECT_EQ(2, host->getIPv6SubnetID());
- EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
- IOAddress("2001:db8:1::1"))));
-
- // Set the negative cache flag on the host.
- new_host->setNegative(true);
-
- // get6 is not supposed to get it.
- host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- EXPECT_FALSE(host);
-
- // But get6Any should.
- host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- ASSERT_TRUE(host);
- EXPECT_EQ(2, host->getIPv6SubnetID());
- EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
- IOAddress("2001:db8:1::1"))));
- EXPECT_TRUE(host->getNegative());
-
- // To be sure. Note we use the CfgHosts source so only this
- // get6 overload works.
- host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
- &hwaddrs_[0]->hwaddr_[0],
- hwaddrs_[0]->hwaddr_.size());
- EXPECT_FALSE(host);
-}
-
-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.
- 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.
- addHost6(data_source2, duids_[1], SubnetID(3), IOAddress("2001:db8:1:0:6::"), 72);
-
- CfgMgr::instance().commit();
-
- // Retrieve first reservation.
- host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64);
- ASSERT_TRUE(host);
- EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
- IOAddress("2001:db8:1::"), 64)));
-
- // Make sure the first reservation is not retrieved when the prefix
- // length is incorrect.
- host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 72);
- EXPECT_FALSE(host);
-
- // Retrieve second reservation.
- host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 72);
- ASSERT_TRUE(host);
- EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
- IOAddress("2001:db8:1:0:6::"), 72)));
-
- // Make sure the second reservation is not retrieved when the prefix
- // length is incorrect.
- host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 64);
- EXPECT_FALSE(host);
-}
-
-void
-HostMgrTest::testGetAll4BySubnetIP(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Set the mode of operation with multiple reservations for the same
- // IP address.
- ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
- CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false);
-
- // Initially, no reservations should be present.
- ConstHostCollection hosts = HostMgr::instance().getAll4(SubnetID(1),
- IOAddress("192.0.2.5"));
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations for the same subnet and IP address.
- addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
- addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.5"));
-
- CfgMgr::instance().commit();
-
- // If there non-matching subnet is specified, nothing should be returned.
- hosts = HostMgr::instance().getAll4(SubnetID(100), IOAddress("192.0.2.5"));
- ASSERT_TRUE(hosts.empty());
-
- // For the correct subnet, there should be two reservations.
- hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("192.0.2.5"));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
- EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
-
- // Make sure that two hosts were returned with different identifiers
- // but the same address.
- EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText());
- EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
- EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText());
-}
-
-void
-HostMgrTest::testGetAll6BySubnetIP(BaseHostDataSource& data_source1,
- BaseHostDataSource& data_source2) {
- // Set the mode of operation with multiple reservations for the same
- // IP address.
- ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
- CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false);
-
- // Initially, no reservations should be present.
- ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1),
- IOAddress("2001:db8:1::5"));
- ASSERT_TRUE(hosts.empty());
-
- // Add two reservations for the same subnet.
- addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
- addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::5"));
-
- CfgMgr::instance().commit();
-
- // If there non-matching subnet is specified, nothing should be returned.
- hosts = HostMgr::instance().getAll6(SubnetID(100), IOAddress("2001:db8:1::5"));
- ASSERT_TRUE(hosts.empty());
-
- // For the correct subnet, there should be two reservations.
- hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::5"));
- ASSERT_EQ(2, hosts.size());
-
- // Make sure that subnet is correct.
- EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
- EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
-
- // Make sure that two hosts were returned with different identifiers
- // but the same address.
- EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText());
- EXPECT_TRUE(hosts[0]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
- EXPECT_TRUE(hosts[1]->hasReservation(
- IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
-}
-
// This test verifies that HostMgr returns all reservations for the
// specified HW address. The reservations are defined in the server's
// configuration.
EXPECT_THROW(HostMgr::instance().add(host), NoHostDataSourceManager);
}
-class HostMgrDbLostCallbackTest : public ::testing::Test {
-public:
- HostMgrDbLostCallbackTest()
- : db_lost_callback_called_(0), db_recovered_callback_called_(0),
- db_failed_callback_called_(0),
- io_service_(boost::make_shared<isc::asiolink::IOService>()) {
- db::DatabaseConnection::db_lost_callback_ = 0;
- db::DatabaseConnection::db_recovered_callback_ = 0;
- db::DatabaseConnection::db_failed_callback_ = 0;
- HostMgr::setIOService(io_service_);
- TimerMgr::instance()->setIOService(io_service_);
- CfgMgr::instance().clear();
- }
-
- ~HostMgrDbLostCallbackTest() {
- db::DatabaseConnection::db_lost_callback_ = 0;
- db::DatabaseConnection::db_recovered_callback_ = 0;
- db::DatabaseConnection::db_failed_callback_ = 0;
- HostMgr::setIOService(isc::asiolink::IOServicePtr());
- TimerMgr::instance()->unregisterTimers();
- CfgMgr::instance().clear();
- }
-
- /// @brief Prepares the class for a test.
- ///
- /// Invoked by gtest prior test entry, we create the
- /// appropriate schema and create a basic host manager to
- /// wipe out any prior instance
- virtual void SetUp() {
- HostMgr::setIOService(io_service_);
- db::DatabaseConnection::db_lost_callback_ = 0;
- db::DatabaseConnection::db_recovered_callback_ = 0;
- db::DatabaseConnection::db_failed_callback_ = 0;
- // Ensure we have the proper schema with no transient data.
- createSchema();
- // Wipe out any pre-existing mgr
- HostMgr::create();
- CfgMgr::instance().clear();
- }
-
- /// @brief Pre-text exit clean up
- ///
- /// Invoked by gtest upon test exit, we destroy the schema
- /// we created.
- virtual void TearDown() {
- HostMgr::setIOService(isc::asiolink::IOServicePtr());
- db::DatabaseConnection::db_lost_callback_ = 0;
- db::DatabaseConnection::db_recovered_callback_ = 0;
- db::DatabaseConnection::db_failed_callback_ = 0;
- // If data wipe enabled, delete transient data otherwise destroy the schema
- destroySchema();
- CfgMgr::instance().clear();
- }
-
- /// @brief Abstract method for destroying the back end specific shcema
- virtual void destroySchema() = 0;
-
- /// @brief Abstract method for creating the back end specific shcema
- virtual void createSchema() = 0;
-
- /// @brief Abstract method which returns the back end specific connection
- /// string
- virtual std::string validConnectString() = 0;
-
- /// @brief Abstract method which returns invalid back end specific connection
- /// string
- virtual std::string invalidConnectString() = 0;
-
-#if defined(HAVE_MYSQL) || defined(HAVE_PGSQL)
- /// @brief Verifies open failures do NOT invoke db lost callback
- ///
- /// The db lost callback should only be invoked after successfully
- /// opening the DB and then subsequently losing it. Failing to
- /// open should be handled directly by the application layer.
- void testNoCallbackOnOpenFailure();
-
- /// @brief Verifies the host manager's behavior if DB connection is lost
- ///
- /// This function creates a host manager with a back end that supports
- /// connectivity lost callback (currently only MySQL and PostgreSQL). It
- /// verifies connectivity by issuing a known valid query. Next it simulates
- /// connectivity lost by identifying and closing the socket connection to
- /// the CB backend. It then reissues the query and verifies that:
- /// -# The Query throws DbOperationError (rather than exiting)
- /// -# The registered DbLostCallback was invoked
- /// -# The registered DbRecoveredCallback was invoked
- void testDbLostAndRecoveredCallback();
-
- /// @brief Verifies the host manager's behavior if DB connection is lost
- ///
- /// This function creates a host manager with a back end that supports
- /// connectivity lost callback (currently only MySQL and PostgreSQL). It
- /// verifies connectivity by issuing a known valid query. Next it simulates
- /// connectivity lost by identifying and closing the socket connection to
- /// the CB backend. It then reissues the query and verifies that:
- /// -# The Query throws DbOperationError (rather than exiting)
- /// -# The registered DbLostCallback was invoked
- /// -# The registered DbFailedCallback was invoked
- void testDbLostAndFailedCallback();
-
- /// @brief Verifies the host manager's behavior if DB connection is lost
- ///
- /// This function creates a host manager with a back end that supports
- /// connectivity lost callback (currently only MySQL and PostgreSQL). It
- /// verifies connectivity by issuing a known valid query. Next it simulates
- /// connectivity lost by identifying and closing the socket connection to
- /// the CB backend. It then reissues the query and verifies that:
- /// -# The Query throws DbOperationError (rather than exiting)
- /// -# The registered DbLostCallback was invoked
- /// -# The registered DbRecoveredCallback was invoked after two reconnect
- /// attempts (once failing and second triggered by timer)
- void testDbLostAndRecoveredAfterTimeoutCallback();
-
- /// @brief Verifies the host manager's behavior if DB connection is lost
- ///
- /// This function creates a host manager with a back end that supports
- /// connectivity lost callback (currently only MySQL and PostgreSQL). It
- /// verifies connectivity by issuing a known valid query. Next it simulates
- /// connectivity lost by identifying and closing the socket connection to
- /// the CB backend. It then reissues the query and verifies that:
- /// -# The Query throws DbOperationError (rather than exiting)
- /// -# The registered DbLostCallback was invoked
- /// -# The registered DbFailedCallback was invoked after two reconnect
- /// attempts (once failing and second triggered by timer)
- void testDbLostAndFailedAfterTimeoutCallback();
-#endif
-
- /// @brief Callback function registered with the host manager
- bool db_lost_callback(db::ReconnectCtlPtr /* not_used */) {
- return (++db_lost_callback_called_);
- }
-
- /// @brief Flag used to detect calls to db_lost_callback function
- uint32_t db_lost_callback_called_;
-
- /// @brief Callback function registered with the host manager
- bool db_recovered_callback(db::ReconnectCtlPtr /* not_used */) {
- return (++db_recovered_callback_called_);
- }
-
- /// @brief Flag used to detect calls to db_recovered_callback function
- uint32_t db_recovered_callback_called_;
-
- /// @brief Callback function registered with the host manager
- bool db_failed_callback(db::ReconnectCtlPtr /* not_used */) {
- return (++db_failed_callback_called_);
- }
-
- /// @brief Flag used to detect calls to db_failed_callback function
- uint32_t db_failed_callback_called_;
-
- /// The IOService object, used for all ASIO operations.
- isc::asiolink::IOServicePtr io_service_;
-};
-
-#if defined(HAVE_MYSQL) || defined(HAVE_PGSQL)
-
-void
-HostMgrDbLostCallbackTest::testNoCallbackOnOpenFailure() {
- DatabaseConnection::db_lost_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
-
- // Set the connectivity recovered callback.
- DatabaseConnection::db_recovered_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
-
- // Set the connectivity failed callback.
- DatabaseConnection::db_failed_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
-
- // Connect to the host backend.
- ASSERT_THROW(HostMgr::addBackend(invalidConnectString()), DbOpenError);
-
- io_service_->poll();
-
- EXPECT_EQ(0, db_lost_callback_called_);
- EXPECT_EQ(0, db_recovered_callback_called_);
- EXPECT_EQ(0, db_failed_callback_called_);
-}
-
-void
-HostMgrDbLostCallbackTest::testDbLostAndRecoveredCallback() {
- // Set the connectivity lost callback.
- DatabaseConnection::db_lost_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
-
- // Set the connectivity recovered callback.
- DatabaseConnection::db_recovered_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
-
- // Set the connectivity failed callback.
- DatabaseConnection::db_failed_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
-
- std::string access = validConnectString();
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
-
- // Create the HostMgr.
- HostMgr::create();
-
- // Find the most recently opened socket. Our SQL client's socket should
- // be the next one.
- int last_open_socket = findLastSocketFd();
-
- // Fill holes.
- FillFdHoles holes(last_open_socket);
-
- // Connect to the host backend.
- ASSERT_NO_THROW(HostMgr::addBackend(access));
-
- // Find the SQL client socket.
- int sql_socket = findLastSocketFd();
- ASSERT_TRUE(sql_socket > last_open_socket);
-
- // Verify we can execute a query. We don't care about the answer.
- ConstHostCollection hosts;
- ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
-
- // Now close the sql socket out from under backend client
- ASSERT_EQ(0, close(sql_socket));
-
- // A query should fail with DbConnectionUnusable.
- ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
- DbConnectionUnusable);
-
- io_service_->poll();
-
- // Our lost and recovered connectivity callback should have been invoked.
- EXPECT_EQ(1, db_lost_callback_called_);
- EXPECT_EQ(1, db_recovered_callback_called_);
- EXPECT_EQ(0, db_failed_callback_called_);
-}
-
-void
-HostMgrDbLostCallbackTest::testDbLostAndFailedCallback() {
- // Set the connectivity lost callback.
- DatabaseConnection::db_lost_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
-
- // Set the connectivity recovered callback.
- DatabaseConnection::db_recovered_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
-
- // Set the connectivity failed callback.
- DatabaseConnection::db_failed_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
-
- std::string access = validConnectString();
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
-
- // Create the HostMgr.
- HostMgr::create();
-
- // Find the most recently opened socket. Our SQL client's socket should
- // be the next one.
- int last_open_socket = findLastSocketFd();
-
- // Fill holes.
- FillFdHoles holes(last_open_socket);
-
- // Connect to the host backend.
- ASSERT_NO_THROW(HostMgr::addBackend(access));
-
- // Find the SQL client socket.
- int sql_socket = findLastSocketFd();
- ASSERT_TRUE(sql_socket > last_open_socket);
-
- // Verify we can execute a query. We don't care about the answer.
- ConstHostCollection hosts;
- ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
-
- access = invalidConnectString();
- CfgMgr::instance().clear();
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access + " ");
-
- // Now close the sql socket out from under backend client
- ASSERT_EQ(0, close(sql_socket));
-
- // A query should fail with DbConnectionUnusable.
- ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
- DbConnectionUnusable);
-
- io_service_->poll();
-
- // Our lost and recovered connectivity callback should have been invoked.
- EXPECT_EQ(1, db_lost_callback_called_);
- EXPECT_EQ(0, db_recovered_callback_called_);
- EXPECT_EQ(1, db_failed_callback_called_);
-}
-
-void
-HostMgrDbLostCallbackTest::testDbLostAndRecoveredAfterTimeoutCallback() {
- // Set the connectivity lost callback.
- DatabaseConnection::db_lost_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
-
- // Set the connectivity recovered callback.
- DatabaseConnection::db_recovered_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
-
- // Set the connectivity failed callback.
- DatabaseConnection::db_failed_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
-
- std::string access = validConnectString();
- std::string extra = " max-reconnect-tries=2 reconnect-wait-time=1";
- access += extra;
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
-
- // Create the HostMgr.
- HostMgr::create();
-
- // Find the most recently opened socket. Our SQL client's socket should
- // be the next one.
- int last_open_socket = findLastSocketFd();
-
- // Fill holes.
- FillFdHoles holes(last_open_socket);
-
- // Connect to the host backend.
- ASSERT_NO_THROW(HostMgr::addBackend(access));
-
- // Find the SQL client socket.
- int sql_socket = findLastSocketFd();
- ASSERT_TRUE(sql_socket > last_open_socket);
-
- // Verify we can execute a query. We don't care about the answer.
- ConstHostCollection hosts;
- ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
-
- access = invalidConnectString();
- access += extra;
- CfgMgr::instance().clear();
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access + " ");
-
- // Now close the sql socket out from under backend client
- ASSERT_EQ(0, close(sql_socket));
-
- // A query should fail with DbConnectionUnusable.
- ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
- DbConnectionUnusable);
-
- io_service_->poll();
-
- // Our lost and recovered connectivity callback should have been invoked.
- EXPECT_EQ(1, db_lost_callback_called_);
- EXPECT_EQ(0, db_recovered_callback_called_);
- EXPECT_EQ(0, db_failed_callback_called_);
-
- access = validConnectString();
- access += extra;
- CfgMgr::instance().clear();
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
-
- sleep(1);
-
- io_service_->poll();
-
- // Our recovered connectivity callback should have been invoked.
- EXPECT_EQ(2, db_lost_callback_called_);
- EXPECT_EQ(1, db_recovered_callback_called_);
- EXPECT_EQ(0, db_failed_callback_called_);
-}
-
-void
-HostMgrDbLostCallbackTest::testDbLostAndFailedAfterTimeoutCallback() {
- // Set the connectivity lost callback.
- DatabaseConnection::db_lost_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
-
- // Set the connectivity recovered callback.
- DatabaseConnection::db_recovered_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
-
- // Set the connectivity failed callback.
- DatabaseConnection::db_failed_callback_ =
- std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
-
- std::string access = validConnectString();
- std::string extra = " max-reconnect-tries=2 reconnect-wait-time=1";
- access += extra;
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
-
- // Create the HostMgr.
- HostMgr::create();
-
- // Find the most recently opened socket. Our SQL client's socket should
- // be the next one.
- int last_open_socket = findLastSocketFd();
-
- // Fill holes.
- FillFdHoles holes(last_open_socket);
-
- // Connect to the host backend.
- ASSERT_NO_THROW(HostMgr::addBackend(access));
-
- // Find the SQL client socket.
- int sql_socket = findLastSocketFd();
- ASSERT_TRUE(sql_socket > last_open_socket);
-
- // Verify we can execute a query. We don't care about the answer.
- ConstHostCollection hosts;
- ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
-
- access = invalidConnectString();
- access += extra;
- CfgMgr::instance().clear();
- CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access + " ");
-
- // Now close the sql socket out from under backend client
- ASSERT_EQ(0, close(sql_socket));
-
- // A query should fail with DbConnectionUnusable.
- ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
- DbConnectionUnusable);
-
- io_service_->poll();
-
- // Our lost and recovered connectivity callback should have been invoked.
- EXPECT_EQ(1, db_lost_callback_called_);
- EXPECT_EQ(0, db_recovered_callback_called_);
- EXPECT_EQ(0, db_failed_callback_called_);
-
- sleep(1);
-
- io_service_->poll();
-
- // Our recovered connectivity callback should have been invoked.
- EXPECT_EQ(2, db_lost_callback_called_);
- EXPECT_EQ(0, db_recovered_callback_called_);
- EXPECT_EQ(1, db_failed_callback_called_);
-}
-#endif
-
-// 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 we have the proper schema with no transient data.
- db::test::createMySQLSchema();
-
- // Connect to the database
- try {
- HostMgr::addBackend(db::test::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() {
- HostMgr::instance().getHostDataSource()->rollback();
- HostMgr::delBackend("mysql");
-
- // If data wipe enabled, delete transient data otherwise destroy the schema
- db::test::destroyMySQLSchema();
-}
-
-/// @brief Test fixture class for validating @c HostMgr using
-/// MySQL as alternate host data source and MySQL connectivity loss.
-class MySQLHostMgrDbLostCallbackTest : public HostMgrDbLostCallbackTest {
-public:
- virtual void destroySchema() {
- // If data wipe enabled, delete transient data otherwise destroy the schema
- db::test::destroyMySQLSchema();
- }
-
- virtual void createSchema() {
- // Ensure we have the proper schema with no transient data.
- db::test::createMySQLSchema();
- }
-
- virtual std::string validConnectString() {
- return (db::test::validMySQLConnectionString());
- }
-
- virtual std::string invalidConnectString() {
- return (connectionString(MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
- VALID_USER, VALID_PASSWORD));
- }
-};
-
-// This test verifies that reservations for a particular client can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(MySQLHostMgrTest, getAll) {
- testGetAll(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(MySQLHostMgrTest, getAll4BySubnet) {
- testGetAll4BySubnet(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(MySQLHostMgrTest, getAll6BySubnet) {
- testGetAll6BySubnet(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that HostMgr returns all reservations for the specified
-// IPv4 subnet and reserved address.
-TEST_F(MySQLHostMgrTest, getAll4BySubnetIP) {
- testGetAll4BySubnetIP(*getCfgHosts(), *getCfgHosts());
-}
-
-// This test verifies that HostMgr returns all reservations for the specified
-// IPv6 subnet and reserved address.
-TEST_F(MySQLHostMgrTest, getAll6BySubnetIP) {
- testGetAll6BySubnetIP(*getCfgHosts(), *getCfgHosts());
-}
-
-// This test verifies that reservations for a particular hostname can be
-// retrieved from the configuration file and a database simultaneously.
-TEST_F(MySQLHostMgrTest, getAllbyHostname) {
- testGetAllbyHostname(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname and
-// DHCPv4 subnet can be retrieved from the configuration file and a
-// database simultaneously.
-TEST_F(MySQLHostMgrTest, getAllbyHostnameSubnet4) {
- testGetAllbyHostnameSubnet4(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname and
-// DHCPv6 subnet can be retrieved from the configuration file and a
-// database simultaneously.
-TEST_F(MySQLHostMgrTest, getAllbyHostnameSubnet6) {
- testGetAllbyHostnameSubnet6(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved by pages from the configuration file and a database
-// simultaneously.
-TEST_F(MySQLHostMgrTest, getPage4) {
- testGetPage4(true);
-}
-
-// This test verifies that all v4 reservations be retrieved by pages
-// from the configuration file and a database simultaneously.
-TEST_F(MySQLHostMgrTest, getPage4All) {
- testGetPage4All(true);
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved by pages from the configuration file and a database
-// simultaneously.
-TEST_F(MySQLHostMgrTest, getPage6) {
- testGetPage6(true);
-}
-
-// This test verifies that all v6 reservations be retrieved by pages
-// from the configuration file and a database simultaneously.
-TEST_F(MySQLHostMgrTest, getPage6All) {
- testGetPage6All(true);
-}
-
-// This test verifies that IPv4 reservations for a particular client can
-// be retrieved from the configuration file and a database simultaneously.
-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());
-}
-
-// This test verifies that it is possible to control whether the reserved
-// IP addresses are unique or non unique via the HostMgr.
-TEST_F(MySQLHostMgrTest, setIPReservationsUnique) {
- EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(true));
- EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
-}
-
-/// @brief Verifies that db lost callback is not invoked on an open failure
-TEST_F(MySQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailure) {
- MultiThreadingTest mt(false);
- testNoCallbackOnOpenFailure();
-}
-
-/// @brief Verifies that db lost callback is not invoked on an open failure
-TEST_F(MySQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
- MultiThreadingTest mt(true);
- testNoCallbackOnOpenFailure();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndRecoveredCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndRecoveredCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndFailedCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndFailedCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndRecoveredAfterTimeoutCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndRecoveredAfterTimeoutCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndFailedAfterTimeoutCallback();
-}
-
-/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
-TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndFailedAfterTimeoutCallback();
-}
-
-
-#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 Build PostgreSQL schema for a test.
- virtual void SetUp();
-
- /// @brief Rollback and drop PostgreSQL schema after the test.
- virtual void TearDown();
-};
-
-void
-PostgreSQLHostMgrTest::SetUp() {
- HostMgrTest::SetUp();
-
- // Ensure we have the proper schema with no transient data.
- db::test::createPgSQLSchema();
-
- // Connect to the database
- try {
- HostMgr::addBackend(db::test::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() {
- HostMgr::instance().getHostDataSource()->rollback();
- HostMgr::delBackend("postgresql");
- // If data wipe enabled, delete transient data otherwise destroy the schema
- db::test::destroyPgSQLSchema();
-}
-
-/// @brief Test fixture class for validating @c HostMgr using
-/// PostgreSQL as alternate host data source and PostgreSQL connectivity loss.
-class PostgreSQLHostMgrDbLostCallbackTest : public HostMgrDbLostCallbackTest {
-public:
- virtual void destroySchema() {
- // If data wipe enabled, delete transient data otherwise destroy the schema
- db::test::destroyPgSQLSchema();
- }
-
- virtual void createSchema() {
- // Ensure we have the proper schema with no transient data.
- db::test::createPgSQLSchema();
- }
-
- virtual std::string validConnectString() {
- return (db::test::validPgSQLConnectionString());
- }
-
- virtual std::string invalidConnectString() {
- return (connectionString(PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
- VALID_USER, VALID_PASSWORD));
- }
-};
-
-// This test verifies that reservations for a particular client can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getAll) {
- testGetAll(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getAll4BySubnet) {
- testGetAll4BySubnet(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getAll6BySubnet) {
- testGetAll6BySubnet(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that HostMgr returns all reservations for the specified
-// IPv4 subnet and reserved address.
-TEST_F(PostgreSQLHostMgrTest, getAll4BySubnetIP) {
- testGetAll4BySubnetIP(*getCfgHosts(), *getCfgHosts());
-}
-
-// This test verifies that HostMgr returns all reservations for the specified
-// IPv6 subnet and reserved address.
-TEST_F(PostgreSQLHostMgrTest, getAll6BySubnetIP) {
- testGetAll6BySubnetIP(*getCfgHosts(), *getCfgHosts());
-}
-
-// This test verifies that reservations for a particular hostname can be
-// retrieved from the configuration file and a database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getAllbyHostname) {
- testGetAllbyHostname(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname and
-// DHCPv4 subnet can be retrieved from the configuration file and a
-// database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getAllbyHostnameSubnet4) {
- testGetAllbyHostnameSubnet4(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname and
-// DHCPv6 subnet can be retrieved from the configuration file and a
-// database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getAllbyHostnameSubnet6) {
- testGetAllbyHostnameSubnet6(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved by pages from the configuration file and a database
-// simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getPage4) {
- testGetPage4(true);
-}
-
-// This test verifies that all v4 reservations be retrieved by pages
-// from the configuration file and a database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getPage4All) {
- testGetPage4All(true);
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved by pages from the configuration file and a database
-// simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getPage6) {
- testGetPage6(true);
-}
-
-// This test verifies that all v6 reservations be retrieved by pages
-// from the configuration file and a database simultaneously.
-TEST_F(PostgreSQLHostMgrTest, getPage6All) {
- testGetPage6All(true);
-}
-
-// This test verifies that IPv4 reservations for a particular client can
-// be retrieved from the configuration file and a database simultaneously.
-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());
-}
-
-// This test verifies that it is possible to control whether the reserved
-// IP addresses are unique or non unique via the HostMgr.
-TEST_F(PostgreSQLHostMgrTest, setIPReservationUnique) {
- EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(true));
- EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
-}
-
-/// @brief Verifies that db lost callback is not invoked on an open failure
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailure) {
- MultiThreadingTest mt(false);
- testNoCallbackOnOpenFailure();
-}
-
-/// @brief Verifies that db lost callback is not invoked on an open failure
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
- MultiThreadingTest mt(true);
- testNoCallbackOnOpenFailure();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndRecoveredCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndRecoveredCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndFailedCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndFailedCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndRecoveredAfterTimeoutCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndRecoveredAfterTimeoutCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
- MultiThreadingTest mt(false);
- testDbLostAndFailedAfterTimeoutCallback();
-}
-
-/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
-TEST_F(PostgreSQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
- MultiThreadingTest mt(true);
- testDbLostAndFailedAfterTimeoutCallback();
-}
-
-
-#endif
-
-// The following tests require Cassandra enabled.
-#if defined HAVE_CQL
-
-/// @brief Test fixture class for validating @c HostMgr using
-/// CQL as alternate host data source.
-class CQLHostMgrTest : public HostMgrTest {
-protected:
-
- /// @brief Build CQL schema for a test.
- virtual void SetUp();
-
- /// @brief Rollback and drop CQL schema after the test.
- virtual void TearDown();
-};
-
-void
-CQLHostMgrTest::SetUp() {
- HostMgrTest::SetUp();
-
- // Ensure we have the proper schema with no transient data.
- db::test::createCqlSchema();
-
- // Connect to the database
- try {
- HostMgr::addBackend(db::test::validCqlConnectionString());
- } catch (...) {
- std::cerr << "*** ERROR: unable to open database. The test\n"
- "*** environment is broken and must be fixed before\n"
- "*** the CQL tests will run correctly.\n"
- "*** The reason for the problem is described in the\n"
- "*** accompanying exception output.\n";
- throw;
- }
-}
-
-void
-CQLHostMgrTest::TearDown() {
- HostMgr::instance().getHostDataSource()->rollback();
- HostMgr::delBackend("cql");
-
- // If data wipe enabled, delete transient data otherwise destroy the schema
- db::test::destroyCqlSchema();
-}
-
-// This test verifies that reservations for a particular client can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getAll) {
- testGetAll(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getAll4BySubnet) {
- testGetAll4BySubnet(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getAll6BySubnet) {
- testGetAll6BySubnet(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname can be
-// retrieved from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getAllbyHostname) {
- testGetAllbyHostname(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname and
-// DHCPv4 subnet can be retrieved from the configuration file and a
-// database simultaneously.
-TEST_F(CQLHostMgrTest, getAllbyHostnameSubnet4) {
- testGetAllbyHostnameSubnet4(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular hostname and
-// DHCPv6 subnet can be retrieved from the configuration file and a
-// database simultaneously.
-TEST_F(CQLHostMgrTest, getAllbyHostnameSubnet6) {
- testGetAllbyHostnameSubnet6(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved by pages from the configuration file and a database
-// simultaneously.
-TEST_F(CQLHostMgrTest, getPage4) {
- testGetPage4(true);
-}
-
-// This test verifies that all v4 reservations be retrieved by pages
-// from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getPage4All) {
- testGetPage4All(true);
-}
-
-// This test verifies that reservations for a particular subnet can
-// be retrieved by pages from the configuration file and a database
-// simultaneously.
-TEST_F(CQLHostMgrTest, getPage6) {
- testGetPage6(true);
-}
-
-// This test verifies that all v6 reservations be retrieved by pages
-// from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getPage6All) {
- testGetPage6All(true);
-}
-
-// This test verifies that IPv4 reservations for a particular client can
-// be retrieved from the configuration file and a database simultaneously.
-TEST_F(CQLHostMgrTest, getAll4) {
- testGetAll4(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that the IPv4 reservation can be retrieved from a
-// database.
-TEST_F(CQLHostMgrTest, get4) {
- testGet4(HostMgr::instance());
-}
-
-// This test verifies that the IPv6 reservation can be retrieved from a
-// database.
-TEST_F(CQLHostMgrTest, get6) {
- testGet6(HostMgr::instance());
-}
-
-// This test verifies that the IPv6 prefix reservation can be retrieved
-// from a configuration file and a database.
-TEST_F(CQLHostMgrTest, get6ByPrefix) {
- testGet6ByPrefix(*getCfgHosts(), HostMgr::instance());
-}
-
-// This test verifies that it is possible to control whether the reserved
-// IP addresses are unique or non unique via the HostMgr.
-TEST_F(CQLHostMgrTest, setIPReservationsUnique) {
- EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(true));
- // This is currently not supported for Cassandra.
- EXPECT_FALSE(HostMgr::instance().setIPReservationsUnique(false));
-}
-
-#endif
-
} // namespace
testMultipleHosts6();
}
+/// @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 we have the proper schema with no transient data.
+ db::test::createMySQLSchema();
+
+ // Connect to the database
+ try {
+ HostMgr::addBackend(db::test::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() {
+ HostMgr::instance().getHostDataSource()->rollback();
+ HostMgr::delBackend("mysql");
+ // If data wipe enabled, delete transient data otherwise destroy the schema
+ db::test::destroyMySQLSchema();
+}
+
+/// @brief Test fixture class for validating @c HostMgr using
+/// MySQL as alternate host data source and MySQL connectivity loss.
+class MySQLHostMgrDbLostCallbackTest : public HostMgrDbLostCallbackTest {
+public:
+ virtual void destroySchema() {
+ // If data wipe enabled, delete transient data otherwise destroy the schema
+ db::test::destroyMySQLSchema();
+ }
+
+ virtual void createSchema() {
+ // Ensure we have the proper schema with no transient data.
+ db::test::createMySQLSchema();
+ }
+
+ virtual std::string validConnectString() {
+ return (db::test::validMySQLConnectionString());
+ }
+
+ virtual std::string invalidConnectString() {
+ return (connectionString(MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
+ VALID_USER, VALID_PASSWORD));
+ }
+};
+
+// This test verifies that reservations for a particular client can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getAll) {
+ testGetAll(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getAll4BySubnet) {
+ testGetAll4BySubnet(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getAll6BySubnet) {
+ testGetAll6BySubnet(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that HostMgr returns all reservations for the specified
+// IPv4 subnet and reserved address.
+TEST_F(MySQLHostMgrTest, getAll4BySubnetIP) {
+ testGetAll4BySubnetIP(*getCfgHosts(), *getCfgHosts());
+}
+
+// This test verifies that HostMgr returns all reservations for the specified
+// IPv6 subnet and reserved address.
+TEST_F(MySQLHostMgrTest, getAll6BySubnetIP) {
+ testGetAll6BySubnetIP(*getCfgHosts(), *getCfgHosts());
+}
+
+// This test verifies that reservations for a particular hostname can be
+// retrieved from the configuration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getAllbyHostname) {
+ testGetAllbyHostname(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname and
+// DHCPv4 subnet can be retrieved from the configuration file and a
+// database simultaneously.
+TEST_F(MySQLHostMgrTest, getAllbyHostnameSubnet4) {
+ testGetAllbyHostnameSubnet4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname and
+// DHCPv6 subnet can be retrieved from the configuration file and a
+// database simultaneously.
+TEST_F(MySQLHostMgrTest, getAllbyHostnameSubnet6) {
+ testGetAllbyHostnameSubnet6(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved by pages from the configuration file and a database
+// simultaneously.
+TEST_F(MySQLHostMgrTest, getPage4) {
+ testGetPage4(true);
+}
+
+// This test verifies that all v4 reservations be retrieved by pages
+// from the configuration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getPage4All) {
+ testGetPage4All(true);
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved by pages from the configuration file and a database
+// simultaneously.
+TEST_F(MySQLHostMgrTest, getPage6) {
+ testGetPage6(true);
+}
+
+// This test verifies that all v6 reservations be retrieved by pages
+// from the configuration file and a database simultaneously.
+TEST_F(MySQLHostMgrTest, getPage6All) {
+ testGetPage6All(true);
+}
+
+// This test verifies that IPv4 reservations for a particular client can
+// be retrieved from the configuration file and a database simultaneously.
+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());
+}
+
+// This test verifies that it is possible to control whether the reserved
+// IP addresses are unique or non unique via the HostMgr.
+TEST_F(MySQLHostMgrTest, setIPReservationsUnique) {
+ EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(true));
+ EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
+}
+
+/// @brief Verifies that db lost callback is not invoked on an open failure
+TEST_F(MySQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailure) {
+ MultiThreadingTest mt(false);
+ testNoCallbackOnOpenFailure();
+}
+
+/// @brief Verifies that db lost callback is not invoked on an open failure
+TEST_F(MySQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
+ MultiThreadingTest mt(true);
+ testNoCallbackOnOpenFailure();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to MySQL is handled correctly.
+TEST_F(MySQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
} // namespace
testMultipleHosts6();
}
+/// @brief Test fixture class for validating @c HostMgr using
+/// PostgreSQL as alternate host data source.
+class PgSQLHostMgrTest : public HostMgrTest {
+protected:
+
+ /// @brief Build PostgreSQL schema for a test.
+ virtual void SetUp();
+
+ /// @brief Rollback and drop PostgreSQL schema after the test.
+ virtual void TearDown();
+};
+
+void
+PgSQLHostMgrTest::SetUp() {
+ HostMgrTest::SetUp();
+
+ // Ensure we have the proper schema with no transient data.
+ db::test::createPgSQLSchema();
+
+ // Connect to the database
+ try {
+ HostMgr::addBackend(db::test::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
+PgSQLHostMgrTest::TearDown() {
+ HostMgr::instance().getHostDataSource()->rollback();
+ HostMgr::delBackend("postgresql");
+ // If data wipe enabled, delete transient data otherwise destroy the schema
+ db::test::destroyPgSQLSchema();
+}
+
+/// @brief Test fixture class for validating @c HostMgr using
+/// PostgreSQL as alternate host data source and PostgreSQL connectivity loss.
+class PgSQLHostMgrDbLostCallbackTest : public HostMgrDbLostCallbackTest {
+public:
+ virtual void destroySchema() {
+ // If data wipe enabled, delete transient data otherwise destroy the schema
+ db::test::destroyPgSQLSchema();
+ }
+
+ virtual void createSchema() {
+ // Ensure we have the proper schema with no transient data.
+ db::test::createPgSQLSchema();
+ }
+
+ virtual std::string validConnectString() {
+ return (db::test::validPgSQLConnectionString());
+ }
+
+ virtual std::string invalidConnectString() {
+ return (connectionString(PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST,
+ VALID_USER, VALID_PASSWORD));
+ }
+};
+
+// This test verifies that reservations for a particular client can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAll) {
+ testGetAll(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAll4BySubnet) {
+ testGetAll4BySubnet(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAll6BySubnet) {
+ testGetAll6BySubnet(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that HostMgr returns all reservations for the specified
+// IPv4 subnet and reserved address.
+TEST_F(PgSQLHostMgrTest, getAll4BySubnetIP) {
+ testGetAll4BySubnetIP(*getCfgHosts(), *getCfgHosts());
+}
+
+// This test verifies that HostMgr returns all reservations for the specified
+// IPv6 subnet and reserved address.
+TEST_F(PgSQLHostMgrTest, getAll6BySubnetIP) {
+ testGetAll6BySubnetIP(*getCfgHosts(), *getCfgHosts());
+}
+
+// This test verifies that reservations for a particular hostname can be
+// retrieved from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAllbyHostname) {
+ testGetAllbyHostname(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname and
+// DHCPv4 subnet can be retrieved from the configuration file and a
+// database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAllbyHostnameSubnet4) {
+ testGetAllbyHostnameSubnet4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular hostname and
+// DHCPv6 subnet can be retrieved from the configuration file and a
+// database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAllbyHostnameSubnet6) {
+ testGetAllbyHostnameSubnet6(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved by pages from the configuration file and a database
+// simultaneously.
+TEST_F(PgSQLHostMgrTest, getPage4) {
+ testGetPage4(true);
+}
+
+// This test verifies that all v4 reservations be retrieved by pages
+// from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getPage4All) {
+ testGetPage4All(true);
+}
+
+// This test verifies that reservations for a particular subnet can
+// be retrieved by pages from the configuration file and a database
+// simultaneously.
+TEST_F(PgSQLHostMgrTest, getPage6) {
+ testGetPage6(true);
+}
+
+// This test verifies that all v6 reservations be retrieved by pages
+// from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getPage6All) {
+ testGetPage6All(true);
+}
+
+// This test verifies that IPv4 reservations for a particular client can
+// be retrieved from the configuration file and a database simultaneously.
+TEST_F(PgSQLHostMgrTest, getAll4) {
+ testGetAll4(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that the IPv4 reservation can be retrieved from a
+// database.
+TEST_F(PgSQLHostMgrTest, get4) {
+ testGet4(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 reservation can be retrieved from a
+// database.
+TEST_F(PgSQLHostMgrTest, get6) {
+ testGet6(HostMgr::instance());
+}
+
+// This test verifies that the IPv6 prefix reservation can be retrieved
+// from a configuration file and a database.
+TEST_F(PgSQLHostMgrTest, get6ByPrefix) {
+ testGet6ByPrefix(*getCfgHosts(), HostMgr::instance());
+}
+
+// This test verifies that it is possible to control whether the reserved
+// IP addresses are unique or non unique via the HostMgr.
+TEST_F(PgSQLHostMgrTest, setIPReservationsUnique) {
+ EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(true));
+ EXPECT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
+}
+
+/// @brief Verifies that db lost callback is not invoked on an open failure
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailure) {
+ MultiThreadingTest mt(false);
+ testNoCallbackOnOpenFailure();
+}
+
+/// @brief Verifies that db lost callback is not invoked on an open failure
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testNoCallbackOnOpenFailureMultiThreading) {
+ MultiThreadingTest mt(true);
+ testNoCallbackOnOpenFailure();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndFailedCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndRecoveredAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndRecoveredAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallback) {
+ MultiThreadingTest mt(false);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
+/// @brief Verifies that loss of connectivity to PostgreSQL is handled correctly.
+TEST_F(PgSQLHostMgrDbLostCallbackTest, testDbLostAndFailedAfterTimeoutCallbackMultiThreading) {
+ MultiThreadingTest mt(true);
+ testDbLostAndFailedAfterTimeoutCallback();
+}
+
} // namespace
#include <dhcp/option_int.h>
#include <dhcp/option_string.h>
#include <dhcp/option_vendor.h>
-#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
+#include <dhcpsrv/tests/test_utils.h>
#include <dhcpsrv/testutils/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
#include <database/testutils/schema.h>
using namespace isc::db::test;
using namespace isc::util;
using namespace isc::data;
+namespace ph = std::placeholders;
namespace isc {
namespace dhcp {
ASSERT_NO_THROW(hdsptr_->add(host2));
}
+void
+HostMgrDbLostCallbackTest::testNoCallbackOnOpenFailure() {
+ isc::db::DatabaseConnection::db_lost_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ isc::db::DatabaseConnection::db_recovered_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ isc::db::DatabaseConnection::db_failed_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ // Connect to the host backend.
+ ASSERT_THROW(HostMgr::addBackend(invalidConnectString()), DbOpenError);
+
+ io_service_->poll();
+
+ EXPECT_EQ(0, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+}
+
+void
+HostMgrDbLostCallbackTest::testDbLostAndRecoveredCallback() {
+ // Set the connectivity lost callback.
+ isc::db::DatabaseConnection::db_lost_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ isc::db::DatabaseConnection::db_recovered_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ isc::db::DatabaseConnection::db_failed_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
+
+ // Create the HostMgr.
+ HostMgr::create();
+
+ // Find the most recently opened socket. Our SQL client's socket should
+ // be the next one.
+ int last_open_socket = findLastSocketFd();
+
+ // Fill holes.
+ FillFdHoles holes(last_open_socket);
+
+ // Connect to the host backend.
+ ASSERT_NO_THROW(HostMgr::addBackend(access));
+
+ // Find the SQL client socket.
+ int sql_socket = findLastSocketFd();
+ ASSERT_TRUE(sql_socket > last_open_socket);
+
+ // Verify we can execute a query. We don't care about the answer.
+ ConstHostCollection hosts;
+ ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost and recovered connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(1, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+}
+
+void
+HostMgrDbLostCallbackTest::testDbLostAndFailedCallback() {
+ // Set the connectivity lost callback.
+ isc::db::DatabaseConnection::db_lost_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ isc::db::DatabaseConnection::db_recovered_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ isc::db::DatabaseConnection::db_failed_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
+
+ // Create the HostMgr.
+ HostMgr::create();
+
+ // Find the most recently opened socket. Our SQL client's socket should
+ // be the next one.
+ int last_open_socket = findLastSocketFd();
+
+ // Fill holes.
+ FillFdHoles holes(last_open_socket);
+
+ // Connect to the host backend.
+ ASSERT_NO_THROW(HostMgr::addBackend(access));
+
+ // Find the SQL client socket.
+ int sql_socket = findLastSocketFd();
+ ASSERT_TRUE(sql_socket > last_open_socket);
+
+ // Verify we can execute a query. We don't care about the answer.
+ ConstHostCollection hosts;
+ ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
+
+ access = invalidConnectString();
+ CfgMgr::instance().clear();
+ // by adding an extra space in the access string will cause the DatabaseConnection::parse
+ // to throw resulting in failure to recreate the manager
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access + " ");
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost and recovered connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(1, db_failed_callback_called_);
+}
+
+void
+HostMgrDbLostCallbackTest::testDbLostAndRecoveredAfterTimeoutCallback() {
+ // Set the connectivity lost callback.
+ isc::db::DatabaseConnection::db_lost_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ isc::db::DatabaseConnection::db_recovered_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ isc::db::DatabaseConnection::db_failed_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ std::string extra = " max-reconnect-tries=2 reconnect-wait-time=1";
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
+
+ // Create the HostMgr.
+ HostMgr::create();
+
+ // Find the most recently opened socket. Our SQL client's socket should
+ // be the next one.
+ int last_open_socket = findLastSocketFd();
+
+ // Fill holes.
+ FillFdHoles holes(last_open_socket);
+
+ // Connect to the host backend.
+ ASSERT_NO_THROW(HostMgr::addBackend(access));
+
+ // Find the SQL client socket.
+ int sql_socket = findLastSocketFd();
+ ASSERT_TRUE(sql_socket > last_open_socket);
+
+ // Verify we can execute a query. We don't care about the answer.
+ ConstHostCollection hosts;
+ ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
+
+ access = invalidConnectString();
+ access += extra;
+ CfgMgr::instance().clear();
+ // by adding an extra space in the access string will cause the DatabaseConnection::parse
+ // to throw resulting in failure to recreate the manager
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access + " ");
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost and recovered connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+
+ access = validConnectString();
+ access += extra;
+ CfgMgr::instance().clear();
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
+
+ sleep(1);
+
+ io_service_->poll();
+
+ // Our recovered connectivity callback should have been invoked.
+ EXPECT_EQ(2, db_lost_callback_called_);
+ EXPECT_EQ(1, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+}
+
+void
+HostMgrDbLostCallbackTest::testDbLostAndFailedAfterTimeoutCallback() {
+ // Set the connectivity lost callback.
+ isc::db::DatabaseConnection::db_lost_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1);
+
+ // Set the connectivity recovered callback.
+ isc::db::DatabaseConnection::db_recovered_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1);
+
+ // Set the connectivity failed callback.
+ isc::db::DatabaseConnection::db_failed_callback_ =
+ std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1);
+
+ std::string access = validConnectString();
+ std::string extra = " max-reconnect-tries=2 reconnect-wait-time=1";
+ access += extra;
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access);
+
+ // Create the HostMgr.
+ HostMgr::create();
+
+ // Find the most recently opened socket. Our SQL client's socket should
+ // be the next one.
+ int last_open_socket = findLastSocketFd();
+
+ // Fill holes.
+ FillFdHoles holes(last_open_socket);
+
+ // Connect to the host backend.
+ ASSERT_NO_THROW(HostMgr::addBackend(access));
+
+ // Find the SQL client socket.
+ int sql_socket = findLastSocketFd();
+ ASSERT_TRUE(sql_socket > last_open_socket);
+
+ // Verify we can execute a query. We don't care about the answer.
+ ConstHostCollection hosts;
+ ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")));
+
+ access = invalidConnectString();
+ access += extra;
+ CfgMgr::instance().clear();
+ // by adding an extra space in the access string will cause the DatabaseConnection::parse
+ // to throw resulting in failure to recreate the manager
+ CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access + " ");
+
+ // Now close the sql socket out from under backend client
+ ASSERT_EQ(0, close(sql_socket));
+
+ // A query should fail with DbConnectionUnusable.
+ ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")),
+ DbConnectionUnusable);
+
+ io_service_->poll();
+
+ // Our lost and recovered connectivity callback should have been invoked.
+ EXPECT_EQ(1, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(0, db_failed_callback_called_);
+
+ sleep(1);
+
+ io_service_->poll();
+
+ // Our recovered connectivity callback should have been invoked.
+ EXPECT_EQ(2, db_lost_callback_called_);
+ EXPECT_EQ(0, db_recovered_callback_called_);
+ EXPECT_EQ(1, db_failed_callback_called_);
+}
+
+void
+// cppcheck-suppress unusedFunction
+HostMgrTest::SetUp() {
+ // Remove all configuration which may be dangling from the previous test.
+ CfgMgr::instance().clear();
+ // Recreate HostMgr instance. It drops any previous state.
+ HostMgr::create();
+ // Create HW addresses from the template.
+ const uint8_t mac_template[] = {
+ 0x01, 0x02, 0x0A, 0xBB, 0x03, 0x00
+ };
+ for (uint8_t i = 0; i < 10; ++i) {
+ std::vector<uint8_t> vec(mac_template,
+ mac_template + sizeof(mac_template));
+ vec[vec.size() - 1] = i;
+ HWAddrPtr hwaddr(new HWAddr(vec, HTYPE_ETHER));
+ hwaddrs_.push_back(hwaddr);
+ }
+ // Create DUIDs from the template.
+ const uint8_t duid_template[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00
+ };
+ for (uint8_t i = 0; i < 10; ++i) {
+ std::vector<uint8_t> vec(duid_template,
+ duid_template + sizeof(mac_template));
+ vec[vec.size() - 1] = i;
+ DuidPtr duid(new DUID(vec));
+ duids_.push_back(duid);
+ }
+}
+
+CfgHostsPtr
+HostMgrTest::getCfgHosts() const {
+ return (CfgMgr::instance().getStagingCfg()->getCfgHosts());
+}
+
+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, SUBNET_ID_UNUSED,
+ 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(Host::IDENT_HWADDR,
+ &hwaddrs_[1]->hwaddr_[0],
+ hwaddrs_[1]->hwaddr_.size());
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations for the same HW address. They differ by the IP
+ // address reserved and the IPv4 subnet.
+ 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
+ // returned.
+ hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
+ &hwaddrs_[1]->hwaddr_[0],
+ hwaddrs_[1]->hwaddr_.size());
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct HW address, there should be two reservations.
+ hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_EQ(2, hosts.size());
+
+ // We don't know the order in which the reservations are returned so
+ // we have to match with any of the two reservations returned.
+
+ // Look for the first reservation.
+ bool found = false;
+ for (unsigned i = 0; i < 2; ++i) {
+ if (hosts[0]->getIPv4Reservation() == IOAddress("192.0.2.5")) {
+ ASSERT_EQ(1, hosts[0]->getIPv4SubnetID());
+ found = true;
+ }
+ }
+ if (!found) {
+ ADD_FAILURE() << "Reservation for the IPv4 address 192.0.2.5"
+ " not found using getAll method";
+ }
+
+ // Look for the second reservation.
+ found = false;
+ for (unsigned i = 0; i < 2; ++i) {
+ if (hosts[1]->getIPv4Reservation() == IOAddress("192.0.3.10")) {
+ ASSERT_EQ(10, hosts[1]->getIPv4SubnetID());
+ found = true;
+ }
+ }
+ if (!found) {
+ ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10"
+ " not found using getAll method";
+ }
+}
+
+void
+HostMgrTest::testGetAll4BySubnet(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts = HostMgr::instance().getAll4(SubnetID(1));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations for the same subnet.
+ addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+ addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.6"));
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching subnet is specified, nothing should be returned.
+ hosts = HostMgr::instance().getAll4(SubnetID(100));
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct subnet, there should be two reservations.
+ hosts = HostMgr::instance().getAll4(SubnetID(1));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
+
+ // Make sure that two different hosts were returned.
+ EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+ EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
+}
+
+void
+HostMgrTest::testGetAll6BySubnet(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations for the same subnet.
+ addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
+ addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::6"));
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching subnet is specified, nothing should be returned.
+ hosts = HostMgr::instance().getAll6(SubnetID(100));
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct subnet, there should be two reservations.
+ hosts = HostMgr::instance().getAll6(SubnetID(1));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
+
+ // Make sure that two different hosts were returned.
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
+ EXPECT_TRUE(hosts[1]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+}
+
+void
+HostMgrTest::testGetAllbyHostname(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts =
+ HostMgr::instance().getAllbyHostname("host");
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations with the same hostname.
+ HostPtr host1(new Host(hwaddrs_[0]->toText(false), "hw-address",
+ SubnetID(1), SUBNET_ID_UNUSED,
+ IOAddress("192.0.2.5")));
+ host1->setHostname("Host");
+ data_source1.add(host1);
+ HostPtr host2(new Host(hwaddrs_[1]->toText(false), "hw-address",
+ SubnetID(10), SUBNET_ID_UNUSED,
+ IOAddress("192.0.3.10")));
+ host2->setHostname("hosT");
+ data_source2.add(host2);
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching hostname is specified, nothing should be
+ // returned.
+ hosts = HostMgr::instance().getAllbyHostname("foobar");
+ EXPECT_TRUE(hosts.empty());
+
+ // For the correct hostname, there should be two reservations.
+ hosts = HostMgr::instance().getAllbyHostname("host");
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ(10, hosts[1]->getIPv4SubnetID());
+
+ // Make sure that hostname is correct including its case.
+ EXPECT_EQ("Host", hosts[0]->getHostname());
+ EXPECT_EQ("hosT", hosts[1]->getHostname());
+}
+
+void
+HostMgrTest::testGetAllbyHostnameSubnet4(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts =
+ HostMgr::instance().getAllbyHostname4("host", SubnetID(1));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations with the same hostname.
+ HostPtr host1(new Host(hwaddrs_[0]->toText(false), "hw-address",
+ SubnetID(1), SUBNET_ID_UNUSED,
+ IOAddress("192.0.2.5")));
+ host1->setHostname("Host");
+ data_source1.add(host1);
+ HostPtr host2(new Host(hwaddrs_[1]->toText(false), "hw-address",
+ SubnetID(1), SUBNET_ID_UNUSED,
+ IOAddress("192.0.2.6")));
+ host2->setHostname("hosT");
+ data_source2.add(host2);
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching hostname is specified, nothing should be
+ // returned.
+ hosts = HostMgr::instance().getAllbyHostname4("foobar", SubnetID(1));
+ EXPECT_TRUE(hosts.empty());
+
+ // If there non-matching subnet is specified, nothing should be
+ // returned.
+ hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(10));
+ EXPECT_TRUE(hosts.empty());
+
+ // For the correct hostname, there should be two reservations.
+ hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
+
+ // Make sure that two different hosts were returned.
+ EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+ EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
+
+ // Make sure that hostname is correct including its case.
+ EXPECT_EQ("Host", hosts[0]->getHostname());
+ EXPECT_EQ("hosT", hosts[1]->getHostname());
+}
+
+void
+HostMgrTest::testGetAllbyHostnameSubnet6(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts =
+ HostMgr::instance().getAllbyHostname6("host", SubnetID(1));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations with the same hostname.
+ HostPtr host1(new Host(duids_[0]->toText(), "duid",
+ SubnetID(1), SubnetID(1),
+ IOAddress::IPV4_ZERO_ADDRESS()));
+ host1->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ IOAddress("2001:db8:1::5"), 128));
+ host1->setHostname("Host");
+ data_source1.add(host1);
+ HostPtr host2(new Host(duids_[1]->toText(), "duid",
+ SubnetID(1), SubnetID(1),
+ IOAddress::IPV4_ZERO_ADDRESS()));
+ host2->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ IOAddress("2001:db8:1::6"), 128));
+ host2->setHostname("hosT");
+ data_source2.add(host2);
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching hostname is specified, nothing should be
+ // returned.
+ hosts = HostMgr::instance().getAllbyHostname6("foobar", SubnetID(1));
+ EXPECT_TRUE(hosts.empty());
+
+ // If there non-matching subnet is specified, nothing should be
+ // returned.
+ hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(10));
+ EXPECT_TRUE(hosts.empty());
+
+ // For the correct hostname, there should be two reservations.
+ hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
+
+ // Make sure that two different hosts were returned.
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
+ EXPECT_TRUE(hosts[1]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Make sure that hostname is correct including its case.
+ EXPECT_EQ("Host", hosts[0]->getHostname());
+ EXPECT_EQ("hosT", hosts[1]->getHostname());
+}
+
+void
+HostMgrTest::testGetPage4(bool use_database) {
+ BaseHostDataSource& data_source1 = *getCfgHosts();
+ BaseHostDataSource& data_source2 = HostMgr::instance();
+
+ // Initially, no reservations should be present.
+ size_t idx(0);
+ HostPageSize page_size(10);
+ ConstHostCollection hosts =
+ HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
+ ASSERT_TRUE(hosts.empty());
+ if (use_database) {
+ EXPECT_EQ(2, idx);
+ } else {
+ EXPECT_EQ(1, idx);
+ }
+
+ // Add two reservations for the same subnet.
+ addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+ addHost4(use_database ? data_source2 : data_source1,
+ hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.6"));
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching subnet is specified, nothing should be returned.
+ idx = 0;
+ hosts = HostMgr::instance().getPage4(SubnetID(100), idx, 0, page_size);
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct subnet, there should be two reservations.
+ idx = 0;
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
+ if (use_database) {
+ ASSERT_EQ(1, hosts.size());
+ } else {
+ ASSERT_EQ(2, hosts.size());
+ }
+
+ // Make sure that returned values are correct.
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+ if (!use_database) {
+ EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
+
+ // Check it was the last page.
+ uint64_t hid = hosts[1]->getHostId();
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 1;
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+
+ if (use_database) {
+ uint64_t hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ ASSERT_EQ(0, idx);
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size);
+ ASSERT_EQ(1, hosts.size());
+ ASSERT_NE(0, idx);
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
+
+ // Alternate way to use the database.
+ idx = 1;
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
+ ASSERT_EQ(1, hosts.size());
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
+
+ // Check it was the last page.
+ hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 2;
+ hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+}
+
+void
+HostMgrTest::testGetPage6(bool use_database) {
+ BaseHostDataSource& data_source1 = *getCfgHosts();
+ BaseHostDataSource& data_source2 = HostMgr::instance();
+
+ // Initially, no reservations should be present.
+ size_t idx(0);
+ HostPageSize page_size(10);
+ ConstHostCollection hosts =
+ HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
+ ASSERT_TRUE(hosts.empty());
+ if (use_database) {
+ EXPECT_EQ(2, idx);
+ } else {
+ EXPECT_EQ(1, idx);
+ }
+
+ // Add two reservations for the same subnet.
+ addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
+ addHost6(use_database ? data_source2 : data_source1,
+ duids_[1], SubnetID(1), IOAddress("2001:db8:1::6"));
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching subnet is specified, nothing should be returned.
+ idx = 0;
+ hosts = HostMgr::instance().getPage6(SubnetID(100), idx, 0, page_size);
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct subnet, there should be two reservations.
+ idx = 0;
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
+ if (use_database) {
+ ASSERT_EQ(1, hosts.size());
+ } else {
+ ASSERT_EQ(2, hosts.size());
+ }
+
+ // Make sure that returned values are correct.
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
+ if (!use_database) {
+ EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[1]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Check it was the last page.
+ uint64_t hid = hosts[1]->getHostId();
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 1;
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+
+ if (use_database) {
+ uint64_t hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ ASSERT_EQ(0, idx);
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size);
+ ASSERT_EQ(1, hosts.size());
+ ASSERT_NE(0, idx);
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Alternate way to use the database.
+ idx = 1;
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
+ ASSERT_EQ(1, hosts.size());
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Check it was the last page.
+ hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 2;
+ hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+}
+
+void
+HostMgrTest::testGetPage4All(bool use_database) {
+ BaseHostDataSource& data_source1 = *getCfgHosts();
+ BaseHostDataSource& data_source2 = HostMgr::instance();
+
+ // Initially, no reservations should be present.
+ size_t idx(0);
+ HostPageSize page_size(10);
+ ConstHostCollection hosts =
+ HostMgr::instance().getPage4(idx, 0, page_size);
+ ASSERT_TRUE(hosts.empty());
+ if (use_database) {
+ EXPECT_EQ(2, idx);
+ } else {
+ EXPECT_EQ(1, idx);
+ }
+
+ // Add two reservations.
+ addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+ addHost4(use_database ? data_source2 : data_source1,
+ hwaddrs_[1], SubnetID(2), IOAddress("192.0.2.6"));
+
+ CfgMgr::instance().commit();
+
+ // There should be two reservations.
+ idx = 0;
+ hosts = HostMgr::instance().getPage4(idx, 0, page_size);
+ if (use_database) {
+ ASSERT_EQ(1, hosts.size());
+ } else {
+ ASSERT_EQ(2, hosts.size());
+ }
+
+ // Make sure that returned values are correct.
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+ if (!use_database) {
+ EXPECT_EQ(2, hosts[1]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText());
+
+ // Check it was the last page.
+ uint64_t hid = hosts[1]->getHostId();
+ hosts = HostMgr::instance().getPage4(idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 1;
+ hosts = HostMgr::instance().getPage4(idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+
+ if (use_database) {
+ uint64_t hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ ASSERT_EQ(0, idx);
+ hosts = HostMgr::instance().getPage4(idx, hid, page_size);
+ ASSERT_EQ(1, hosts.size());
+ ASSERT_NE(0, idx);
+ EXPECT_EQ(2, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
+
+ // Alternate way to use the database.
+ idx = 1;
+ hosts = HostMgr::instance().getPage4(idx, 0, page_size);
+ ASSERT_EQ(1, hosts.size());
+ EXPECT_EQ(2, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText());
+
+ // Check it was the last page.
+ hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ hosts = HostMgr::instance().getPage4(idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 2;
+ hosts = HostMgr::instance().getPage4(idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+}
+
+void
+HostMgrTest::testGetPage6All(bool use_database) {
+ BaseHostDataSource& data_source1 = *getCfgHosts();
+ BaseHostDataSource& data_source2 = HostMgr::instance();
+
+ // Initially, no reservations should be present.
+ size_t idx(0);
+ HostPageSize page_size(10);
+ ConstHostCollection hosts =
+ HostMgr::instance().getPage6(idx, 0, page_size);
+ ASSERT_TRUE(hosts.empty());
+ if (use_database) {
+ EXPECT_EQ(2, idx);
+ } else {
+ EXPECT_EQ(1, idx);
+ }
+
+ // Add two reservations.
+ addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
+ addHost6(use_database ? data_source2 : data_source1,
+ duids_[1], SubnetID(2), IOAddress("2001:db8:1::6"));
+
+ CfgMgr::instance().commit();
+
+ // There should be two reservations.
+ idx = 0;
+ hosts = HostMgr::instance().getPage6(idx, 0, page_size);
+ if (use_database) {
+ ASSERT_EQ(1, hosts.size());
+ } else {
+ ASSERT_EQ(2, hosts.size());
+ }
+
+ // Make sure that returned values are correct.
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
+ if (!use_database) {
+ EXPECT_EQ(2, hosts[1]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[1]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Check it was the last page.
+ uint64_t hid = hosts[1]->getHostId();
+ hosts = HostMgr::instance().getPage6(idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 1;
+ hosts = HostMgr::instance().getPage6(idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+
+ if (use_database) {
+ uint64_t hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ ASSERT_EQ(0, idx);
+ hosts = HostMgr::instance().getPage6(idx, hid, page_size);
+ ASSERT_EQ(1, hosts.size());
+ ASSERT_NE(0, idx);
+ EXPECT_EQ(2, hosts[0]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Alternate way to use the database.
+ idx = 1;
+ hosts = HostMgr::instance().getPage6(idx, 0, page_size);
+ ASSERT_EQ(1, hosts.size());
+ EXPECT_EQ(2, hosts[0]->getIPv6SubnetID());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"))));
+
+ // Check it was the last page.
+ hid = hosts[0]->getHostId();
+ ASSERT_NE(0, hid);
+ hosts = HostMgr::instance().getPage6(idx, hid, page_size);
+ ASSERT_EQ(0, hosts.size());
+ idx = 2;
+ hosts = HostMgr::instance().getPage6(idx, 0, page_size);
+ ASSERT_EQ(0, hosts.size());
+ }
+}
+
+void
+HostMgrTest::testGetAll4(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Initially, no hosts should be present.
+ ConstHostCollection hosts =
+ HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two hosts to different data sources.
+ addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+ addHost4(data_source2, hwaddrs_[1], SubnetID(10), IOAddress("192.0.2.5"));
+
+ CfgMgr::instance().commit();
+
+ // Retrieve all hosts, This should return hosts from both sources
+ // in a single container.
+ hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that IPv4 address is correct.
+ EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+ EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText());
+
+ // Make sure that two different hosts were returned.
+ EXPECT_NE(hosts[0]->getIPv4SubnetID(), hosts[1]->getIPv4SubnetID());
+}
+
+void
+HostMgrTest::testGet4(BaseHostDataSource& data_source) {
+ // Initially, no host should be present.
+ ConstHostPtr host =
+ HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_FALSE(host);
+
+ // Add new host to the database.
+ addHost4(data_source, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+
+ CfgMgr::instance().commit();
+
+ // Retrieve the host from the database and expect that the parameters match.
+ host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_TRUE(host);
+ EXPECT_EQ(1, host->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
+}
+
+void
+HostMgrTest::testGet4Any() {
+ // Initially, no host should be present.
+ ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ ASSERT_FALSE(host);
+ HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ ASSERT_FALSE(host);
+
+ // Add new host to the database.
+ HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1),
+ SUBNET_ID_UNUSED, IOAddress("192.0.2.5")));
+ // Abuse of the server's configuration.
+ getCfgHosts()->add(new_host);
+
+ CfgMgr::instance().commit();
+
+ // Retrieve the host from the database and expect that the parameters match.
+ host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ ASSERT_TRUE(host);
+ EXPECT_EQ(1, host->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
+
+ // Set the negative cache flag on the host.
+ new_host->setNegative(true);
+
+ // get4 is not supposed to get it.
+ host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ EXPECT_FALSE(host);
+
+ // But get4Any should.
+ host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ ASSERT_TRUE(host);
+ EXPECT_EQ(1, host->getIPv4SubnetID());
+ EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
+ EXPECT_TRUE(host->getNegative());
+
+ // To be sure. Note we use the CfgHosts source so only this
+ // get4 overload works.
+ host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ EXPECT_FALSE(host);
+}
+
+void
+HostMgrTest::testGet6(BaseHostDataSource& data_source) {
+ // Initially, no host should be present.
+ ConstHostPtr host =
+ HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ ASSERT_FALSE(host);
+
+ // Add new host to the database.
+ addHost6(data_source, duids_[0], SubnetID(2), IOAddress("2001:db8:1::1"));
+
+ CfgMgr::instance().commit();
+
+ // Retrieve the host from the database and expect that the parameters match.
+ host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID,
+ &duids_[0]->getDuid()[0],
+ duids_[0]->getDuid().size());
+ ASSERT_TRUE(host);
+ EXPECT_EQ(2, host->getIPv6SubnetID());
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ IOAddress("2001:db8:1::1"))));
+}
+
+void
+HostMgrTest::testGet6Any() {
+ // Initially, no host should be present.
+ ConstHostPtr host = HostMgr::instance().get6(SubnetID(2),
+ Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_FALSE(host);
+ host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_FALSE(host);
+
+ // Add new host to the database.
+ HostPtr new_host(new Host(hwaddrs_[0]->toText(false), "hw-address",
+ SubnetID(1), SubnetID(2),
+ IOAddress::IPV4_ZERO_ADDRESS()));
+ new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ IOAddress("2001:db8:1::1"), 128));
+ // Abuse of the server's configuration.
+ getCfgHosts()->add(new_host);
+
+ CfgMgr::instance().commit();
+
+ // Retrieve the host from the database and expect that the parameters match.
+ host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_TRUE(host);
+ EXPECT_EQ(2, host->getIPv6SubnetID());
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ IOAddress("2001:db8:1::1"))));
+
+ // Set the negative cache flag on the host.
+ new_host->setNegative(true);
+
+ // get6 is not supposed to get it.
+ host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ EXPECT_FALSE(host);
+
+ // But get6Any should.
+ host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ ASSERT_TRUE(host);
+ EXPECT_EQ(2, host->getIPv6SubnetID());
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+ IOAddress("2001:db8:1::1"))));
+ EXPECT_TRUE(host->getNegative());
+
+ // To be sure. Note we use the CfgHosts source so only this
+ // get6 overload works.
+ host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR,
+ &hwaddrs_[0]->hwaddr_[0],
+ hwaddrs_[0]->hwaddr_.size());
+ EXPECT_FALSE(host);
+}
+
+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.
+ 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.
+ addHost6(data_source2, duids_[1], SubnetID(3), IOAddress("2001:db8:1:0:6::"), 72);
+
+ CfgMgr::instance().commit();
+
+ // Retrieve first reservation.
+ host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64);
+ ASSERT_TRUE(host);
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
+ IOAddress("2001:db8:1::"), 64)));
+
+ // Make sure the first reservation is not retrieved when the prefix
+ // length is incorrect.
+ host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 72);
+ EXPECT_FALSE(host);
+
+ // Retrieve second reservation.
+ host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 72);
+ ASSERT_TRUE(host);
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
+ IOAddress("2001:db8:1:0:6::"), 72)));
+
+ // Make sure the second reservation is not retrieved when the prefix
+ // length is incorrect.
+ host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 64);
+ EXPECT_FALSE(host);
+}
+
+void
+HostMgrTest::testGetAll4BySubnetIP(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Set the mode of operation with multiple reservations for the same
+ // IP address.
+ ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false);
+
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts = HostMgr::instance().getAll4(SubnetID(1),
+ IOAddress("192.0.2.5"));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations for the same subnet and IP address.
+ addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5"));
+ addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.5"));
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching subnet is specified, nothing should be returned.
+ hosts = HostMgr::instance().getAll4(SubnetID(100), IOAddress("192.0.2.5"));
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct subnet, there should be two reservations.
+ hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("192.0.2.5"));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv4SubnetID());
+ EXPECT_EQ(1, hosts[1]->getIPv4SubnetID());
+
+ // Make sure that two hosts were returned with different identifiers
+ // but the same address.
+ EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText());
+ EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText());
+ EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText());
+}
+
+void
+HostMgrTest::testGetAll6BySubnetIP(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2) {
+ // Set the mode of operation with multiple reservations for the same
+ // IP address.
+ ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false);
+
+ // Initially, no reservations should be present.
+ ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1),
+ IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(hosts.empty());
+
+ // Add two reservations for the same subnet.
+ addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"));
+ addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::5"));
+
+ CfgMgr::instance().commit();
+
+ // If there non-matching subnet is specified, nothing should be returned.
+ hosts = HostMgr::instance().getAll6(SubnetID(100), IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(hosts.empty());
+
+ // For the correct subnet, there should be two reservations.
+ hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::5"));
+ ASSERT_EQ(2, hosts.size());
+
+ // Make sure that subnet is correct.
+ EXPECT_EQ(1, hosts[0]->getIPv6SubnetID());
+ EXPECT_EQ(1, hosts[1]->getIPv6SubnetID());
+
+ // Make sure that two hosts were returned with different identifiers
+ // but the same address.
+ EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText());
+ EXPECT_TRUE(hosts[0]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
+ EXPECT_TRUE(hosts[1]->hasReservation(
+ IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"))));
+}
+
} // namespace test
} // namespace dhcp
} // namespace isc
#define GENERIC_HOST_DATA_SOURCE_UNITTEST_H
#include <asiolink/io_address.h>
+#include <database/database_connection.h>
#include <dhcpsrv/base_host_data_source.h>
+#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/host.h>
+#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/testutils/generic_backend_unittest.h>
#include <dhcp/classify.h>
#include <dhcp/option.h>
};
+class HostMgrDbLostCallbackTest : public ::testing::Test {
+public:
+ HostMgrDbLostCallbackTest()
+ : db_lost_callback_called_(0), db_recovered_callback_called_(0),
+ db_failed_callback_called_(0),
+ io_service_(boost::make_shared<isc::asiolink::IOService>()) {
+ isc::db::DatabaseConnection::db_lost_callback_ = 0;
+ isc::db::DatabaseConnection::db_recovered_callback_ = 0;
+ isc::db::DatabaseConnection::db_failed_callback_ = 0;
+ isc::dhcp::HostMgr::setIOService(io_service_);
+ isc::dhcp::TimerMgr::instance()->setIOService(io_service_);
+ isc::dhcp::CfgMgr::instance().clear();
+ }
+
+ ~HostMgrDbLostCallbackTest() {
+ isc::db::DatabaseConnection::db_lost_callback_ = 0;
+ isc::db::DatabaseConnection::db_recovered_callback_ = 0;
+ isc::db::DatabaseConnection::db_failed_callback_ = 0;
+ isc::dhcp::HostMgr::setIOService(isc::asiolink::IOServicePtr());
+ isc::dhcp::TimerMgr::instance()->unregisterTimers();
+ isc::dhcp::CfgMgr::instance().clear();
+ }
+
+ /// @brief Prepares the class for a test.
+ ///
+ /// Invoked by gtest prior test entry, we create the
+ /// appropriate schema and create a basic host manager to
+ /// wipe out any prior instance
+ virtual void SetUp() {
+ isc::dhcp::HostMgr::setIOService(io_service_);
+ isc::db::DatabaseConnection::db_lost_callback_ = 0;
+ isc::db::DatabaseConnection::db_recovered_callback_ = 0;
+ isc::db::DatabaseConnection::db_failed_callback_ = 0;
+ // Ensure we have the proper schema with no transient data.
+ createSchema();
+ // Wipe out any pre-existing mgr
+ isc::dhcp::HostMgr::create();
+ isc::dhcp::CfgMgr::instance().clear();
+ }
+
+ /// @brief Pre-text exit clean up
+ ///
+ /// Invoked by gtest upon test exit, we destroy the schema
+ /// we created.
+ virtual void TearDown() {
+ isc::dhcp::HostMgr::setIOService(isc::asiolink::IOServicePtr());
+ isc::db::DatabaseConnection::db_lost_callback_ = 0;
+ isc::db::DatabaseConnection::db_recovered_callback_ = 0;
+ isc::db::DatabaseConnection::db_failed_callback_ = 0;
+ // If data wipe enabled, delete transient data otherwise destroy the schema
+ destroySchema();
+ isc::dhcp::CfgMgr::instance().clear();
+ }
+
+ /// @brief Abstract method for destroying the back end specific shcema
+ virtual void destroySchema() = 0;
+
+ /// @brief Abstract method for creating the back end specific shcema
+ virtual void createSchema() = 0;
+
+ /// @brief Abstract method which returns the back end specific connection
+ /// string
+ virtual std::string validConnectString() = 0;
+
+ /// @brief Abstract method which returns invalid back end specific connection
+ /// string
+ virtual std::string invalidConnectString() = 0;
+
+ /// @brief Verifies open failures do NOT invoke db lost callback
+ ///
+ /// The db lost callback should only be invoked after successfully
+ /// opening the DB and then subsequently losing it. Failing to
+ /// open should be handled directly by the application layer.
+ void testNoCallbackOnOpenFailure();
+
+ /// @brief Verifies the host manager's behavior if DB connection is lost
+ ///
+ /// This function creates a host manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifying and
+ /// closing the socket connection to the host backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbRecoveredCallback was invoked
+ void testDbLostAndRecoveredCallback();
+
+ /// @brief Verifies the host manager's behavior if DB connection is lost
+ ///
+ /// This function creates a host manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifying and
+ /// closing the socket connection to the host backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbFailedCallback was invoked
+ void testDbLostAndFailedCallback();
+
+ /// @brief Verifies the host manager's behavior if DB connection is lost
+ ///
+ /// This function creates a host manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifyingLost and
+ /// closing the socket connection to the host backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbRecoveredCallback was invoked after two reconnect
+ /// attempts (once failing and second triggered by timer)
+ void testDbLostAndRecoveredAfterTimeoutCallback();
+
+ /// @brief Verifies the host manager's behavior if DB connection is lost
+ ///
+ /// This function creates a host manager with an back end that
+ /// supports connectivity lost callback (currently only MySQL and
+ /// PostgreSQL currently). It verifies connectivity by issuing a known
+ /// valid query. Next it simulates connectivity lost by identifyingLost and
+ /// closing the socket connection to the host backend. It then reissues
+ /// the query and verifies that:
+ /// -# The Query throws DbOperationError (rather than exiting)
+ /// -# The registered DbLostCallback was invoked
+ /// -# The registered DbFailedCallback was invoked after two reconnect
+ /// attempts (once failing and second triggered by timer)
+ void testDbLostAndFailedAfterTimeoutCallback();
+
+ /// @brief Callback function registered with the host manager
+ bool db_lost_callback(db::ReconnectCtlPtr /* not_used */) {
+ return (++db_lost_callback_called_);
+ }
+
+ /// @brief Flag used to detect calls to db_lost_callback function
+ uint32_t db_lost_callback_called_;
+
+ /// @brief Callback function registered with the host manager
+ bool db_recovered_callback(db::ReconnectCtlPtr /* not_used */) {
+ return (++db_recovered_callback_called_);
+ }
+
+ /// @brief Flag used to detect calls to db_recovered_callback function
+ uint32_t db_recovered_callback_called_;
+
+ /// @brief Callback function registered with the host manager
+ bool db_failed_callback(db::ReconnectCtlPtr /* not_used */) {
+ return (++db_failed_callback_called_);
+ }
+
+ /// @brief Flag used to detect calls to db_failed_callback function
+ uint32_t db_failed_callback_called_;
+
+ /// The IOService object, used for all ASIO operations.
+ isc::asiolink::IOServicePtr io_service_;
+};
+
+/// @brief Test fixture class for @c HostMgr class.
+class HostMgrTest : public ::testing::Test {
+protected:
+
+ /// @brief Prepares the class for a test.
+ ///
+ /// This method crates a handful of unique HW address and DUID objects
+ /// for use in unit tests. These objects are held in the @c hwaddrs_ and
+ /// @c duids_ members respectively.
+ ///
+ /// This method also resets the @c CfgMgr configuration and re-creates
+ /// the @c HostMgr object.
+ virtual void SetUp();
+
+ /// @brief Convenience method returning a pointer to the @c CfgHosts object
+ /// 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 isc::asiolink::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 isc::asiolink::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 HostMgr returns all reservations for the
+ /// specified DHCPv4 subnet.
+ ///
+ /// 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 testGetAll4BySubnet(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified DHCPv6 subnet.
+ ///
+ /// 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 testGetAll6BySubnet(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified hostname.
+ ///
+ /// 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 testGetAllbyHostname(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified hostname and DHCPv4 subnet.
+ ///
+ /// 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 testGetAllbyHostnameSubnet4(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified hostname and DHCPv6 subnet.
+ ///
+ /// 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 testGetAllbyHostnameSubnet6(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified DHCPv4 subnet by pages.
+ ///
+ /// If reservations are added to different host data sources, it is expected
+ /// that the @c HostMgr will retrieve reservations from both of them.
+ ///
+ /// @param use_database True when the second reservation is inserted
+ /// in a database.
+ void testGetPage4(bool use_database);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified DHCPv6 subnet by pages.
+ ///
+ /// If reservations are added to different host data sources, it is expected
+ /// that the @c HostMgr will retrieve reservations from both of them.
+ ///
+ /// @param use_database True when the second reservation is inserted
+ /// in a database.
+ void testGetPage6(bool use_database);
+
+ /// @brief This test verifies that HostMgr returns all reservations
+ /// by pages.
+ ///
+ /// If reservations are added to different host data sources, it is expected
+ /// that the @c HostMgr will retrieve reservations from both of them.
+ ///
+ /// @param use_database True when the second reservation is inserted
+ /// in a database.
+ void testGetPage4All(bool use_database);
+
+ /// @brief This test verifies that HostMgr returns all reservations
+ /// by pages.
+ ///
+ /// If reservations are added to different host data sources, it is expected
+ /// that the @c HostMgr will retrieve reservations from both of them.
+ ///
+ /// @param use_database True when the second reservation is inserted
+ /// in a database.
+ void testGetPage6All(bool use_database);
+
+ /// @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 negative
+ /// cached reservation with and only with get4Any.
+ void testGet4Any();
+
+ /// @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 negative
+ /// cached reservation with and only with get6Any.
+ void testGet6Any();
+
+ /// @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 This test verifies that HostMgr returns all reservations for the
+ /// specified DHCPv4 subnet and IPv4 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 testGetAll4BySubnetIP(BaseHostDataSource& data_source1,
+ BaseHostDataSource& data_source2);
+
+ /// @brief This test verifies that HostMgr returns all reservations for the
+ /// specified DHCPv6 subnet and IPv6 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 testGetAll6BySubnetIP(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.
+ std::vector<DuidPtr> duids_;
+};
+
} // namespace test
} // namespace dhcp
} // namespace isc