From: Marcin Siodelski Date: Thu, 18 Aug 2016 16:21:26 +0000 (+0200) Subject: [4323] Implemented tests for use of alternate host data source. X-Git-Tag: trac4631_base~12^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5eef188306fd2496159a535c357c95d6fb99347;p=thirdparty%2Fkea.git [4323] Implemented tests for use of alternate host data source. --- diff --git a/src/lib/dhcpsrv/host_mgr.cc b/src/lib/dhcpsrv/host_mgr.cc index 16709c5be8..090a5433ac 100644 --- a/src/lib/dhcpsrv/host_mgr.cc +++ b/src/lib/dhcpsrv/host_mgr.cc @@ -47,7 +47,7 @@ HostMgr::create(const std::string& access) { HostDataSourceFactory::create(access); } else { // Ok, no parameters were specified. We should destroy the existing - // insteance. + // instance. HostDataSourceFactory::destroy(); } @@ -214,8 +214,12 @@ HostMgr::get6(const SubnetID& subnet_id, } void -HostMgr::add(const HostPtr&) { - isc_throw(isc::NotImplemented, "HostMgr::add is not implemented"); +HostMgr::add(const HostPtr& host) { + if (!alternate_source_) { + isc_throw(NoHostDataSourceManager, "unable to add new host because there is " + "no alternate host data source present"); + } + alternate_source_->add(host); } } // end of isc::dhcp namespace diff --git a/src/lib/dhcpsrv/host_mgr.h b/src/lib/dhcpsrv/host_mgr.h index f4633281b9..f7483fe074 100644 --- a/src/lib/dhcpsrv/host_mgr.h +++ b/src/lib/dhcpsrv/host_mgr.h @@ -53,7 +53,7 @@ namespace dhcp { /// reservations specified in the configuration file) can't be disabled. /// /// @todo Implement alternate host data sources: MySQL, PostgreSQL, etc. -class HostMgr : public boost::noncopyable, BaseHostDataSource { +class HostMgr : public boost::noncopyable, public BaseHostDataSource { public: /// @brief Creates new instance of the @c HostMgr. diff --git a/src/lib/dhcpsrv/tests/host_mgr_unittest.cc b/src/lib/dhcpsrv/tests/host_mgr_unittest.cc index 2abad6c444..0f67f33bc1 100644 --- a/src/lib/dhcpsrv/tests/host_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_mgr_unittest.cc @@ -9,12 +9,23 @@ #include #include #include +#include #include + +#if defined HAVE_MYSQL +#include +#endif + +#if defined HAVE_PGSQL +#include +#endif + #include #include using namespace isc; using namespace isc::dhcp; +using namespace isc::dhcp::test; using namespace isc::asiolink; namespace { @@ -37,6 +48,85 @@ protected: /// in the @c CfgMgr. CfgHostsPtr getCfgHosts() const; + /// @brief Inserts IPv4 reservation into the host data source. + /// + /// @param data_source Reference to the data source to which the reservation + /// should be inserted. + /// @param hwaddr Pointer to the hardware address to be associated with the + /// reservation. + /// @param subnet_id IPv4 subnet id. + /// @param address IPv4 address to be reserved. + void addHost4(BaseHostDataSource& data_source, + const HWAddrPtr& hwaddr, + const SubnetID& subnet_id, + const IOAddress& address); + + /// @brief Inserts IPv6 reservation into the host data source. + /// + /// @param data_source Reference to the data source to which the reservation + /// should be inserted. + /// @param duid Pointer to the DUID to be associated with the reservation. + /// @param subnet_id IPv6 subnet id. + /// @param address IPv6 address/prefix to be reserved. + /// @param prefix_len Prefix length. The default value is 128 which + /// indicates that the reservation is for an IPv6 address rather than a + /// prefix. + void addHost6(BaseHostDataSource& data_source, + const DuidPtr& duid, + const SubnetID& subnet_id, + const IOAddress& address, + const uint8_t prefix_len = 128); + + /// @brief This test verifies that HostMgr returns all reservations for the + /// specified HW address. + /// + /// If reservations are added to different host data sources, it is expected + /// that the @c HostMgr will retrieve reservations from both of them. + /// + /// @param data_source1 Host data source to which first reservation is + /// inserted. + /// @param data_source2 Host data source to which second reservation is + /// inserted. + void testGetAll(BaseHostDataSource& data_source1, + BaseHostDataSource& data_source2); + + /// @brief This test verifies that it is possible to retrieve IPv4 + /// reservation for the particular host using HostMgr. + /// + /// If reservations are added to different host data sources, it is expected + /// that the @c HostMgr will retrieve reservations from both of them. + /// + /// @param data_source1 Host data source to which first reservation is + /// inserted. + /// @param data_source2 Host data source to which second reservation is + /// inserted. + void testGetAll4(BaseHostDataSource& data_source1, + BaseHostDataSource& data_source2); + + /// @brief This test verifies that it is possible to retrieve an IPv4 + /// reservation for the particular host using HostMgr. + /// + /// @param data_source Host data source to which reservation is inserted and + /// from which it will be retrieved. + void testGet4(BaseHostDataSource& data_source); + + /// @brief This test verifies that it is possible to retrieve an IPv6 + /// reservation for the particular host using HostMgr. + /// + /// @param data_source Host data source to which reservation is inserted and + /// from which it will be retrieved. + void testGet6(BaseHostDataSource& data_source); + + /// @brief This test verifies that it is possible to retrieve an IPv6 + /// prefix reservation for the particular host using HostMgr. + /// + /// @param data_source1 Host data source to which first reservation is + /// inserted. + /// @param data_source2 Host data source to which second reservation is + /// inserted. + void testGet6ByPrefix(BaseHostDataSource& data_source1, + BaseHostDataSource& data_source2); + /// @brief HW addresses to be used by the tests. std::vector hwaddrs_; /// @brief DUIDs to be used by the tests. @@ -79,22 +169,43 @@ HostMgrTest::getCfgHosts() const { return (CfgMgr::instance().getStagingCfg()->getCfgHosts()); } -/// This test verifies that HostMgr returns all reservations for the -/// specified HW address. The reservations are defined in the server's -/// configuration. -TEST_F(HostMgrTest, getAll) { +void +HostMgrTest::addHost4(BaseHostDataSource& data_source, + const HWAddrPtr& hwaddr, + const SubnetID& subnet_id, + const IOAddress& address) { + data_source.add(HostPtr(new Host(hwaddr->toText(false), + "hw-address", subnet_id, SubnetID(0), + address))); +} + +void +HostMgrTest::addHost6(BaseHostDataSource& data_source, + const DuidPtr& duid, + const SubnetID& subnet_id, + const IOAddress& address, + const uint8_t prefix_len) { + HostPtr new_host(new Host(duid->toText(), "duid", SubnetID(1), + subnet_id, IOAddress::IPV4_ZERO_ADDRESS())); + new_host->addReservation(IPv6Resrv(prefix_len == 128 ? IPv6Resrv::TYPE_NA : + IPv6Resrv::TYPE_PD, + address, prefix_len)); + data_source.add(new_host); +} + + +void +HostMgrTest::testGetAll(BaseHostDataSource& data_source1, + BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll(hwaddrs_[0]); ASSERT_TRUE(hosts.empty()); // Add two reservations for the same HW address. They differ by the IP // address reserved and the IPv4 subnet. - getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false), - "hw-address", SubnetID(1), SubnetID(0), - IOAddress("192.0.2.5")))); - getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false), - "hw-address", SubnetID(10), SubnetID(0), - IOAddress("192.0.3.10")))); + addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); + addHost4(data_source2, hwaddrs_[0], SubnetID(10), IOAddress("192.0.3.10")); + CfgMgr::instance().commit(); // If there non-matching HW address is specified, nothing should be @@ -136,24 +247,18 @@ TEST_F(HostMgrTest, getAll) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10" " not found using getAll method"; } - } -// This test verifies that it is possible to gather all reservations for the -// specified IPv4 address from the HostMgr. The reservations are specified in -// the server's configuration. -TEST_F(HostMgrTest, getAll4) { +void +HostMgrTest::testGetAll4(BaseHostDataSource& data_source1, + BaseHostDataSource& data_source2) { ConstHostCollection hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")); ASSERT_TRUE(hosts.empty()); - getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false), - "hw-address", SubnetID(1), SubnetID(0), - IOAddress("192.0.2.5")))); + addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); + addHost4(data_source2, hwaddrs_[1], SubnetID(10), IOAddress("192.0.2.5")); - getCfgHosts()->add(HostPtr(new Host(hwaddrs_[1]->toText(false), - "hw-address", SubnetID(10), SubnetID(0), - IOAddress("192.0.2.5")))); CfgMgr::instance().commit(); hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")); @@ -167,17 +272,13 @@ TEST_F(HostMgrTest, getAll4) { EXPECT_NE(hosts[0]->getIPv4SubnetID(), hosts[1]->getIPv4SubnetID()); } -// This test verifies that it is possible to retrieve a reservation for the -// particular host using HostMgr. The reservation is specified in the server's -// configuration. -TEST_F(HostMgrTest, get4) { +void +HostMgrTest::testGet4(BaseHostDataSource& data_source) { ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), hwaddrs_[0]); ASSERT_FALSE(host); - getCfgHosts()->add(HostPtr(new Host(hwaddrs_[0]->toText(false), - "hw-address", - SubnetID(1), SubnetID(2), - IOAddress("192.0.2.5")))); + addHost4(data_source, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); + CfgMgr::instance().commit(); host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR, @@ -188,18 +289,13 @@ TEST_F(HostMgrTest, get4) { EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText()); } -// This test verifies that it is possible to retrieve IPv6 reservations for -// the particular host using HostMgr. The reservation is specified in the -// server's configuration. -TEST_F(HostMgrTest, get6) { +void +HostMgrTest::testGet6(BaseHostDataSource& data_source) { ConstHostPtr host = HostMgr::instance().get6(SubnetID(2), duids_[0]); ASSERT_FALSE(host); - HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1), - SubnetID(2), IOAddress("0.0.0.0"))); - new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, - IOAddress("2001:db8:1::1"))); - getCfgHosts()->add(new_host); + addHost6(data_source, duids_[0], SubnetID(2), IOAddress("2001:db8:1::1")); + CfgMgr::instance().commit(); host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID, @@ -210,25 +306,18 @@ TEST_F(HostMgrTest, get6) { IOAddress("2001:db8:1::1")))); } -// This test verifies that it is possible to retrieve the reservation of the -// particular IPv6 prefix using HostMgr. -TEST_F(HostMgrTest, get6ByPrefix) { +void +HostMgrTest::testGet6ByPrefix(BaseHostDataSource& data_source1, + BaseHostDataSource& data_source2) { ConstHostPtr host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64); ASSERT_FALSE(host); // Add a host with a reservation for a prefix 2001:db8:1::/64. - HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1), - SubnetID(2), IOAddress("0.0.0.0"))); - new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, - IOAddress("2001:db8:1::"), 64)); - getCfgHosts()->add(new_host); + addHost6(data_source1, duids_[0], SubnetID(2), IOAddress("2001:db8:1::"), 64); // Add another host having a reservation for prefix 2001:db8:1:0:6::/72. - new_host.reset(new Host(duids_[1]->toText(), "duid", SubnetID(2), - SubnetID(3), IOAddress::IPV4_ZERO_ADDRESS())); - new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, - IOAddress("2001:db8:1:0:6::"), 72)); - getCfgHosts()->add(new_host); + addHost6(data_source2, duids_[1], SubnetID(3), IOAddress("2001:db8:1:0:6::"), 72); + CfgMgr::instance().commit(); // Retrieve first reservation. @@ -254,4 +343,189 @@ TEST_F(HostMgrTest, get6ByPrefix) { EXPECT_FALSE(host); } +/// This test verifies that HostMgr returns all reservations for the +/// specified HW address. The reservations are defined in the server's +/// configuration. +TEST_F(HostMgrTest, getAll) { + testGetAll(*getCfgHosts(), *getCfgHosts()); +} + +// This test verifies that it is possible to gather all reservations for the +// specified IPv4 address from the HostMgr. The reservations are specified in +// the server's configuration. +TEST_F(HostMgrTest, getAll4) { + testGetAll4(*getCfgHosts(), *getCfgHosts()); +} + +// This test verifies that it is possible to retrieve a reservation for the +// particular host using HostMgr. The reservation is specified in the server's +// configuration. +TEST_F(HostMgrTest, get4) { + testGet4(*getCfgHosts()); +} + +// This test verifies that it is possible to retrieve IPv6 reservations for +// the particular host using HostMgr. The reservation is specified in the +// server's configuration. +TEST_F(HostMgrTest, get6) { + testGet6(*getCfgHosts()); +} + +// This test verifies that it is possible to retrieve the reservation of the +// particular IPv6 prefix using HostMgr. +TEST_F(HostMgrTest, get6ByPrefix) { + testGet6ByPrefix(*getCfgHosts(), *getCfgHosts()); +} + +// The following tests require MySQL enabled. +#if defined HAVE_MYSQL + +/// @brief Test fixture class for validating @c HostMgr using +/// MySQL as alternate host data source. +class MySQLHostMgrTest : public HostMgrTest { +protected: + + /// @brief Build MySQL schema for a test. + virtual void SetUp(); + + /// @brief Rollback and drop MySQL schema after the test. + virtual void TearDown(); +}; + +void +MySQLHostMgrTest::SetUp() { + HostMgrTest::SetUp(); + + // Ensure schema is the correct one. + destroyMySQLSchema(); + createMySQLSchema(); + + // Connect to the database + try { + HostMgr::create(validMySQLConnectionString()); + } catch (...) { + std::cerr << "*** ERROR: unable to open database. The test\n" + "*** environment is broken and must be fixed before\n" + "*** the MySQL tests will run correctly.\n" + "*** The reason for the problem is described in the\n" + "*** accompanying exception output.\n"; + throw; + } +} + +void +MySQLHostMgrTest::TearDown() { + HostDataSourceFactory::getHostDataSourcePtr()->rollback(); + HostDataSourceFactory::destroy(); + destroyMySQLSchema(); +} + +// This test verifies that reservations for a particular client can +// be retrieved from the confguration file and a database simultaneously. +TEST_F(MySQLHostMgrTest, getAll) { + testGetAll(*getCfgHosts(), HostMgr::instance()); +} + +// This test verifies that IPv4 reservations for a particular client can +// be retrieved from the configuration file and a database simulatneously. +TEST_F(MySQLHostMgrTest, getAll4) { + testGetAll4(*getCfgHosts(), HostMgr::instance()); +} + +// This test verifies that the IPv4 reservation can be retrieved from a +// database. +TEST_F(MySQLHostMgrTest, get4) { + testGet4(HostMgr::instance()); +} + +// This test verifies that the IPv6 reservation can be retrieved from a +// database. +TEST_F(MySQLHostMgrTest, get6) { + testGet6(HostMgr::instance()); +} + +// This test verifies that the IPv6 prefix reservation can be retrieved +// from a configuration file and a database. +TEST_F(MySQLHostMgrTest, get6ByPrefix) { + testGet6ByPrefix(*getCfgHosts(), HostMgr::instance()); +} + +#endif + + +// The following tests require PostgreSQL enabled. +#if defined HAVE_PGSQL + +/// @brief Test fixture class for validating @c HostMgr using +/// PostgreSQL as alternate host data source. +class PostgreSQLHostMgrTest : public HostMgrTest { +protected: + + /// @brief Prepares the class for a test. + virtual void SetUp(); + + virtual void TearDown(); + +}; + +void +PostgreSQLHostMgrTest::SetUp() { + HostMgrTest::SetUp(); + + // Ensure schema is the correct one. + destroyPgSQLSchema(); + createPgSQLSchema(); + + // Connect to the database + try { + HostMgr::create(validPgSQLConnectionString()); + } catch (...) { + std::cerr << "*** ERROR: unable to open database. The test\n" + "*** environment is broken and must be fixed before\n" + "*** the PostgreSQL tests will run correctly.\n" + "*** The reason for the problem is described in the\n" + "*** accompanying exception output.\n"; + throw; + } +} + +void +PostgreSQLHostMgrTest::TearDown() { + HostDataSourceFactory::getHostDataSourcePtr()->rollback(); + HostDataSourceFactory::destroy(); + destroyPgSQLSchema(); +} + +// This test verifies that reservations for a particular client can +// be retrieved from the confguration file and a database simultaneously. +TEST_F(PostgreSQLHostMgrTest, getAll) { + testGetAll(*getCfgHosts(), HostMgr::instance()); +} + +// This test verifies that IPv4 reservations for a particular client can +// be retrieved from the configuration file and a database simulatneously. +TEST_F(PostgreSQLHostMgrTest, getAll4) { + testGetAll4(*getCfgHosts(), HostMgr::instance()); +} + +// This test verifies that the IPv4 reservation can be retrieved from a +// database. +TEST_F(PostgreSQLHostMgrTest, get4) { + testGet4(HostMgr::instance()); +} + +// This test verifies that the IPv6 reservation can be retrieved from a +// database. +TEST_F(PostgreSQLHostMgrTest, get6) { + testGet6(HostMgr::instance()); +} + +// This test verifies that the IPv6 prefix reservation can be retrieved +// from a configuration file and a database. +TEST_F(PostgreSQLHostMgrTest, get6ByPrefix) { + testGet6ByPrefix(*getCfgHosts(), HostMgr::instance()); +} + +#endif + } // end of anonymous namespace