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
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
return (leases);
}
+void
+Dhcp6Client::setDUID(const std::string& str) {
+ DUID d = DUID::fromText(str);
+ duid_.reset(new DUID(d));
+}
+
void
Dhcp6Client::modifyDUID() {
if (!duid_) {
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
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<Option6IA> 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<Option6IAAddr> 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<Option6IA> 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<Option6IAAddr> 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.
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<Option6IAPrefix>
Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid,
uint32_t expected_t1, uint32_t expected_t2) {
/// @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
///
--- /dev/null
+// 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 <config.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <dhcp6/tests/dhcp6_client.h>
+
+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