From 57b308ffd5dcdc23a5b4c246756720b547d1b63a Mon Sep 17 00:00:00 2001 From: Thomas Markwalder Date: Thu, 19 Mar 2015 14:19:55 -0400 Subject: [PATCH] [3689] Added new host test file Addressing more review comments... new file - host_unittest.cc contains Dhcp6Client based host reservation tests dhcp6_client.cc dhcp6_client.h added setDuid(str) method to allow duid to be set to specific value dhcp6_srv_unittest.cc - deleted host reservation tests, now in host_unittest.cc dhcp6_test_utils.cc dhcp6_test_utils.h deleted createHost6() method --- src/bin/dhcp6/tests/Makefile.am | 1 + src/bin/dhcp6/tests/dhcp6_client.cc | 6 + src/bin/dhcp6/tests/dhcp6_client.h | 10 ++ src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 115 ----------------- src/bin/dhcp6/tests/dhcp6_test_utils.cc | 34 ----- src/bin/dhcp6/tests/dhcp6_test_utils.h | 11 -- src/bin/dhcp6/tests/host_unittest.cc | 146 ++++++++++++++++++++++ 7 files changed, 163 insertions(+), 160 deletions(-) create mode 100644 src/bin/dhcp6/tests/host_unittest.cc diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index 063aa7c487..eca758b340 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/src/bin/dhcp6/tests/Makefile.am @@ -75,6 +75,7 @@ dhcp6_unittests_SOURCES = dhcp6_unittests.cc dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc dhcp6_unittests_SOURCES += fqdn_unittest.cc dhcp6_unittests_SOURCES += hooks_unittest.cc +dhcp6_unittests_SOURCES += host_unittest.cc dhcp6_unittests_SOURCES += dhcp6_test_utils.cc dhcp6_test_utils.h dhcp6_unittests_SOURCES += d2_unittest.cc d2_unittest.h dhcp6_unittests_SOURCES += marker_file.cc diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index 73720695a9..8f445ec882 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -425,6 +425,12 @@ Dhcp6Client::getLeasesByIAID(const uint32_t iaid) const { return (leases); } +void +Dhcp6Client::setDUID(const std::string& str) { + DUID d = DUID::fromText(str); + duid_.reset(new DUID(d)); +} + void Dhcp6Client::modifyDUID() { if (!duid_) { diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index bb63220647..319cc23461 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/src/bin/dhcp6/tests/dhcp6_client.h @@ -302,6 +302,16 @@ public: return (srv_); } + /// @brief Sets the client's DUID from a string value + /// + /// Replaces the client's DUID with one constructed from the given + /// string. The string is expected to hexadecimal digits with or + /// without ":" separators. + /// + /// The DUID modification affects the value returned by the + /// @c Dhcp6Client::getClientId + void setDUID(const std::string& duid_str); + /// @brief Modifies the client's DUID (adds one to it). /// /// The DUID should be modified to test negative scenarios when the client diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 34cb9ebd41..a600d41785 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -2094,121 +2094,6 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) { EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol)); } -// Verify that a host reservation is used and that the lease name is set to -// the reservation hostname. -TEST_F(Dhcpv6SrvTest, hostReservationWithHostName) { - // set duid_ for createHost6 - generateClientId(); - - // create host reservation - IOAddress res_address("2001:db8:1:1::babe"); - createHost6(true, IPv6Resrv::TYPE_NA, res_address, "alice"); - - // Let's create a REQUEST - Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234)); - req->setRemoteAddr(IOAddress("fe80::abcd")); - req->setIface("eth0"); - boost::shared_ptr ia = generateIA(D6O_IA_NA, 234, 1500, 3000); - - // with a valid hint - IOAddress hint("2001:db8:1:1::dead:beef"); - ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint)); - - OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500)); - ia->addOption(hint_opt); - req->addOption(ia); - - // Set client id to match duid_ - OptionPtr clientid = generateClientId(); - req->addOption(clientid); - - // server-id is mandatory in REQUEST - req->addOption(srv_.getServerID()); - - // Pass it to the server and hope for a REPLY - Pkt6Ptr reply = srv_.processRequest(req); - - // check if we get response at all - checkResponse(reply, DHCPV6_REPLY, 1234); - - OptionPtr tmp = reply->getOption(D6O_IA_NA); - ASSERT_TRUE(tmp); - - // check that IA_NA was returned and that there's an address included - boost::shared_ptr addr = checkIA_NA(reply, 234, - subnet_->getT1(), - subnet_->getT2()); - ASSERT_TRUE(addr); - - // check that we've got the address we requested - checkIAAddr(addr, res_address, Lease::TYPE_NA); - - // check that the lease is really in the database - Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr); - ASSERT_TRUE(l); - - // Verify that lease hostname matches the reservation name - EXPECT_EQ("alice", l->hostname_); -} - -// Verify that a host reservation is used and that the lease name is blank -// when the reservation hostname is blank. -TEST_F(Dhcpv6SrvTest, hostReservationWithoutHostName) { - // set duid_ for createHost6 - generateClientId(); - - // create host reservation - IOAddress res_address("2001:db8:1:1::babe"); - createHost6(true, IPv6Resrv::TYPE_NA, res_address, ""); - - // Let's create a REQUEST - Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234)); - req->setRemoteAddr(IOAddress("fe80::abcd")); - req->setIface("eth0"); - boost::shared_ptr ia = generateIA(D6O_IA_NA, 234, 1500, 3000); - - // with a valid hint - IOAddress hint("2001:db8:1:1::dead:beef"); - ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint)); - - OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500)); - ia->addOption(hint_opt); - req->addOption(ia); - - // Set client id to match duid_ - OptionPtr clientid = generateClientId(); - req->addOption(clientid); - - // server-id is mandatory in REQUEST - req->addOption(srv_.getServerID()); - - // Pass it to the server and hope for a REPLY - Pkt6Ptr reply = srv_.processRequest(req); - - // check if we get response at all - checkResponse(reply, DHCPV6_REPLY, 1234); - - OptionPtr tmp = reply->getOption(D6O_IA_NA); - ASSERT_TRUE(tmp); - - // check that IA_NA was returned and that there's an address included - boost::shared_ptr addr = checkIA_NA(reply, 234, - subnet_->getT1(), - subnet_->getT2()); - ASSERT_TRUE(addr); - - // check that we've got the address we requested - checkIAAddr(addr, res_address, Lease::TYPE_NA); - - // check that the lease is really in the database - Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr); - ASSERT_TRUE(l); - - // Verify that lease hostname matches the reservation name - EXPECT_EQ("", l->hostname_); -} - - /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test /// to call processX() methods. diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.cc b/src/bin/dhcp6/tests/dhcp6_test_utils.cc index b225ff5359..98f043a76f 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.cc +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.cc @@ -77,40 +77,6 @@ Dhcpv6SrvTest::checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid, return (addr); } -/// @brief Utility function that creates a host reservation (duid) -/// -/// @param add_to_host_mgr true if the reservation should be added -/// @param type specifies reservation type (NA or PD) -/// @param addr specifies reserved address -/// @param hostname specifies hostname to be used in reservation -/// @return created Host object. -HostPtr -Dhcpv6SrvTest::createHost6(bool add_to_host_mgr, IPv6Resrv::Type type, - const asiolink::IOAddress& addr, const std::string& hostname) { - HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(), - Host::IDENT_DUID, SubnetID(0), subnet_->getID(), - asiolink::IOAddress("0.0.0.0"), hostname)); - - // Prefix length doesn't matter here, let's assume address is /128 and - // prefix is /64 - IPv6Resrv resv(type, addr, type == IPv6Resrv::TYPE_NA? 128 : 64); - host->addReservation(resv); - - if (add_to_host_mgr) { - - // Let's add the host. - CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); - - // We also need to add existing subnet - CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_); - - // Commit this configuration. - CfgMgr::instance().commit(); - } - - return (host); -} - boost::shared_ptr Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid, uint32_t expected_t1, uint32_t expected_t2) { diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index 4fc4753fc4..4896d5dde1 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -345,17 +345,6 @@ public: /// @param srv Server to be configured. void configure(const std::string& config, NakedDhcpv6Srv& srv); - /// @brief Utility function that creates a host reservation (duid) - /// - /// @param add_to_host_mgr true if the reservation should be added - /// @param type specifies reservation type (NA or PD) - /// @param addr specifies reserved address - /// @param hostname specifies hostname to be used in reservation - /// @return created Host object. - isc::dhcp::HostPtr - createHost6(bool add_to_host_mgr, isc::dhcp::IPv6Resrv::Type type, - const asiolink::IOAddress& addr, const std::string& hostname); - /// @brief Checks that server response (ADVERTISE or REPLY) contains proper /// IA_NA option /// diff --git a/src/bin/dhcp6/tests/host_unittest.cc b/src/bin/dhcp6/tests/host_unittest.cc new file mode 100644 index 0000000000..341c7f594a --- /dev/null +++ b/src/bin/dhcp6/tests/host_unittest.cc @@ -0,0 +1,146 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::dhcp::test; +using namespace isc::test; + +namespace { + +/// @brief Set of JSON configurations used by the Host reservation unit tests. +/// +/// - Configuration 0: +/// Single subnet with two reservations, one with a hostname, one without +const char* CONFIGS[] = { + // Configuration 0: + "{ " + "\"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"valid-lifetime\": 4000, " + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ " + " { " + " \"subnet\": \"2001:db8:1::/48\", " + " \"pools\": [ { \"pool\": \"2001:db8:1:1::/64\" } ]," + " \"interface\" : \"eth0\" , " + " \"reservations\": [" + " {" + " \"duid\": \"01:02:03:04\"," + " \"ip-addresses\": [ \"2001:db8:1:1::babe\" ]," + " \"hostname\": \"alice\"" + " }," + " {" + " \"duid\": \"01:02:03:05\"," + " \"ip-addresses\": [ \"2001:db8:1:1::babf\" ]" + " } ]" + " } ]" + "}" +}; + +/// @brief Test fixture class for testing host reservations +class HostTest : public Dhcpv6SrvTest { +public: + /// @brief Constructor. + /// + /// Sets up fake interfaces. + HostTest() + : Dhcpv6SrvTest(), + iface_mgr_test_config_(true) { + } + + /// @brief Interface Manager's fake configuration control. + IfaceMgrTestConfig iface_mgr_test_config_; +}; + +TEST_F(HostTest, basicSARRs) { + Dhcp6Client client; + configure(CONFIGS[0], *client.getServer()); + + // Make sure we ended-up having expected number of subnets configured. + const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()-> + getCfgSubnets6()->getAll(); + ASSERT_EQ(1, subnets->size()); + + // Configure client to request IA_NA and aAppend IA_NA option + // to the client's message. + client.setDUID("01:02:03:04"); + client.useNA(); + ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:1:1::dead:beef")); + + // Perform 4-way exchange. + ASSERT_NO_THROW(client.doSARR()); + + // Verify that the client we got the reserved address + ASSERT_EQ(1, client.getLeaseNum()); + Lease6 lease_client = client.getLease(0); + EXPECT_EQ("2001:db8:1:1::babe", lease_client.addr_.toText()); + + // Check that the server recorded the lease. + // and lease has reserved hostname + Lease6Ptr lease_server = checkLease(lease_client); + ASSERT_TRUE(lease_server); + EXPECT_EQ("alice", lease_server->hostname_); + + // Now redo the client, adding one to the DUID + client.clearConfig(); + client.modifyDUID(); + client.useNA(); + ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:1:1::dead:beef")); + + // Perform 4-way exchange. + ASSERT_NO_THROW(client.doSARR()); + + // Verify that the client we got the reserved address + ASSERT_EQ(1, client.getLeaseNum()); + lease_client = client.getLease(0); + EXPECT_EQ("2001:db8:1:1::babf", lease_client.addr_.toText()); + + // Check that the server recorded the lease. + // and that the server lease has NO hostname + lease_server = checkLease(lease_client); + ASSERT_TRUE(lease_server); + EXPECT_EQ("", lease_server->hostname_); + + // Now redo the client with yet another DUID and verify that + // we get a dynamic address. + client.clearConfig(); + client.modifyDUID(); + client.useNA(); + ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:1:1::dead:beef")); + + // Perform 4-way exchange. + ASSERT_NO_THROW(client.doSARR()); + + // Verify that the client got a dynamic address + ASSERT_EQ(1, client.getLeaseNum()); + lease_client = client.getLease(0); + EXPECT_EQ("2001:db8:1:1::", lease_client.addr_.toText()); + + // Check that the server recorded the lease. + // and that the server lease has NO hostname + lease_server = checkLease(lease_client); + ASSERT_TRUE(lease_server); + EXPECT_EQ("", lease_server->hostname_); +} + +} // end of anonymous namespace -- 2.47.2