From: Marcin Siodelski Date: Mon, 27 Oct 2014 19:08:22 +0000 (+0100) Subject: [3562] Added more tests for HostReservationParser class. X-Git-Tag: kea-eng-20141219~28^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7d63012c02b957c59ffb0dba92b421d3a2ab8119;p=thirdparty%2Fkea.git [3562] Added more tests for HostReservationParser class. --- diff --git a/src/lib/dhcpsrv/host.cc b/src/lib/dhcpsrv/host.cc index b613d80cc8..7fff0d6cfa 100644 --- a/src/lib/dhcpsrv/host.cc +++ b/src/lib/dhcpsrv/host.cc @@ -30,7 +30,7 @@ void IPv6Resrv::set(const asiolink::IOAddress& prefix, const uint8_t prefix_len) { if (!prefix.isV6() || prefix.isV6Multicast()) { isc_throw(isc::BadValue, "invalid prefix '" << prefix - << " for new IPv6 reservation"); + << "' for new IPv6 reservation"); } else if (prefix_len > 128) { isc_throw(isc::BadValue, "invalid prefix length '" @@ -61,12 +61,16 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len, const std::string& dhcp4_client_classes, const std::string& dhcp6_client_classes) : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id), - ipv6_subnet_id_(ipv6_subnet_id), ipv4_reservation_(ipv4_reservation), + ipv6_subnet_id_(ipv6_subnet_id), + ipv4_reservation_(asiolink::IOAddress("0.0.0.0")), hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes), dhcp6_client_classes_(dhcp6_client_classes) { // Initialize HWAddr or DUID setIdentifier(identifier, identifier_len, identifier_type); + + // Validate and set IPv4 address reservation. + setIPv4Reservation(ipv4_reservation); } Host::Host(const std::string& identifier, const std::string& identifier_name, @@ -76,12 +80,16 @@ Host::Host(const std::string& identifier, const std::string& identifier_name, const std::string& dhcp4_client_classes, const std::string& dhcp6_client_classes) : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id), - ipv6_subnet_id_(ipv6_subnet_id), ipv4_reservation_(ipv4_reservation), + ipv6_subnet_id_(ipv6_subnet_id), + ipv4_reservation_(asiolink::IOAddress("0.0.0.0")), hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes), dhcp6_client_classes_(dhcp6_client_classes) { // Initialize HWAddr or DUID setIdentifier(identifier, identifier_name); + + // Validate and set IPv4 address reservation. + setIPv4Reservation(ipv4_reservation); } const std::vector& @@ -138,6 +146,16 @@ Host::setIdentifier(const std::string& identifier, const std::string& name) { } } +void +Host::setIPv4Reservation(const asiolink::IOAddress& address) { + if (!address.isV4()) { + isc_throw(isc::BadValue, "address '" << address << "' is not a valid" + " IPv4 address"); + } + ipv4_reservation_ = address; +} + + void Host::addReservation(const IPv6Resrv& reservation) { ipv6_reservations_.insert(IPv6ResrvTuple(reservation.getType(), diff --git a/src/lib/dhcpsrv/host.h b/src/lib/dhcpsrv/host.h index d4cfb23b7f..ee6bb75427 100644 --- a/src/lib/dhcpsrv/host.h +++ b/src/lib/dhcpsrv/host.h @@ -316,9 +316,9 @@ public: /// The new reservation removes a previous reservation. /// /// @param address Address to be reserved for the client. - void setIPv4Reservation(const asiolink::IOAddress& address) { - ipv4_reservation_ = address; - } + /// + /// @throw isc::BadValue if the provided address is not an IPv4 address. + void setIPv4Reservation(const asiolink::IOAddress& address); /// @brief Returns reserved IPv4 address. /// diff --git a/src/lib/dhcpsrv/host_reservation_parser.cc b/src/lib/dhcpsrv/host_reservation_parser.cc index 26149e6188..64d94145a1 100644 --- a/src/lib/dhcpsrv/host_reservation_parser.cc +++ b/src/lib/dhcpsrv/host_reservation_parser.cc @@ -101,7 +101,8 @@ HostReservationParser4::build(isc::data::ConstElementPtr reservation_data) { BOOST_FOREACH(ConfigPair element, reservation_data->mapValue()) { try { if (element.first == "ip-address") { - host_->setIPv4Reservation(IOAddress(element.second->stringValue())); + host_->setIPv4Reservation(IOAddress(element.second-> + stringValue())); } } catch (const std::exception& ex) { diff --git a/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc b/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc index 4625896062..ee06a5a31b 100644 --- a/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc @@ -241,15 +241,21 @@ TEST_F(CfgHostsTest, get6) { // Add hosts. for (int i = 0; i < 25; ++i) { // Add host identified by HW address. - cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false), - "hw-address", - SubnetID(10), SubnetID(1 + i % 2), - increase(IOAddress("2001:db8:1::1"), i)))); + HostPtr host = HostPtr(new Host(hwaddrs_[i]->toText(false), + "hw-address", + SubnetID(10), SubnetID(1 + i % 2), + IOAddress("0.0.0.0"))); + host->addReservation(IPv6Resrv(increase(IOAddress("2001:db8:1::1"), + i))); + cfg.add(host); // Add host identified by DUID. - cfg.add(HostPtr(new Host(duids_[i]->toText(), "duid", - SubnetID(10), SubnetID(1 + i % 2), - increase(IOAddress("2001:db8:2::1"), i)))); + host = HostPtr(new Host(duids_[i]->toText(), "duid", + SubnetID(10), SubnetID(1 + i % 2), + IOAddress("0.0.0.0"))); + host->addReservation(IPv6Resrv(increase(IOAddress("2001:db8:2::1"), + i))); + cfg.add(host); } for (int i = 0; i < 25; ++i) { @@ -260,8 +266,11 @@ TEST_F(CfgHostsTest, get6) { hwaddrs_[i]); ASSERT_TRUE(host); EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID()); + IPv6ResrvRange reservations = + host->getIPv6Reservations(IPv6Resrv::TYPE_NA); + ASSERT_EQ(1, std::distance(reservations.first, reservations.second)); EXPECT_EQ(increase(IOAddress("2001:db8:1::1"), i), - host->getIPv4Reservation()); + reservations.first->second.getPrefix()); // Retrieve host by DUID. The HW address is non-null but there is no // reservation made for the HW address so the reservation is returned @@ -269,8 +278,10 @@ TEST_F(CfgHostsTest, get6) { host = cfg.get6(SubnetID(1 + i % 2), duids_[i], hwaddrs_[i + 25]); ASSERT_TRUE(host); EXPECT_EQ(1 + i % 2, host->getIPv6SubnetID()); + reservations = host->getIPv6Reservations(IPv6Resrv::TYPE_NA); + ASSERT_EQ(1, std::distance(reservations.first, reservations.second)); EXPECT_EQ(increase(IOAddress("2001:db8:2::1"), i), - host->getIPv4Reservation()); + reservations.first->second.getPrefix()); } // Also check that when the get6 finds multiple Host objects that fulfil diff --git a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc index 907e959583..b06889bc2c 100644 --- a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc @@ -62,6 +62,9 @@ protected: return (false); } + void + expectFailure(const HostReservationParser& parser, + const std::string& config) const; /// @brief HW Address object used by tests. HWAddrPtr hwaddr_; @@ -138,6 +141,43 @@ TEST_F(HostReservationParserTest, dhcp4DUID) { EXPECT_TRUE(hosts[0]->getHostname().empty()); } +// This test verifies that the configuration parser for host reservations +// throws an exception when IPv6 address is specified for IPv4 address +// reservation. +TEST_F(HostReservationParserTest, dhcp4IPv6Address) { + std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\"," + "\"ip-address\": \"2001:db8:1::1\" }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser4 parser(SubnetID(10)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser for host reservations +// throws an exception when no HW address nor DUID is specified. +TEST_F(HostReservationParserTest, noIdentifier) { + std::string config = "{ \"ip-address\": \"192.0.2.112\"," + "\"hostname\": \"\" }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser4 parser(SubnetID(10)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser for host reservations +// throws an exception when invalid IP address is specified. +TEST_F(HostReservationParserTest, malformedAddress) { + std::string config = "{ \"hw-address\": \"01:02:03:04:05:06\"," + "\"ip-address\": \"192.0.2.bogus\" }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser4 parser(SubnetID(10)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + // This test verfies that the parser can parse the IPv6 reservation entry for // which hw-address is a host identifier. TEST_F(HostReservationParserTest, dhcp6HWaddr) { @@ -218,5 +258,18 @@ TEST_F(HostReservationParserTest, dhcp6DUID) { ASSERT_EQ(0, std::distance(prefixes.first, prefixes.second)); } +// This test verifies that the configuration parser throws an exception +// when IPv4 address is specified for IPv6 reservation. +TEST_F(HostReservationParserTest, dhcp6IPv4Address) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"ip-addresses\": [ \"192.0.2.3\", \"2001:db8:1::200\" ]," + "\"prefixes\": [ ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/tests/host_unittest.cc b/src/lib/dhcpsrv/tests/host_unittest.cc index 90cc1f834d..0849210895 100644 --- a/src/lib/dhcpsrv/tests/host_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_unittest.cc @@ -380,6 +380,10 @@ TEST(HostTest, setValues) { EXPECT_EQ(234, host->getIPv6SubnetID()); EXPECT_EQ("10.0.0.1", host->getIPv4Reservation().toText()); EXPECT_EQ("other-host.example.org", host->getHostname()); + + // An IPv6 address can't be used for IPv4 reservations. + EXPECT_THROW(host->setIPv4Reservation(IOAddress("2001:db8:1::1")), + isc::BadValue); } // Test that Host constructors initialize client classes from string.