BIND 10 trac3222, updated. 8a34ddb92a150b69ceed86af47256187634089c0 [3222] Added D2 unit test files to dhpc6

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Feb 20 21:32:02 UTC 2014


The branch, trac3222 has been updated
       via  8a34ddb92a150b69ceed86af47256187634089c0 (commit)
      from  9a3ec0716d8ca77ce19cda435f79ccb19d06bef1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8a34ddb92a150b69ceed86af47256187634089c0
Author: Thomas Markwalder <tmark at isc.org>
Date:   Thu Feb 20 16:31:16 2014 -0500

    [3222] Added D2 unit test files to dhpc6

-----------------------------------------------------------------------

Summary of changes:
 src/bin/{dhcp4 => dhcp6}/tests/d2_unittest.cc |   66 +++++++++++++------------
 src/bin/{dhcp4 => dhcp6}/tests/d2_unittest.h  |   24 ++++-----
 2 files changed, 46 insertions(+), 44 deletions(-)
 copy src/bin/{dhcp4 => dhcp6}/tests/d2_unittest.cc (88%)
 copy src/bin/{dhcp4 => dhcp6}/tests/d2_unittest.h (89%)

-----------------------------------------------------------------------
diff --git a/src/bin/dhcp6/tests/d2_unittest.cc b/src/bin/dhcp6/tests/d2_unittest.cc
new file mode 100644
index 0000000..d3cec74
--- /dev/null
+++ b/src/bin/dhcp6/tests/d2_unittest.cc
@@ -0,0 +1,381 @@
+// Copyright (C) 2014 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 <dhcp/iface_mgr.h>
+#include <dhcp6/config_parser.h>
+#include <dhcp6/tests/d2_unittest.h>
+#include <dhcpsrv/cfgmgr.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @todo
+void
+D2Dhcpv6Srv::d2ClientErrorHandler(const
+                                dhcp_ddns::NameChangeSender::Result result,
+                                dhcp_ddns::NameChangeRequestPtr& ncr) {
+    ++error_count_;
+    // call base class error handler
+    Dhcpv6Srv::d2ClientErrorHandler(result, ncr);
+}
+
+const bool Dhcp6SrvD2Test::SHOULD_PASS;
+const bool Dhcp6SrvD2Test::SHOULD_FAIL;
+
+Dhcp6SrvD2Test::Dhcp6SrvD2Test() : rcode_(-1) {
+}
+
+Dhcp6SrvD2Test::~Dhcp6SrvD2Test() {
+    reset();
+}
+
+dhcp_ddns::NameChangeRequestPtr
+Dhcp6SrvD2Test::buildTestNcr(uint32_t dhcid_id_num) {
+    // Build an NCR from json string.
+    std::ostringstream stream;
+
+    stream <<
+        "{"
+        " \"change_type\" : 0 , "
+        " \"forward_change\" : true , "
+        " \"reverse_change\" : false , "
+        " \"fqdn\" : \"myhost.example.com.\" , "
+        " \"ip_address\" : \"192.168.2.1\" , "
+        " \"dhcid\" : \""
+
+        << std::hex << std::setfill('0') << std::setw(16)
+        << dhcid_id_num << "\" , "
+
+        " \"lease_expires_on\" : \"20140121132405\" , "
+        " \"lease_length\" : 1300 "
+        "}";
+
+    return (dhcp_ddns::NameChangeRequest::fromJSON(stream.str()));
+}
+
+void
+Dhcp6SrvD2Test::reset() {
+    std::string config = "{ \"interfaces\": [ \"all\" ],"
+            "\"hooks-libraries\": [ ],"
+            "\"preferred-lifetime\": 3000,"
+            "\"rebind-timer\": 2000, "
+            "\"renew-timer\": 1000, "
+            "\"valid-lifetime\": 4000, "
+            "\"subnet6\": [ ], "
+            "\"dhcp-ddns\": { \"enable-updates\" : false }, "
+            "\"option-def\": [ ], "
+            "\"option-data\": [ ] }";
+    configure(config, SHOULD_PASS);
+}
+
+void
+Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
+                            const std::string& ip_address,
+                            const uint32_t port) {
+    std::ostringstream config;
+    config <<
+        "{ \"interfaces\": [ \"*\" ],"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ],"
+        " \"dhcp-ddns\" : {"
+        "     \"enable-updates\" : " << (enable_d2 ? "true" : "false") <<  ", "
+        "     \"server-ip\" : \"" << ip_address << "\", "
+        "     \"server-port\" : " << port << ", "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"allow-client-update\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"test.suffix.\" },"
+        "\"valid-lifetime\": 4000 }";
+
+    configure(config.str(), exp_result);
+}
+
+void
+Dhcp6SrvD2Test::configure(const std::string& config, bool exp_result) {
+    ElementPtr json = Element::fromJSON(config);
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    ASSERT_TRUE(status);
+
+    int rcode;
+    ConstElementPtr comment = config::parseAnswer(rcode, status);
+    if (exp_result == SHOULD_PASS) {
+        ASSERT_EQ(0, rcode);
+    } else {
+        ASSERT_EQ(1, rcode);
+    }
+}
+
+// Tests ability to turn on and off ddns updates by submitting
+// by submitting the appropriate configuration to Dhcp6 server
+// and then invoking its startD2() method.
+TEST_F(Dhcp6SrvD2Test, enableDisable) {
+    // Grab the manager and verify that be default ddns is off
+    // and a sender was not started.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_FALSE(mgr.ddnsEnabled());
+    ASSERT_FALSE(mgr.amSending());
+
+    // Verify a valid config with ddns enabled configures ddns properly,
+    // but does not start the sender.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_FALSE(mgr.amSending());
+
+    // Verify that calling start does not throw and starts the sender.
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Verify a valid config with ddns disabled configures ddns properly.
+    // Sender should not have been started.
+    ASSERT_NO_FATAL_FAILURE(configureD2(false));
+    ASSERT_FALSE(mgr.ddnsEnabled());
+    ASSERT_FALSE(mgr.amSending());
+
+    // Verify that the sender does NOT get started when ddns is disabled.
+    srv_.startD2();
+    ASSERT_FALSE(mgr.amSending());
+}
+
+// Tests Dhcp6 server's ability to correctly handle a flawed dhcp-ddns configuration.
+// It does so by first enabling updates by submitting a valid configuration and then
+// ensuring they remain on after submitting a flawed configuration.
+// and then invoking its startD2() method.
+TEST_F(Dhcp6SrvD2Test, badConfig) {
+    // Grab the manager and verify that be default ddns is off
+    // and a sender was not started.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_FALSE(mgr.ddnsEnabled());
+
+    // Configure it enabled and start it.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Now attempt to give it an invalid configuration.
+    // Result should indicate failure.
+    ASSERT_NO_FATAL_FAILURE(configureD2(false, SHOULD_FAIL, "bogus_ip"));
+
+    // Configure was not altered, so ddns should be enabled and still sending.
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Verify that calling start does not throw or stop the sender.
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+}
+
+// Checks that submitting an identical dhcp-ddns configuration
+// is handled properly.  Not effect should be no change in
+// status for ddns updating.  Updates should still enabled and
+// in send mode.  This indicates that the sender was not stopped.
+TEST_F(Dhcp6SrvD2Test, sameConfig) {
+    // Grab the manager and verify that be default ddns is off
+    // and a sender was not started.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_FALSE(mgr.ddnsEnabled());
+
+    // Configure it enabled and start it.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Now submit an identical configuration.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+
+    // Configuration was not altered, so ddns should still enabled and sending.
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Verify that calling start does not throw or stop the sender.
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+}
+
+// Checks that submitting an different, but valid dhcp-ddns configuration
+// is handled properly.  Updates should be enabled, however they should
+// not yet be running.  This indicates that the sender was stopped and
+// replaced, but not yet started.
+TEST_F(Dhcp6SrvD2Test, differentConfig) {
+    // Grab the manager and verify that be default ddns is off
+    // and a sender was not started.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_FALSE(mgr.ddnsEnabled());
+
+    // Configure it enabled and start it.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Now enable it on a different port.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "127.0.0.1", 54001));
+
+    // Configuration was altered, so ddns should still enabled but not sending.
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_FALSE(mgr.amSending());
+
+    // Verify that calling start starts the sender.
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+}
+
+// Checks that given a valid, enabled configuration and placing
+// sender in send mode, permits NCR requests to be sent via UPD
+// socket.  Note this test does not employ any sort of receiving
+// client to verify actual transmission.  These types of tests
+// are including under dhcp_ddns and d2 unit testing.
+TEST_F(Dhcp6SrvD2Test, simpleUDPSend) {
+    // Grab the manager and verify that be default ddns is off
+    // and a sender was not started.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_FALSE(mgr.ddnsEnabled());
+
+    // Configure it enabled and start it.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Verify that we can queue up a message.
+    dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
+    ASSERT_NO_THROW(mgr.sendRequest(ncr));
+    EXPECT_EQ(1, mgr.getQueueSize());
+
+    // Calling receive should detect the ready IO on the sender's select-fd,
+    // and invoke callback, which should complete the send.
+    ASSERT_NO_THROW(IfaceMgr::instance().receive4(0,0));
+
+    // Verify the queue is now empty.
+    EXPECT_EQ(0, mgr.getQueueSize());
+}
+
+// Checks that an IO error in sending a request to D2, results in ddns updates
+// being suspended.  This indicates that Dhcp6Srv's error handler has been
+// invoked as expected.  Note that this unit test relies on an attempt to send
+// to a server address of 0.0.0.0 port 0 fails under all OSs.
+TEST_F(Dhcp6SrvD2Test, forceUDPSendFailure) {
+    // Grab the manager and verify that be default ddns is off
+    // and a sender was not started.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_FALSE(mgr.ddnsEnabled());
+
+    // Configure it enabled and start it.
+    // Using server address of 0.0.0.0/0 should induce failure on send.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "0.0.0.0", 0));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Queue up 3 messages.
+    for (int i = 0; i < 3; i++) {
+        dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr(i + 1);
+        ASSERT_NO_THROW(mgr.sendRequest(ncr));
+    }
+    EXPECT_EQ(3, mgr.getQueueSize());
+
+    // Calling receive should detect the ready IO on the sender's select-fd,
+    // and invoke callback, which should complete the send, which should
+    // fail.
+    ASSERT_NO_THROW(IfaceMgr::instance().receive4(0,0));
+
+    // Verify the error handler was invoked.
+    EXPECT_EQ(1, srv_.error_count_);
+
+    // Verify that updates are disabled and we are no longer sending.
+    ASSERT_FALSE(mgr.ddnsEnabled());
+    ASSERT_FALSE(mgr.amSending());
+
+    // Verify message is still in the queue.
+    EXPECT_EQ(3, mgr.getQueueSize());
+
+    // Verify that we can't just restart it.
+    /// @todo This may change if we add ability to resume.
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_FALSE(mgr.amSending());
+
+    // Configure it enabled and start it.
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Verify message is still in the queue.
+    EXPECT_EQ(3, mgr.getQueueSize());
+
+    // This will finish sending the 1st message in queue
+    // and initiate send of 2nd message.
+    ASSERT_NO_THROW(IfaceMgr::instance().receive4(0,0));
+    EXPECT_EQ(1, srv_.error_count_);
+
+    // First message is off the queue.
+    EXPECT_EQ(2, mgr.getQueueSize());
+}
+
+// Tests error handling of D2ClientMgr::sendRequest() failure
+// by attempting to queue maximum number of messages.
+TEST_F(Dhcp6SrvD2Test, queueMaxError) {
+    // Configure it enabled and start it.
+    dhcp::D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
+    ASSERT_NO_FATAL_FAILURE(configureD2(true));
+    ASSERT_TRUE(mgr.ddnsEnabled());
+    ASSERT_NO_THROW(srv_.startD2());
+    ASSERT_TRUE(mgr.amSending());
+
+    // Attempt to queue more then the maximum allowed.
+    int max_msgs = mgr.getQueueMaxSize();
+    for (int i = 0; i < max_msgs + 1; i++) {
+        dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr(i + 1);
+        ASSERT_NO_THROW(mgr.sendRequest(ncr));
+    }
+
+    // Stopping sender will complete the first message so there
+    // should be max less one.
+    EXPECT_EQ(max_msgs - 1, mgr.getQueueSize());
+
+    // Verify the error handler was invoked.
+    EXPECT_EQ(1, srv_.error_count_);
+
+    // Verify that updates are disabled and we are no longer sending.
+    ASSERT_FALSE(mgr.ddnsEnabled());
+    ASSERT_FALSE(mgr.amSending());
+}
+
+
+} // namespace test
+} // namespace dhcp
+} // namespace isc
+
diff --git a/src/bin/dhcp6/tests/d2_unittest.h b/src/bin/dhcp6/tests/d2_unittest.h
new file mode 100644
index 0000000..51ae3b1
--- /dev/null
+++ b/src/bin/dhcp6/tests/d2_unittest.h
@@ -0,0 +1,117 @@
+// Copyright (C) 2014 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.
+
+/// @file d2_unittest.h Defines classes for testing Dhcpv6srv with D2ClientMgr
+
+#ifndef D2_UNITTEST_H
+#define D2_UNITTEST_H
+
+#include <dhcp6/dhcp6_srv.h>
+#include <config/ccsession.h>
+
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief Test derivation of Dhcpv6Srv class used in D2 testing.
+/// Use of this class allows the intervention at strategic points in testing
+/// by permitting overridden methods and access to scope protected members.
+class D2Dhcpv6Srv : public  Dhcpv6Srv {
+public:
+    /// @brief Counts the number of times the client error handler is called.
+    int error_count_;
+
+    /// @brief Constructor
+    D2Dhcpv6Srv()
+        : Dhcpv6Srv(0), error_count_(0) {
+    }
+
+    /// @brief virtual Destructor.
+    virtual ~D2Dhcpv6Srv() {
+    }
+
+    /// @brief Override the error handler.
+    virtual void d2ClientErrorHandler(const dhcp_ddns::NameChangeSender::
+                                      Result result,
+                                      dhcp_ddns::NameChangeRequestPtr& ncr);
+};
+
+/// @brief Test fixture which permits testing the interaction between the
+/// D2ClientMgr and Dhcpv6Srv.
+class Dhcp6SrvD2Test : public ::testing::Test {
+public:
+    /// @brief Mnemonic constants for calls to configuration methods.
+    static const bool SHOULD_PASS = true;
+    static const bool SHOULD_FAIL = false;
+
+    /// @brief Constructor
+    Dhcp6SrvD2Test();
+
+    /// @brief virtual Destructor
+    virtual ~Dhcp6SrvD2Test();
+
+    /// @brief Resets the CfgMgr singleton to defaults.
+    /// Primarily used in the test destructor as gtest doesn't exit between
+    /// tests.
+    /// @todo CfgMgr should provide a method to reset everything or maybe
+    /// reconstruct the singleton.
+    void reset();
+
+    /// @brief Configures the server with D2 enabled or disabled
+    ///
+    /// Constructs a configuration string including dhcp-ddns with the
+    /// parameters given and passes it into the server's configuration handler.
+    ///
+    /// @param enable_updates value to assign to the enable-updates parameter
+    /// @param exp_result indicates if configuration should pass or fail
+    /// @param ip_address IP address for the D2 server
+    /// @param port  port for the D2 server
+    void configureD2(bool enable_updates, bool exp_result = SHOULD_PASS,
+                     const std::string& ip_address = "127.0.0.1",
+                     const uint32_t port = 53001);
+
+    /// @brief Configures the server with the given configuration
+    ///
+    /// Passes the given configuration string into the server's configuration
+    /// handler.  It accepts a flag indicating whether or not the configuration
+    /// is expected to succeed or fail.  This permits testing the server's
+    /// response to both valid and invalid configurations.
+    ///
+    /// @param config JSON string containing the configuration
+    /// @param exp_result indicates if configuration should pass or fail
+    void configure(const std::string& config, bool exp_result = SHOULD_PASS);
+
+    /// @brief Contructs a NameChangeRequest message from a fixed JSON string.
+    ///
+    /// @param dhcid_id_num Integer value to use as the DHCID.
+    dhcp_ddns::NameChangeRequestPtr buildTestNcr(uint32_t
+                                                 dhcid_id_num = 0xdeadbeef);
+
+    /// @brief Stores the return code of the last configuration attempt.
+    int rcode_;
+
+    /// @brief Stores the message component of the last configuration tattempt.
+    isc::data::ConstElementPtr comment_;
+
+    /// @brief Server object under test.
+    D2Dhcpv6Srv srv_;
+};
+
+}; // end of isc::dhcp::test namespace
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // D2_UNITTEST_H



More information about the bind10-changes mailing list