Browse Source

[2949] Severl unit-tests for inf-request implemented.

Tomek Mrugalski 10 years ago
parent
commit
4ed28a79d7

+ 2 - 1
src/bin/dhcp6/tests/Makefile.am

@@ -25,7 +25,7 @@ AM_CPPFLAGS += -DTOP_BUILDDIR="\"$(top_builddir)\""
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 
-CLEANFILES  = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
+CLEANFILES  = $(builddir)/logger_lockfile
 CLEANFILES += $(builddir)/load_marker.txt $(builddir)/unload_marker.txt
 CLEANFILES += *.json *.log
 
@@ -84,6 +84,7 @@ dhcp6_unittests_SOURCES += rebind_unittest.cc
 dhcp6_unittests_SOURCES += sarr_unittest.cc
 dhcp6_unittests_SOURCES += config_parser_unittest.cc
 dhcp6_unittests_SOURCES += confirm_unittest.cc
+dhcp6_unittests_SOURCES += infrequest_unittest.cc
 dhcp6_unittests_SOURCES += dhcp6_message_test.cc dhcp6_message_test.h
 
 if CONFIG_BACKEND_BUNDY

+ 42 - 3
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-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
@@ -16,6 +16,7 @@
 #include <dhcp/option_custom.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
+#include <dhcp/option_int_array.h>
 #include <dhcp/pkt6.h>
 #include <dhcpsrv/lease.h>
 #include <dhcp6/tests/dhcp6_client.h>
@@ -40,6 +41,8 @@ Dhcp6Client::Dhcp6Client() :
     use_na_(false),
     use_pd_(false),
     use_relay_(false),
+    send_oro_(false),
+    send_client_id_(true),
     prefix_hint_() {
 }
 
@@ -52,7 +55,10 @@ Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
     srv_(srv),
     use_na_(false),
     use_pd_(false),
-    use_relay_(false) {
+    use_relay_(false),
+    send_oro_(false),
+    send_client_id_(true),
+    prefix_hint_() {
 }
 
 void
@@ -245,7 +251,17 @@ Dhcp6Client::createLease(const Lease6& lease) {
 Pkt6Ptr
 Dhcp6Client::createMsg(const uint8_t msg_type) {
     Pkt6Ptr msg(new Pkt6(msg_type, curr_transid_++));
-    msg->addOption(getClientId());
+
+    if (send_client_id_) {
+        msg->addOption(getClientId());
+    }
+    if (send_oro_) {
+        OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
+        oro->setValues(oro_);
+
+        msg->addOption(oro);
+    };
+
     return (msg);
 }
 
@@ -296,6 +312,29 @@ Dhcp6Client::doRequest() {
 }
 
 void
+Dhcp6Client::doInfRequest() {
+    context_.query_ = createMsg(DHCPV6_INFORMATION_REQUEST);
+
+    // Not allowed in INF-REQUEST, but hey! Let's test it.
+    if (use_na_) {
+        context_.query_->addOption(Option6IAPtr(new Option6IA(D6O_IA_NA,
+                                                              1234)));
+    }
+
+    // IA-PD is also not allowed. So it may be useful in testing, too.
+    if (use_pd_) {
+        Option6IAPtr ia(new Option6IA(D6O_IA_PD, 5678));
+        if (prefix_hint_) {
+            ia->addOption(prefix_hint_);
+        }
+        context_.query_->addOption(ia);
+    }
+
+    sendMsg(context_.query_);
+    context_.response_ = receiveOneMsg();
+}
+
+void
 Dhcp6Client::doRebind() {
     Pkt6Ptr query = createMsg(DHCPV6_REBIND);
     copyIAsFromLeases(query);

+ 19 - 0
src/bin/dhcp6/tests/dhcp6_client.h

@@ -22,6 +22,7 @@
 #include <boost/noncopyable.hpp>
 #include <boost/shared_ptr.hpp>
 #include <set>
+#include <vector>
 
 namespace isc {
 namespace dhcp {
@@ -217,6 +218,12 @@ public:
     /// receiving server's response (if any).
     void doConfirm();
 
+
+    /// @brief Performs stateless (inf-request / reply) exchange.
+    ///
+    /// This function generates
+    void doInfRequest();
+
     /// @brief Removes the stateful configuration obtained from the server.
     ///
     /// It removes all leases held by the client.
@@ -365,6 +372,12 @@ public:
         relay_link_addr_ = link_addr;
     }
 
+    /// @brief Controls whether the client should send a client-id or not
+    /// @param send should the client-id be sent?
+    void sendClientId(bool send) {
+        send_client_id_ = send;
+    }
+
     /// @brief Lease configuration obtained by the client.
     Configuration config_;
 
@@ -470,8 +483,14 @@ private:
     bool use_pd_;    ///< Enable prefix delegation.
     bool use_relay_; ///< Enable relaying messages to the server.
 
+    bool send_oro_;
+    bool send_client_id_;
+
     /// @brief Pointer to the option holding a prefix hint.
     Option6IAPrefixPtr prefix_hint_;
+
+    // @brief List of options to be requested
+    std::vector<uint16_t> oro_;
 };
 
 } // end of namespace isc::dhcp::test

+ 0 - 5
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -186,15 +186,10 @@ TEST_F(NakedDhcpv6SrvTest, ReleaseNoSubnet) {
     checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
 }
 
-
 // Test verifies that the Dhcpv6_srv class can be instantiated. It checks a mode
 // without open sockets and with sockets opened on a high port (to not require
 // root privileges).
 TEST_F(Dhcpv6SrvTest, basic) {
-    // srv has stubbed interface detection. It will read
-    // interfaces.txt instead. It will pretend to have detected
-    // fe80::1234 link-local address on eth0 interface. Obviously
-    // an attempt to bind this socket will fail.
     boost::scoped_ptr<Dhcpv6Srv> srv;
 
     ASSERT_NO_THROW( {

+ 211 - 0
src/bin/dhcp6/tests/infrequest_unittest.cc

@@ -0,0 +1,211 @@
+// 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>
+#include <dhcp/option6_addrlst.h>
+#include <dhcp/option6_client_fqdn.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 Information-Request unit tests.
+///
+/// - Configuration 0:
+///   - one subnet used on eth0 interface
+///     - with address and prefix pools
+///     - dns-servers option
+/// - Configuation 1:
+///   - one subnet used on eth0 interface
+///     - no addresses or prefixes
+///     - domain-search option
+/// - Configuration 2:
+///   - one subnet used on eth0 interface
+///     - dns-servers option for subnet
+///   - sip-servers defined in global scope
+/// - Configuration 3:
+///   - nis-server, nis-domain specified in global scope
+///   - no subnets defined
+const char* CONFIGS[] = {
+    // Configuration 0
+    "{ \"interfaces\": [ \"*\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ],"
+        "    \"pd-pools\": ["
+        "        { \"prefix\": \"2001:db8:3::\", "
+        "          \"prefix-len\": 48, "
+        "          \"delegated-len\": 64"
+        "        } ],"
+        "    \"option-data\": [ {"
+        "        \"name\": \"dns-servers\","
+        "        \"data\": \"2001:db8::1, 2001:db8::2\""
+        "    } ],"
+        "    \"subnet\": \"2001:db8::/32\", "
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 }",
+    // Configuration 1
+    "{ \"interfaces\": [ \"*\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"option-data\": [ {"
+        "    \"name\": \"sip-server-addr\","
+        "    \"data\": \"2001:db8::abcd\""
+        "    } ],"
+        "    \"subnet\": \"2001:db8::/32\", "
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 }",
+    // Configuration 2
+    "{ \"interfaces\": [ \"*\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "    \"option-data\": [ {"
+        "        \"name\": \"sip-server-dns\","
+        "        \"data\": \"2001:db8::1\""
+        "    } ],"
+        "\"subnet6\": [ { "
+        "    \"subnet\": \"2001:db8::/32\", "
+        "    \"interface\": \"eth0\","
+        "    \"option-data\": [ {"
+        "        \"name\": \"dns-servers\","
+        "        \"data\": \"2001:db8::2\""
+        "    } ]"
+        " } ],"
+        "\"valid-lifetime\": 4000 }",
+    // Configuration 2
+    "{ \"interfaces\": [ \"*\" ],"
+        "\"option-data\": [ {"
+        "    \"name\": \"nis-servers\","
+        "    \"data\": \"2001:db8::1, 2001:db8::2\""
+        " } ],"
+        "\"subnet6\": [ ]"
+        "}"
+};
+
+/// @brief Test fixture class for testing 4-way exchange: Solicit-Advertise,
+/// Request-Reply.
+class InfRequestTest : public Dhcpv6SrvTest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Sets up fake interfaces.
+    InfRequestTest()
+        : Dhcpv6SrvTest(),
+          iface_mgr_test_config_(true) {
+    }
+
+    /// @brief Interface Manager's fake configuration control.
+    IfaceMgrTestConfig iface_mgr_test_config_;
+};
+
+/// Check that server processes correctly an incoming inf-request in a
+/// typical subnet that has also address and prefix pools.
+TEST_F(InfRequestTest, infRequestBasic) {
+    Dhcp6Client client;
+
+    // Configure client to request IA_PD.
+    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());
+
+    // Perform 2-way exchange (Inf-request/reply)
+    ASSERT_NO_THROW(client.doInfRequest());
+
+    // Confirm that there's a response
+    Pkt6Ptr response = client.getContext().response_;
+    ASSERT_TRUE(response);
+
+    Option6AddrLstPtr dns = boost::dynamic_pointer_cast<Option6AddrLst>
+                            (response->getOption(D6O_NAME_SERVERS));
+    ASSERT_TRUE(dns);
+    Option6AddrLst::AddressContainer addrs = dns->getAddresses();
+    ASSERT_EQ(2, addrs.size());
+    EXPECT_EQ("2001:db8::1", addrs[0].toText());
+    EXPECT_EQ("2001:db8::2", addrs[0].toText());
+}
+
+/// Check that server processes correctly an incoming inf-request
+/// that does not hold client-id. It's so called anonymous inf-request.
+/// Uncommon, but certainly valid behavior.
+TEST_F(InfRequestTest, infRequestAnonymous) {
+    Dhcp6Client client;
+
+    // Configure client to request IA_PD.
+    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());
+
+    // Perform 2-way exchange (Inf-request/reply)
+    client.sendClientId(false);
+    ASSERT_NO_THROW(client.doInfRequest());
+
+    // Confirm that there's a response
+    Pkt6Ptr response = client.getContext().response_;
+    ASSERT_TRUE(response);
+
+    Option6AddrLstPtr dns = boost::dynamic_pointer_cast<Option6AddrLst>
+                            (response->getOption(D6O_NAME_SERVERS));
+    ASSERT_TRUE(dns);
+    Option6AddrLst::AddressContainer addrs = dns->getAddresses();
+    ASSERT_EQ(2, addrs.size());
+    EXPECT_EQ("2001:db8::1", addrs[0].toText());
+    EXPECT_EQ("2001:db8::2", addrs[0].toText());
+}
+
+/// Check that server processes correctly an incoming inf-request
+/// if there is a subnet without any addresses or prefixes configured.
+TEST_F(InfRequestTest, infRequestStateless) {
+    Dhcp6Client client;
+
+    // Configure client to request IA_PD.
+    configure(CONFIGS[1], *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());
+
+    // Perform 2-way exchange (Inf-request/reply)
+    ASSERT_NO_THROW(client.doInfRequest());
+
+    // Confirm that there's a response
+    Pkt6Ptr response = client.getContext().response_;
+    ASSERT_TRUE(response);
+
+    Option6AddrLstPtr sip = boost::dynamic_pointer_cast<Option6AddrLst>
+                            (response->getOption(D6O_SIP_SERVERS_ADDR));
+    ASSERT_TRUE(sip);
+    Option6AddrLst::AddressContainer addrs = sip->getAddresses();
+    ASSERT_EQ(1, addrs.size());
+    EXPECT_EQ("2001:db8::abcd", addrs[0].toText());
+}
+
+
+} // end of anonymous namespace