Parcourir la source

[2995] First unit-test for subnet6_select hook implemented.

Tomek Mrugalski il y a 12 ans
Parent
commit
5e4b2f06b8
1 fichiers modifiés avec 117 ajouts et 0 suppressions
  1. 117 0
      src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

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

@@ -24,6 +24,7 @@
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option_int_array.h>
+#include <dhcp/iface_mgr.h>
 #include <dhcp6/config_parser.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp/dhcp6.h>
@@ -148,6 +149,16 @@ public:
     NakedDhcpv6SrvTest() : rcode_(-1) {
         // it's ok if that fails. There should not be such a file anyway
         unlink(DUID_FILE);
+
+        const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+        // There must be some interface detected
+        if (ifaces.empty()) {
+            // We can't use ASSERT in constructor
+            ADD_FAILURE() << "No interfaces detected.";
+        }
+
+        valid_iface_ = ifaces.begin()->getName();
     }
 
     // Generate IA_NA option with specified parameters
@@ -296,6 +307,9 @@ public:
 
     int rcode_;
     ConstElementPtr comment_;
+
+    // Name of a valid network interface
+    string valid_iface_;
 };
 
 // Provides suport for tests against a preconfigured subnet6
@@ -2027,9 +2041,33 @@ public:
         return pkt6_send_callout(callout_handle);
     }
 
+    // Callback that stores received callout name and subnet6 values
+    static int
+    subnet6_select_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("subnet6_select");
+
+        callout_handle.getArgument("pkt6", callback_pkt6_);
+        callout_handle.getArgument("subnet6", callback_subnet6_);
+        callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
+
+        if (callback_subnet6_) {
+            cout << "#### subnet6_select: subnet6=" << callback_subnet6_->toText()
+                 << ", subnet6collection.size=" << callback_subnet6collection_.size()
+                 << endl;
+        } else {
+            cout << "#### subnet6 empty!" << endl;
+        }
+
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
     void resetCalloutBuffers() {
         callback_name_ = string("");
         callback_pkt6_.reset();
+        callback_subnet6_.reset();
+        callback_subnet6collection_.clear();
         callback_argument_names_.clear();
     }
 
@@ -2040,6 +2078,10 @@ public:
 
     static Pkt6Ptr callback_pkt6_; ///< Pkt6 structure returned in the callout
 
+    static Subnet6Ptr callback_subnet6_;
+
+    static Subnet6Collection callback_subnet6collection_;
+
     static vector<string> callback_argument_names_;
 };
 
@@ -2047,6 +2089,10 @@ string HooksDhcpv6SrvTest::callback_name_;
 
 Pkt6Ptr HooksDhcpv6SrvTest::callback_pkt6_;
 
+Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
+
+Subnet6Collection HooksDhcpv6SrvTest::callback_subnet6collection_;
+
 vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
 
 
@@ -2299,6 +2345,77 @@ TEST_F(HooksDhcpv6SrvTest, skip_pkt6_send) {
     ASSERT_EQ(0, srv_->fake_sent_.size());
 }
 
+
+// This test checks if Option Request Option (ORO) is parsed correctly
+// and the requested options are actually assigned.
+TEST_F(HooksDhcpv6SrvTest, subnet_select) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::getCalloutManager()->registerCallout("subnet6_select",
+                    subnet6_select_callout));
+
+    // Configure 2 subnets, both directly reachable over local interface
+    // (let's not complicate the matter with relays)
+    string config = "{ \"interface\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/64\" ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"" + valid_iface_ + "\" "
+        " }, {"
+        "    \"pool\": [ \"2001:db8:2::/64\" ],"
+        "    \"subnet\": \"2001:db8:2::/48\" "
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    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);
+    comment_ = parseAnswer(rcode_, status);
+    ASSERT_EQ(0, rcode_);
+
+    // Prepare solicit packet. Server should select first subnet for it
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface(valid_iface_);
+    sol->addOption(generateIA(234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr adv = srv_->processSolicit(sol);
+
+    // check if we get response at all
+    ASSERT_TRUE(adv);
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("subnet6_select", callback_name_);
+
+    // Check that pkt6 argument passing was successful and returned proper value
+    EXPECT_TRUE(callback_pkt6_.get() == sol.get());
+
+    Subnet6Collection exp_subnets = CfgMgr::instance().getSubnets6();
+
+    // The server is supposed to pick the first subnet, because of matching
+    // interface. Check that the value is reported properly.
+    ASSERT_TRUE(callback_subnet6_);
+    EXPECT_EQ(callback_subnet6_.get(), exp_subnets.front().get());
+
+    // Server is supposed to report two subnets
+    ASSERT_EQ(exp_subnets.size(), callback_subnet6collection_.size());
+
+    // Compare that the available subnets are reported as expected
+    EXPECT_TRUE(exp_subnets[0].get() == callback_subnet6collection_[0].get());
+    EXPECT_TRUE(exp_subnets[1].get() == callback_subnet6collection_[1].get());
+
+}
+
+
 /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
 /// to call processX() methods.