From: Andrei Pavel Date: Wed, 5 Apr 2023 11:39:28 +0000 (+0300) Subject: [#549] add tests for reservation-update X-Git-Tag: Kea-2.3.7~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc07e69d0c9b23c3c794e432cdcbe09af8dfe98f;p=thirdparty%2Fkea.git [#549] add tests for reservation-update --- diff --git a/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc b/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc index a4cb460892..b79790ec7e 100644 --- a/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc @@ -5,6 +5,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include + #include #include #include @@ -12,7 +13,10 @@ #include #include #include +#include + #include + #include #include @@ -1200,5 +1204,69 @@ TEST_F(CfgHostsTest, duplicatesSubnet6DUID) { "foo.example.com")))); } +// Checks that updates work correctly. +TEST_F(CfgHostsTest, update) { + CfgHosts cfg; + + HostPtr const host(boost::make_shared(duids_[0]->toText(), "duid", SUBNET_ID_UNUSED, + SubnetID(1), IOAddress("0.0.0.0"), + "foo.example.com")); + + // Updating any host currently throws because it relies on delete being + // implemented which is not. + EXPECT_THROW_MSG(cfg.update(host), NotImplemented, "sorry, not implemented"); + + // Temporary return. Remove it and the preceding EXPECT_THROW_MSG when delete gets implemented. + return; + + // Updating a host that doesn't exist should throw. + EXPECT_THROW_MSG(cfg.update(host), HostNotFound, "Host not updated (not found)."); + + // There should be no hosts. + HostCollection hosts(cfg.getAll6(SubnetID(1))); + EXPECT_EQ(0, hosts.size()); + + // Add a host. + EXPECT_NO_THROW(cfg.add(host)); + + // The host should be in the config. + hosts = cfg.getAll6(SubnetID(1)); + ASSERT_EQ(1, hosts.size()); + EXPECT_EQ("duid=010203040500 ipv6_subnet_id=1 hostname=foo.example.com " + "ipv4_reservation=(no) siaddr=(no) sname=(empty) file=(empty) " + "key=(empty) ipv6_reservations=(none)", hosts[0]->toText()); + + // Update the host. Change nothing. + EXPECT_NO_THROW(cfg.update(host)); + + // The same host should be in the config. + hosts = cfg.getAll6(SubnetID(1)); + ASSERT_EQ(1, hosts.size()); + EXPECT_EQ("duid=010203040500 ipv6_subnet_id=1 hostname=foo.example.com " + "ipv4_reservation=(no) siaddr=(no) sname=(empty) file=(empty) " + "key=(empty) ipv6_reservations=(none)", hosts[0]->toText()); + + // Update the host with new hostname. + host->setHostname("bar.example.com"); + EXPECT_NO_THROW(cfg.update(host)); + + // The change should be reflected in the config. + hosts = cfg.getAll6(SubnetID(1)); + ASSERT_EQ(1, hosts.size()); + EXPECT_EQ("duid=010203040500 ipv6_subnet_id=1 hostname=bar.example.com " + "ipv4_reservation=(no) siaddr=(no) sname=(empty) file=(empty) " + "key=(empty) ipv6_reservations=(none)", hosts[0]->toText()); + + // Remove hostname from host. + host->setHostname(""); + EXPECT_NO_THROW(cfg.update(host)); + + // The change should be reflected in the config. + hosts = cfg.getAll6(SubnetID(1)); + ASSERT_EQ(1, hosts.size()); + EXPECT_EQ("duid=010203040500 ipv6_subnet_id=1 hostname=(empty) " + "ipv4_reservation=(no) siaddr=(no) sname=(empty) file=(empty) " + "key=(empty) ipv6_reservations=(none)", hosts[0]->toText()); +} -} // end of anonymous namespace +} // namespace diff --git a/src/lib/dhcpsrv/tests/host_cache_unittest.cc b/src/lib/dhcpsrv/tests/host_cache_unittest.cc index c6ad920098..516c0f4e99 100644 --- a/src/lib/dhcpsrv/tests/host_cache_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_cache_unittest.cc @@ -698,6 +698,9 @@ public: return (false); } + void update(HostPtr const&) { + } + std::string getType() const { return ("one"); } diff --git a/src/lib/dhcpsrv/tests/host_mgr_unittest.cc b/src/lib/dhcpsrv/tests/host_mgr_unittest.cc index 5b19af0bb1..a1b3647fd2 100644 --- a/src/lib/dhcpsrv/tests/host_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_mgr_unittest.cc @@ -5,6 +5,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include + #include #include #include @@ -12,8 +13,10 @@ #include #include #include +#include #include + #include using namespace isc; @@ -21,7 +24,6 @@ using namespace isc::db; using namespace isc::dhcp; using namespace isc::dhcp::test; using namespace isc::asiolink; - namespace { // The tests in this file only address the in memory hosts. @@ -152,7 +154,7 @@ TEST_F(HostMgrTest, get6ByPrefix) { } // This test verifies that without a host data source an exception is thrown. -TEST_F(HostMgrTest, addNoDataSource) { +TEST_F(HostMgrTest, noDataSource) { // Remove all configuration. CfgMgr::instance().clear(); // Recreate HostMgr instance. @@ -160,7 +162,11 @@ TEST_F(HostMgrTest, addNoDataSource) { HostPtr host(new Host(hwaddrs_[0]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.5"))); - EXPECT_THROW(HostMgr::instance().add(host), NoHostDataSourceManager); + EXPECT_THROW_MSG(HostMgr::instance().add(host), NoHostDataSourceManager, + "Unable to add new host because there is no hosts-database configured."); + EXPECT_THROW_MSG(HostMgr::instance().update(host), NoHostDataSourceManager, + "Unable to update existing host because there is no hosts-database " + "configured."); } } // namespace diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index 73f602a587..ab4924a554 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2023 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -1467,6 +1467,17 @@ TEST_F(MySqlHostDataSourceTest, testMultipleHosts6MultiThreading) { testMultipleHosts6(); } +/// @brief Tests that hosts can be updated. +TEST_F(MySqlHostDataSourceTest, update) { + testUpdate(); +} + +/// @brief Tests that hosts can be updated. +TEST_F(MySqlHostDataSourceTest, updateMultiThreading) { + MultiThreadingTest mt(true); + testUpdate(); +} + /// @brief Test fixture class for validating @c HostMgr using /// MySQL as alternate host data source. class MySQLHostMgrTest : public HostMgrTest { diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index 2c707f2105..cedcfcd5ba 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2022 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2023 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -1435,6 +1435,16 @@ TEST_F(PgSqlHostDataSourceTest, testMultipleHosts6MultiThreading) { testMultipleHosts6(); } +/// @brief Tests that hosts can be updated. +TEST_F(PgSqlHostDataSourceTest, update) { + testUpdate(); +} + +/// @brief Tests that hosts can be updated. +TEST_F(PgSqlHostDataSourceTest, updateMultiThreading) { + MultiThreadingTest mt(true); + testUpdate(); +} /// @brief Test fixture class for validating @c HostMgr using /// PostgreSQL as alternate host data source. class PgSQLHostMgrTest : public HostMgrTest { diff --git a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc index ed553ae651..0c1fa3de32 100644 --- a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc @@ -20,17 +20,16 @@ #include #include #include +#include #include -#include +#include +#include + #include -#include -#include -#include #include #include -#include using namespace std; using namespace isc::asiolink; @@ -3892,6 +3891,81 @@ HostMgrTest::testGetAll6BySubnetIP(BaseHostDataSource& data_source1, IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } +void +GenericHostDataSourceTest::testUpdate() { + // Make sure the host data source is initialized. + ASSERT_TRUE(hdsptr_); + + // Create a host with an IPv4 address reservation. + HostPtr const host(HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_HWADDR)); + SubnetID const v4_subnet(host->getIPv4SubnetID()); + SubnetID const v6_subnet(host->getIPv6SubnetID()); + string hwaddr(host->getHWAddress()->toText(false)); + boost::replace_all(hwaddr, ":", ""); + boost::to_upper(hwaddr); + + // Updating a host that doesn't exist should throw. + EXPECT_THROW_MSG(hdsptr_->update(host), NoRowsAffected, "Host not updated (not found)."); + + // There should be no hosts. + ConstHostCollection hosts(hdsptr_->getAll4(v4_subnet)); + EXPECT_EQ(0, hosts.size()); + + // Add the host. + EXPECT_NO_THROW(hdsptr_->add(host)); + + // The host should be there. + hosts = hdsptr_->getAll4(v4_subnet); + EXPECT_EQ(1, hosts.size()); + EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + + " ipv6_subnet_id=" + to_string(v6_subnet) + + " hostname=(empty) " + "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " + "ipv6_reservations=(none)", + hosts[0]->toText()); + + // Update the host. Change nothing. + EXPECT_NO_THROW(hdsptr_->update(host)); + + // The same host should be in the data source. + hosts = hdsptr_->getAll4(v4_subnet); + EXPECT_EQ(1, hosts.size()); + EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + + " ipv6_subnet_id=" + to_string(v6_subnet) + + " hostname=(empty) " + "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " + "ipv6_reservations=(none)", + hosts[0]->toText()); + + // Update the host with new hostname. + host->setHostname("foo.example.com"); + EXPECT_NO_THROW(hdsptr_->update(host)); + + // The change should be reflected in the data source. + hosts = hdsptr_->getAll4(v4_subnet); + EXPECT_EQ(1, hosts.size()); + EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + + " ipv6_subnet_id=" + to_string(v6_subnet) + + " hostname=foo.example.com " + "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " + "ipv6_reservations=(none)", + hosts[0]->toText()); + + // Remove hostname from host. + host->setHostname(""); + EXPECT_NO_THROW(hdsptr_->update(host)); + + // The change should be reflected in the data source. + hosts = hdsptr_->getAll4(v4_subnet); + EXPECT_EQ(1, hosts.size()); + EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + + " ipv6_subnet_id=" + to_string(v6_subnet) + + " hostname=(empty) " + "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " + "ipv6_reservations=(none)", + hosts[0]->toText()); +} + } // namespace test } // namespace dhcp } // namespace isc diff --git a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h index 0eb1ddfe0c..c884776b83 100644 --- a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h +++ b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2023 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -513,6 +513,11 @@ public: /// Uses gtest macros to report failures. void testMultipleHosts6(); + /// @brief Tests that hosts can be updated. + /// + /// Uses gtest macros to report failures. + void testUpdate(); + /// @brief Returns DUID with identical content as specified HW address /// /// This method does not have any sense in real life and is only useful diff --git a/src/lib/dhcpsrv/testutils/memory_host_data_source.cc b/src/lib/dhcpsrv/testutils/memory_host_data_source.cc index 3ea2b830c5..89b6e2bf26 100644 --- a/src/lib/dhcpsrv/testutils/memory_host_data_source.cc +++ b/src/lib/dhcpsrv/testutils/memory_host_data_source.cc @@ -375,6 +375,17 @@ MemHostDataSource::del6(const SubnetID& subnet_id, return (false); } +void +MemHostDataSource::update(HostPtr const& host) { + for (auto h = store_.begin(); h != store_.end(); ++h) { + if ((*h)->getHostId() == host->getHostId()) { + store_.erase(h); + break; + } + } + store_.push_back(host); +} + size_t MemHostDataSource::size() const { return (store_.size()); diff --git a/src/lib/dhcpsrv/testutils/memory_host_data_source.h b/src/lib/dhcpsrv/testutils/memory_host_data_source.h index 799ab08ea2..bf8f6a35e6 100644 --- a/src/lib/dhcpsrv/testutils/memory_host_data_source.h +++ b/src/lib/dhcpsrv/testutils/memory_host_data_source.h @@ -257,6 +257,9 @@ public: const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, const size_t identifier_len); + /// @brief Implements @ref BaseHostDataSource::update() for memory hosts. + void update(HostPtr const& host); + /// @brief Return backend type /// /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)