Browse Source

[2414] 2 new tests implemented (ManySolicits, ManyRequests), comments added

Tomek Mrugalski 12 years ago
parent
commit
75622a763d
1 changed files with 191 additions and 35 deletions
  1. 191 35
      src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

+ 191 - 35
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -65,18 +65,18 @@ public:
         CfgMgr::instance().addSubnet6(subnet_);
     }
 
+    // Generate IA_NA option with specified parameters
     shared_ptr<Option6IA> generateIA(uint32_t iaid, uint32_t t1, uint32_t t2) {
         shared_ptr<Option6IA> ia =
-            shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
+            shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, iaid));
         ia->setT1(t1);
         ia->setT2(t2);
         return (ia);
     }
 
-    OptionPtr generateClientId() {
+    // Generate client-id option
+    OptionPtr generateClientId(size_t duid_size = 32) {
 
-        // a dummy content for client-id
-        const size_t duid_size = 32;
         OptionBuffer clnt_duid(duid_size);
         for (int i = 0; i < duid_size; i++) {
             clnt_duid[i] = 100 + i;
@@ -89,6 +89,7 @@ public:
                                      clnt_duid.begin() + duid_size)));
     }
 
+    // Checks if server response (ADVERTISE or REPLY) includes proper server-id.
     void checkServerId(const Pkt6Ptr& rsp, const OptionPtr& expected_srvid) {
         // check that server included its server-id
         OptionPtr tmp = rsp->getOption(D6O_SERVERID);
@@ -97,6 +98,7 @@ public:
         EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
     }
 
+    // Checks if server response (ADVERTISE or REPLY) includes proper client-id.
     void checkClientId(const Pkt6Ptr& rsp, const OptionPtr& expected_clientid) {
         // check that server included our own client-id
         OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
@@ -108,6 +110,8 @@ public:
         EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
     }
 
+    // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
+    // It returns IAADDR option for each chaining with checkIAAddr method.
     shared_ptr<Option6IAAddr> checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
                                          uint32_t expected_t1, uint32_t expected_t2) {
         OptionPtr tmp = rsp->getOption(D6O_IA_NA);
@@ -127,6 +131,7 @@ public:
         return (addr);
     }
 
+    // Check that generated IAADDR option contains expected address.
     void checkIAAddr(shared_ptr<Option6IAAddr> addr, const IOAddress& expected_addr,
                      uint32_t expected_preferred, uint32_t expected_valid) {
         // Check that the assigned address is indeed from the configured pool
@@ -136,19 +141,23 @@ public:
         EXPECT_EQ(addr->getValid(), subnet_->getValid());
     }
 
-    void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_type,
+    // Basic checks for generated response (message type and transaction-id).
+    void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
                        uint32_t expected_transid) {
         ASSERT_TRUE(rsp);
-        EXPECT_EQ(expected_type, rsp->getType());
+        EXPECT_EQ(expected_message_type, rsp->getType());
         EXPECT_EQ(expected_transid, rsp->getTransid());
     }
 
-    Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na, shared_ptr<Option6IAAddr> addr) {
+    // Checks if the lease sent to client is present in the database
+    Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
+                         shared_ptr<Option6IAAddr> addr) {
         shared_ptr<Option6IA> ia = dynamic_pointer_cast<Option6IA>(ia_na);
 
         Lease6Ptr lease = LeaseMgr::instance().getLease6(addr->getAddress());
         if (!lease) {
-            cout << "Lease for " << addr->getAddress().toText() << " not found in the database backend.";
+            cout << "Lease for " << addr->getAddress().toText()
+                 << " not found in the database backend.";
             return (Lease6Ptr());
         }
 
@@ -163,8 +172,14 @@ public:
     ~Dhcpv6SrvTest() {
         CfgMgr::instance().deleteSubnets6();
     };
+
+    // A subnet used in most tests
     Subnet6Ptr subnet_;
+
+    // A pool used in most tests
     Pool6Ptr pool_;
+
+    // A DUID used in most tests (typically as client-id)
     DuidPtr duid_;
 };
 
@@ -270,8 +285,8 @@ TEST_F(Dhcpv6SrvTest, DUID) {
 // There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
 // as they are indirectly tested in Solicit and Request tests.
 
-// This test verifies that incoming SOLICIT can be handled properly, that a
-// reponse is generated, that the response has an address and that address
+// This test verifies that incoming SOLICIT can be handled properly, that an
+// ADVERTISE is generated, that the response has an address and that address
 // really belongs to the configured pool.
 //
 // This test sends a SOLICIT without any hint in IA_NA.
@@ -298,12 +313,7 @@ TEST_F(Dhcpv6SrvTest, SolicitBasic) {
 
     sol->addOption(clientid);
 
-    // Let's not send address in solicit yet
-    // boost::shared_ptr<Option6IAAddr> addr(new Option6IAAddr(D6O_IAADDR,
-    //    IOAddress("2001:db8:1234:ffff::ffff"), 5001, 7001));
-    // ia->addOption(addr);
-    // sol->addOption(ia);
-
+    // Pass it to the server and get an advertise
     Pkt6Ptr reply = srv->processSolicit(sol);
 
     // check if we get response at all
@@ -321,8 +331,8 @@ TEST_F(Dhcpv6SrvTest, SolicitBasic) {
     checkClientId(reply, clientid);
 }
 
-// This test verifies that incoming SOLICIT can be handled properly, that a
-// reponse is generated, that the response has an address and that address
+// This test verifies that incoming SOLICIT can be handled properly, that an
+// ADVERTISE is generated, that the response has an address and that address
 // really belongs to the configured pool.
 //
 // This test sends a SOLICIT with IA_NA that contains a valid hint.
@@ -354,7 +364,7 @@ TEST_F(Dhcpv6SrvTest, SolicitHint) {
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
-    // Pass it to the server and hope for a reply
+    // Pass it to the server and get an advertise
     Pkt6Ptr reply = srv->processSolicit(sol);
 
     // check if we get response at all
@@ -375,8 +385,8 @@ TEST_F(Dhcpv6SrvTest, SolicitHint) {
     checkClientId(reply, clientid);
 }
 
-// This test verifies that incoming SOLICIT can be handled properly, that a
-// reponse is generated, that the response has an address and that address
+// This test verifies that incoming SOLICIT can be handled properly, that an
+// ADVERTISE is generated, that the response has an address and that address
 // really belongs to the configured pool.
 //
 // This test sends a SOLICIT with IA_NA that contains an invalid hint.
@@ -406,7 +416,7 @@ TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
     OptionPtr clientid = generateClientId();
     sol->addOption(clientid);
 
-    // Pass it to the server and get a reply
+    // Pass it to the server and get an advertise
     Pkt6Ptr reply = srv->processSolicit(sol);
 
     // check if we get response at all
@@ -425,18 +435,91 @@ TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
     checkClientId(reply, clientid);
 }
 
-// This test verifies that incoming SOLICIT can be handled properly, that a
-// reponse is generated, that the response has an address and that address
+// This test checks that the server is offering different addresses to different
+// clients in ADVERTISEs. Please note that ADVERTISE is not a guarantee that such
+// and address will be assigned. Had the pool was very small and contained only
+// 2 addresses, the third client would get the same advertise as the first one
+// and this is a correct behavior. It is REQUEST that fill fail for the third
+// client. ADVERTISE is basically saying "if you send me a request, you will
+// probably get an address like this" (there are no guarantees).
+TEST_F(Dhcpv6SrvTest, ManySolicits) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    Pkt6Ptr sol1 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    Pkt6Ptr sol2 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 2345));
+    Pkt6Ptr sol3 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 3456));
+
+    sol1->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol2->setRemoteAddr(IOAddress("fe80::1223"));
+    sol3->setRemoteAddr(IOAddress("fe80::3467"));
+
+    sol1->addOption(generateIA(1, 1500, 3000));
+    sol2->addOption(generateIA(2, 1500, 3000));
+    sol3->addOption(generateIA(3, 1500, 3000));
+
+    // different client-id sizes
+    OptionPtr clientid1 = generateClientId(12);
+    OptionPtr clientid2 = generateClientId(14);
+    OptionPtr clientid3 = generateClientId(16);
+
+    sol1->addOption(clientid1);
+    sol2->addOption(clientid2);
+    sol3->addOption(clientid3);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply1 = srv->processSolicit(sol1);
+    Pkt6Ptr reply2 = srv->processSolicit(sol2);
+    Pkt6Ptr reply3 = srv->processSolicit(sol3);
+
+    // check if we get response at all
+    checkResponse(reply1, DHCPV6_ADVERTISE, 1234);
+    checkResponse(reply2, DHCPV6_ADVERTISE, 2345);
+    checkResponse(reply3, DHCPV6_ADVERTISE, 3456);
+
+    // check that IA_NA was returned and that there's an address included
+    shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
+                                                subnet_->getT2());
+    shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
+                                                subnet_->getT2());
+    shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
+                                                subnet_->getT2());
+
+    // Check that the assigned address is indeed from the configured pool
+    checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+
+    // check DUIDs
+    checkServerId(reply1, srv->getServerID());
+    checkServerId(reply2, srv->getServerID());
+    checkServerId(reply3, srv->getServerID());
+    checkClientId(reply1, clientid1);
+    checkClientId(reply2, clientid2);
+    checkClientId(reply3, clientid3);
+
+    // Finally check that the addresses offered are different
+    EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
+    EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
+    EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
+    cout << "Offered address to client1=" << addr1->getAddress().toText() << endl;
+    cout << "Offered address to client2=" << addr2->getAddress().toText() << endl;
+    cout << "Offered address to client3=" << addr3->getAddress().toText() << endl;
+}
+
+
+// This test verifies that incoming REQUEST can be handled properly, that a
+// REPLY is generated, that the response has an address and that address
 // really belongs to the configured pool.
 //
-// This test sends a SOLICIT with IA_NA that contains a valid hint.
+// This test sends a REQUEST with IA_NA that contains a valid hint.
 //
-// constructed very simple SOLICIT message with:
+// constructed very simple REQUEST message with:
 // - client-id option (mandatory)
 // - IA option (a request for address, with an address that belongs to the
 //              configured pool, i.e. is valid as hint)
 //
-// expected returned ADVERTISE message:
+// expected returned REPLY message:
 // - copy of client-id
 // - server-id
 // - IA that includes IAADDR
@@ -444,9 +527,9 @@ TEST_F(Dhcpv6SrvTest, RequestBasic) {
     boost::scoped_ptr<NakedDhcpv6Srv> srv;
     ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 
-    // Let's create a SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
-    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    // Let's create a REQUEST
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
     shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
 
     // with a valid hint
@@ -454,15 +537,15 @@ TEST_F(Dhcpv6SrvTest, RequestBasic) {
     ASSERT_TRUE(subnet_->inPool(hint));
     OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
     ia->addOption(hint_opt);
-    sol->addOption(ia);
+    req->addOption(ia);
     OptionPtr clientid = generateClientId();
-    sol->addOption(clientid);
+    req->addOption(clientid);
 
-    // Pass it to the server and hope for a reply
-    Pkt6Ptr reply = srv->processSolicit(sol);
+    // 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_ADVERTISE, 1234);
+    checkResponse(reply, DHCPV6_REPLY, 1234);
 
     OptionPtr tmp = reply->getOption(D6O_IA_NA);
     ASSERT_TRUE(tmp);
@@ -484,6 +567,79 @@ TEST_F(Dhcpv6SrvTest, RequestBasic) {
     LeaseMgr::instance().deleteLease6(addr->getAddress());
 }
 
+// This test checks that the server is offering different addresses to different
+// clients in REQUEST. Please note that ADVERTISE is not a guarantee that such
+// and address will be assigned. Had the pool was very small and contained only
+// 2 addresses, the third client would get the same advertise as the first one
+// and this is a correct behavior. It is REQUEST that fill fail for the third
+// client. ADVERTISE is basically saying "if you send me a request, you will
+// probably get an address like this" (there are no guarantees).
+TEST_F(Dhcpv6SrvTest, ManyRequests) {
+    boost::scoped_ptr<NakedDhcpv6Srv> srv;
+    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+
+    Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
+    Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
+    Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
+
+    req1->setRemoteAddr(IOAddress("fe80::abcd"));
+    req2->setRemoteAddr(IOAddress("fe80::1223"));
+    req3->setRemoteAddr(IOAddress("fe80::3467"));
+
+    req1->addOption(generateIA(1, 1500, 3000));
+    req2->addOption(generateIA(2, 1500, 3000));
+    req3->addOption(generateIA(3, 1500, 3000));
+
+    // different client-id sizes
+    OptionPtr clientid1 = generateClientId(12);
+    OptionPtr clientid2 = generateClientId(14);
+    OptionPtr clientid3 = generateClientId(16);
+
+    req1->addOption(clientid1);
+    req2->addOption(clientid2);
+    req3->addOption(clientid3);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr reply1 = srv->processRequest(req1);
+    Pkt6Ptr reply2 = srv->processRequest(req2);
+    Pkt6Ptr reply3 = srv->processRequest(req3);
+
+    // check if we get response at all
+    checkResponse(reply1, DHCPV6_REPLY, 1234);
+    checkResponse(reply2, DHCPV6_REPLY, 2345);
+    checkResponse(reply3, DHCPV6_REPLY, 3456);
+
+    // check that IA_NA was returned and that there's an address included
+    shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
+                                                subnet_->getT2());
+    shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
+                                                subnet_->getT2());
+    shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
+                                                subnet_->getT2());
+
+    // Check that the assigned address is indeed from the configured pool
+    checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+    checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
+
+    // check DUIDs
+    checkServerId(reply1, srv->getServerID());
+    checkServerId(reply2, srv->getServerID());
+    checkServerId(reply3, srv->getServerID());
+    checkClientId(reply1, clientid1);
+    checkClientId(reply2, clientid2);
+    checkClientId(reply3, clientid3);
+
+    // Finally check that the addresses offered are different
+    EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
+    EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
+    EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
+    cout << "Assigned address to client1=" << addr1->getAddress().toText() << endl;
+    cout << "Assigned address to client2=" << addr2->getAddress().toText() << endl;
+    cout << "Assigned address to client3=" << addr3->getAddress().toText() << endl;
+}
+
+
 TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) {
     // Check all possible packet types
     for (int itype = 0; itype < 256; ++itype) {