]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#991] added multi-threading unittests for v6 server
authorRazvan Becheriu <razvan@isc.org>
Thu, 10 Dec 2020 08:49:00 +0000 (10:49 +0200)
committerRazvan Becheriu <razvan@isc.org>
Thu, 10 Dec 2020 19:37:50 +0000 (19:37 +0000)
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_test_utils.cc
src/bin/dhcp4/tests/dhcp4_test_utils.h
src/bin/dhcp6/tests/dhcp6_client.cc
src/bin/dhcp6/tests/dhcp6_test_utils.cc
src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/dhcp6/tests/sarr_unittest.cc

index 7c1cbab9580cf5bad7c4e3719e3f4aa606c85bf2..4f4fc080380713620b65905d79eaa28da6af743b 100644 (file)
@@ -2244,8 +2244,14 @@ TEST_F(Dhcpv4SrvTest, sanityCheck) {
                  RFCViolation);
 }
 
-// Checks if received relay agent info option is echoed back to the client
-TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
+} // end of anonymous namespace
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+void
+Dhcpv4SrvTest::relayAgentInfoEcho() {
     IfaceMgrTestConfig test_config(true);
     NakedDhcpv4Srv srv(0);
 
@@ -2288,9 +2294,8 @@ TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
     EXPECT_TRUE(rai_response->equals(rai_query));
 }
 
-// Checks if received bad relay agent info option is not echoed back
-// to the client
-TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEcho) {
+void
+Dhcpv4SrvTest::badRelayAgentInfoEcho() {
     IfaceMgrTestConfig test_config(true);
     NakedDhcpv4Srv srv(0);
 
@@ -2333,8 +2338,8 @@ TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEcho) {
     ASSERT_FALSE(rai_response);
 }
 
-// Checks if client port can be overridden in packets being sent.
-TEST_F(Dhcpv4SrvTest, portsClientPort) {
+void
+Dhcpv4SrvTest::portsClientPort() {
     IfaceMgrTestConfig test_config(true);
     NakedDhcpv4Srv srv(0);
 
@@ -2374,8 +2379,8 @@ TEST_F(Dhcpv4SrvTest, portsClientPort) {
     EXPECT_EQ(srv.client_port_, offer->getRemotePort());
 }
 
-// Checks if server port can be overridden in packets being sent.
-TEST_F(Dhcpv4SrvTest, portsServerPort) {
+void
+Dhcpv4SrvTest::portsServerPort() {
     IfaceMgrTestConfig test_config(true);
 
     // Do not use DHCP4_SERVER_PORT here as 0 means don't open sockets.
@@ -2415,6 +2420,52 @@ TEST_F(Dhcpv4SrvTest, portsServerPort) {
     EXPECT_EQ(srv.server_port_, offer->getLocalPort());
 }
 
+} // end of isc::dhcp::test namespace
+} // end of isc::dhcp namespace
+} // end of isc namespace
+
+namespace {
+
+TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
+    Dhcpv4SrvMTTestGuard guard(*this, false);
+    relayAgentInfoEcho();
+}
+
+TEST_F(Dhcpv4SrvTest, relayAgentInfoEchoMultiThreading) {
+    Dhcpv4SrvMTTestGuard guard(*this, true);
+    relayAgentInfoEcho();
+}
+
+TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEcho) {
+    Dhcpv4SrvMTTestGuard guard(*this, false);
+    badRelayAgentInfoEcho();
+}
+
+TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEchoMultiThreading) {
+    Dhcpv4SrvMTTestGuard guard(*this, true);
+    badRelayAgentInfoEcho();
+}
+
+TEST_F(Dhcpv4SrvTest, portsClientPort) {
+    Dhcpv4SrvMTTestGuard guard(*this, false);
+    portsClientPort();
+}
+
+TEST_F(Dhcpv4SrvTest, portsClientPortMultiThreading) {
+    Dhcpv4SrvMTTestGuard guard(*this, true);
+    portsClientPort();
+}
+
+TEST_F(Dhcpv4SrvTest, portsServerPort) {
+    Dhcpv4SrvMTTestGuard guard(*this, false);
+    portsServerPort();
+}
+
+TEST_F(Dhcpv4SrvTest, portsServerPortMultiTHreading) {
+    Dhcpv4SrvMTTestGuard guard(*this, true);
+    portsServerPort();
+}
+
 /// @todo Implement tests for subnetSelect See tests in dhcp6_srv_unittest.cc:
 /// selectSubnetAddr, selectSubnetIface, selectSubnetRelayLinkaddr,
 /// selectSubnetRelayInterfaceId. Note that the concept of interface-id is not
index 59a0ecdc26dbc543a367cf2accc9e33cf01d0d69..6f57b9fed535bcca374ce048670572abfb36bae4 100644 (file)
@@ -456,8 +456,6 @@ Dhcpv4SrvTest::TearDown() {
                << " class after the test. Exception has been caught: "
                << ex.what();
     }
-
-    setMultiThreading(false);
 }
 
 void
index 15a6caa588d400c6c9d528abedeb45be530d8a10..6b794ecd1953ab92814a425c7360b711d4eb15a8 100644 (file)
@@ -170,6 +170,11 @@ public:
         }
     }
 
+    /// @brief fake receive packet from server
+    ///
+    /// The client uses this packet as a reply from the server.
+    ///
+    /// @return The received packet.
     Pkt4Ptr receiveOneMsg() {
         if (isc::util::MultiThreadingMgr::instance().getMode()) {
             std::lock_guard<std::mutex> lk(mutex_);
@@ -179,6 +184,12 @@ public:
         }
     }
 
+    /// @brief fake receive packet from server
+    ///
+    /// The client uses this packet as a reply from the server.
+    /// This function should be called in a thread safe context.
+    ///
+    /// @return The received packet.
     Pkt4Ptr receiveOneMsgInternal() {
         // Return empty pointer if server hasn't responded.
         if (fake_sent_.empty()) {
@@ -216,7 +227,7 @@ public:
         processRelease(release, context);
     }
 
-    /// @brief Runs processing DHCPDECLINE
+    /// @brief Runs processing DHCPDECLINE.
     ///
     /// @param decline message received from client
     void processDecline(Pkt4Ptr& decline) {
@@ -227,7 +238,7 @@ public:
     /// @brief Dummy server identifier option used by various tests.
     OptionPtr server_id_;
 
-    /// @brief packets we pretend to receive
+    /// @brief packets we pretend to receive.
     ///
     /// Instead of setting up sockets on interfaces that change between OSes, it
     /// is much easier to fake packet reception. This is a list of packets that
@@ -235,7 +246,7 @@ public:
     /// using fakeReceive() and NakedDhcpv4Srv::receivePacket() methods.
     std::list<Pkt4Ptr> fake_received_;
 
-    /// @brief packets we pretend to send
+    /// @brief packets we pretend to send.
     std::list<Pkt4Ptr> fake_sent_;
 
     using Dhcpv4Srv::adjustIfaceData;
@@ -556,9 +567,19 @@ public:
                            ExpectedResult expected_result);
 
     /// @brief Checks if received relay agent info option is echoed back to the
-    /// client
+    /// client.
     void relayAgentInfoEcho();
 
+    /// @brief Checks if received bad relay agent info option is not echoed back
+    /// to the client.
+    void badRelayAgentInfoEcho();
+
+    /// @brief Checks if client port can be overridden in packets being sent.
+    void portsClientPort();
+
+    /// @brief  Checks if server port can be overridden in packets being sent.
+    void portsServerPort();
+
     /// @brief This function cleans up after the test.
     virtual void TearDown();
 
@@ -567,25 +588,25 @@ public:
         multi_threading_ = enabled;
     }
 
-    /// @brief A subnet used in most tests
+    /// @brief A subnet used in most tests.
     Subnet4Ptr subnet_;
 
-    /// @brief A pool used in most tests
+    /// @brief A pool used in most tests.
     Pool4Ptr pool_;
 
-    /// @brief A client-id used in most tests
+    /// @brief A client-id used in most tests.
     ClientIdPtr client_id_;
 
     /// @brief Return code
     int rcode_;
 
-    /// @brief Comment
+    /// @brief Comment received from configuration.
     isc::data::ConstElementPtr comment_;
 
     /// @brief Server object under test.
     NakedDhcpv4Srv srv_;
 
-    /// @brief The multi-threading flag
+    /// @brief The multi-threading flag.
     bool multi_threading_;
 };
 
index 45c0831febe2ec2b5ce5a187320f9e4c03d96242..fb612a9c4d66330ff9d1f6712d31b79f228a3de3 100644 (file)
@@ -21,6 +21,7 @@
 #include <dhcpsrv/pool.h>
 #include <dhcp6/tests/dhcp6_client.h>
 #include <util/buffer.h>
+#include <util/multi_threading_mgr.h>
 #include <boost/foreach.hpp>
 #include <boost/pointer_cast.hpp>
 #include <algorithm>
@@ -31,6 +32,7 @@
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
+using namespace isc::util;
 
 namespace {
 
@@ -618,7 +620,6 @@ Dhcp6Client::doRelease() {
     }
 }
 
-
 void
 Dhcp6Client::generateIAFromLeases(const Pkt6Ptr& query,
                                   const bool include_address) {
@@ -778,8 +779,7 @@ Dhcp6Client::hasLeaseForAddressRange(const asiolink::IOAddress& first,
 }
 
 bool
-Dhcp6Client::
-hasLeaseWithZeroLifetimeForAddress(const asiolink::IOAddress& address) const {
+Dhcp6Client::hasLeaseWithZeroLifetimeForAddress(const asiolink::IOAddress& address) const {
     std::vector<Lease6> leases = getLeasesByAddress(address);
     BOOST_FOREACH(const Lease6& lease, leases) {
         if ((lease.preferred_lft_ == 0) && (lease.valid_lft_ == 0)) {
@@ -919,13 +919,7 @@ Dhcp6Client::modifyDUID() {
 
 Pkt6Ptr
 Dhcp6Client::receiveOneMsg() {
-    // Return empty pointer if server hasn't responded.
-    if (srv_->fake_sent_.empty()) {
-        return (Pkt6Ptr());
-    }
-    Pkt6Ptr msg = srv_->fake_sent_.front();
-    srv_->fake_sent_.pop_front();
-    return (msg);
+    return (srv_->receiveOneMsg());
 }
 
 void
@@ -991,6 +985,9 @@ Dhcp6Client::sendMsg(const Pkt6Ptr& msg) {
     } catch (...) {
         // Suppress errors, as the DHCPv6 server does.
     }
+
+    // Make sure the server processed all packets in MT.
+    isc::util::MultiThreadingMgr::instance().getThreadPool().wait();
 }
 
 void
index e9591cecdb3e1eb2a1a343b65c8ed266035eff5d..31ff44a78992713c39ee6c7c7a228b192bfff65f 100644 (file)
@@ -6,13 +6,14 @@
 
 #include <config.h>
 #include <gtest/gtest.h>
+#include <cc/command_interpreter.h>
 #include <dhcp/option6_status_code.h>
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp/tests/pkt_captures.h>
 #include <log/logger_support.h>
+#include <dhcpsrv/cfg_multi_threading.h>
 #include <util/pointer_util.h>
-#include <cc/command_interpreter.h>
 #include <stats/stats_mgr.h>
 #include <cstdio>
 #include <sstream>
@@ -22,6 +23,7 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::stats;
+using namespace isc::util;
 
 namespace isc {
 namespace dhcp {
@@ -53,16 +55,14 @@ BaseServerTest::~BaseServerTest() {
 }
 
 Dhcpv6SrvTest::Dhcpv6SrvTest()
-    : NakedDhcpv6SrvTest(), srv_(0) {
-    subnet_ = isc::dhcp::Subnet6Ptr
-        (new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
-                                48, 1000, 2000, 3000, 4000));
+    : NakedDhcpv6SrvTest(), srv_(0), multi_threading_(false) {
+    subnet_ = isc::dhcp::Subnet6Ptr(new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
+                                                           48, 1000, 2000, 3000, 4000));
     subnet_->setIface("eth0");
 
-    pool_ = isc::dhcp::Pool6Ptr
-        (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
-                              isc::asiolink::IOAddress("2001:db8:1:1::"),
-                              64));
+    pool_ = isc::dhcp::Pool6Ptr(new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
+                                isc::asiolink::IOAddress("2001:db8:1:1::"),
+                                64));
     subnet_->addPool(pool_);
 
     isc::dhcp::CfgMgr::instance().clear();
@@ -71,10 +71,9 @@ Dhcpv6SrvTest::Dhcpv6SrvTest()
     isc::dhcp::CfgMgr::instance().commit();
 
     // configure PD pool
-    pd_pool_ = isc::dhcp::Pool6Ptr
-        (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
-                              isc::asiolink::IOAddress("2001:db8:1:2::"),
-                              64, 80));
+    pd_pool_ = isc::dhcp::Pool6Ptr(new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
+                                   isc::asiolink::IOAddress("2001:db8:1:2::"),
+                                   64, 80));
     subnet_->addPool(pd_pool_);
 }
 
@@ -809,6 +808,7 @@ Dhcpv6SrvTest::configure(const std::string& config) {
 
 void
 Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
+    MultiThreadingCriticalSection cs;
     ConstElementPtr json;
     try {
         json = parseJSON(config);
@@ -822,6 +822,9 @@ Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
     // Disable the re-detect flag
     disableIfacesReDetect(json);
 
+    // Set up multi-threading
+    configureMultiThreading(multi_threading_, json);
+
     // Configure the server and make sure the config is accepted
     EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
     ASSERT_TRUE(status);
@@ -830,11 +833,18 @@ Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
     ASSERT_EQ(0, rcode) << "configuration failed, test is broken: "
         << comment->str();
 
+    try {
+        CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
+    } catch (const std::exception& ex) {
+        ADD_FAILURE() << "Error applying multi threading settings: "
+            << ex.what();
+    }
+
     CfgMgr::instance().commit();
 }
 
 NakedDhcpv6SrvTest::NakedDhcpv6SrvTest()
-: rcode_(-1) {
+    : rcode_(-1) {
     // it's ok if that fails. There should not be such a file anyway
     static_cast<void>(remove(DUID_FILE));
 
index a41431ff41b4099a7908af194a230d820b745bdb..3172ef8f2e945656c3a20023480a45fcef0f5cc8 100644 (file)
@@ -29,6 +29,7 @@
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp6/parser_context.h>
 #include <hooks/hooks_manager.h>
+#include <util/multi_threading_mgr.h>
 
 #include <list>
 
@@ -157,6 +158,9 @@ public:
             return (pkt);
         }
 
+        // Make sure the server processed all packets in MT.
+        isc::util::MultiThreadingMgr::instance().getThreadPool().wait();
+
         // If not, just trigger shutdown and
         // return immediately
         shutdown();
@@ -169,7 +173,42 @@ public:
     /// it in fake_send_ list where test can later inspect
     /// server's response.
     virtual void sendPacket(const isc::dhcp::Pkt6Ptr& pkt) {
-        fake_sent_.push_back(pkt);
+        if (isc::util::MultiThreadingMgr::instance().getMode()) {
+            std::lock_guard<std::mutex> lk(mutex_);
+            fake_sent_.push_back(pkt);
+        } else {
+            fake_sent_.push_back(pkt);
+        }
+    }
+
+    /// @brief fake receive packet from server
+    ///
+    /// The client uses this packet as a reply from the server.
+    ///
+    /// @return The received packet.
+    Pkt6Ptr receiveOneMsg() {
+        if (isc::util::MultiThreadingMgr::instance().getMode()) {
+            std::lock_guard<std::mutex> lk(mutex_);
+            return (receiveOneMsgInternal());
+        } else {
+            return (receiveOneMsgInternal());
+        }
+    }
+
+    /// @brief fake receive packet from server
+    ///
+    /// The client uses this packet as a reply from the server.
+    /// This function should be called in a thread safe context.
+    ///
+    /// @return The received packet.
+    Pkt6Ptr receiveOneMsgInternal() {
+        // Return empty pointer if server hasn't responded.
+        if (fake_sent_.empty()) {
+            return (Pkt6Ptr());
+        }
+        Pkt6Ptr msg = fake_sent_.front();
+        fake_sent_.pop_front();
+        return (msg);
     }
 
     /// @brief adds a packet to fake receive queue
@@ -276,7 +315,7 @@ public:
     using Dhcpv6Srv::server_port_;
     using Dhcpv6Srv::client_port_;
 
-    /// @brief packets we pretend to receive
+    /// @brief packets we pretend to receive.
     ///
     /// Instead of setting up sockets on interfaces that change between
     /// OSes, it is much easier to fake packet reception. This is a list
@@ -285,7 +324,11 @@ public:
     /// NakedDhcpv6Srv::receivePacket() methods.
     std::list<isc::dhcp::Pkt6Ptr> fake_received_;
 
+    /// @brief packets we pretend to send.
     std::list<isc::dhcp::Pkt6Ptr> fake_sent_;
+
+    /// @brief Mutex to protect the packet buffers.
+    std::mutex mutex_;
 };
 
 /// @brief Test fixture for any tests requiring blank/empty configuration
@@ -497,6 +540,17 @@ public:
         NO_IA       // Client will not send IA_NA at all
     };
 
+    class Dhcpv6SrvMTTestGuard {
+    public:
+        Dhcpv6SrvMTTestGuard(Dhcpv6SrvTest& test, bool mt_enabled) : test_(test) {
+            test_.setMultiThreading(mt_enabled);
+        }
+        ~Dhcpv6SrvMTTestGuard() {
+            test_.setMultiThreading(false);
+        }
+        Dhcpv6SrvTest& test_;
+    };
+
     /// @brief Constructor that initializes a simple default configuration
     ///
     /// Sets up a single subnet6 with one pool for addresses and second
@@ -587,9 +641,10 @@ public:
 
     // Checks if the lease sent to client is present in the database
     // and is valid when checked against the configured subnet
-    isc::dhcp::Lease6Ptr checkLease
-        (const isc::dhcp::DuidPtr& duid, const isc::dhcp::OptionPtr& ia_na,
-         boost::shared_ptr<isc::dhcp::Option6IAAddr> addr);
+    isc::dhcp::Lease6Ptr
+    checkLease(const isc::dhcp::DuidPtr& duid,
+               const isc::dhcp::OptionPtr& ia_na,
+               boost::shared_ptr<isc::dhcp::Option6IAAddr> addr);
 
     /// @brief Check if the specified lease is present in the data base.
     ///
@@ -606,9 +661,10 @@ public:
     /// @param ia_pd IA_PD option that contains the IAPRefix option
     /// @param prefix pointer to the IAPREFIX option
     /// @return corresponding IPv6 lease (if found)
-    isc::dhcp::Lease6Ptr checkPdLease
-      (const isc::dhcp::DuidPtr& duid, const isc::dhcp::OptionPtr& ia_pd,
-       boost::shared_ptr<isc::dhcp::Option6IAPrefix> prefix);
+    isc::dhcp::Lease6Ptr
+    checkPdLease(const isc::dhcp::DuidPtr& duid,
+                 const isc::dhcp::OptionPtr& ia_pd,
+                 boost::shared_ptr<isc::dhcp::Option6IAPrefix> prefix);
 
     /// @brief Creates a message with specified IA
     ///
@@ -761,18 +817,25 @@ public:
     /// @param stat_name this statistic is expected to be set to 1
     void testReceiveStats(uint8_t pkt_type, const std::string& stat_name);
 
+    /// @brief Set multi-threading mode.
+    void setMultiThreading(bool enabled) {
+        multi_threading_ = enabled;
+    }
 
-    /// A subnet used in most tests
+    /// A subnet used in most tests.
     isc::dhcp::Subnet6Ptr subnet_;
 
-    /// A normal, non-temporary pool used in most tests
+    /// A normal, non-temporary pool used in most tests.
     isc::dhcp::Pool6Ptr pool_;
 
-    /// A prefix pool used in most tests
+    /// A prefix pool used in most tests.
     isc::dhcp::Pool6Ptr pd_pool_;
 
     /// @brief Server object under test.
     NakedDhcpv6Srv srv_;
+
+    /// @brief The multi-threading flag.
+    bool multi_threading_;
 };
 
 /// @brief Patch the server config to add interface-config/re-detect=false
@@ -787,13 +850,35 @@ disableIfacesReDetect(isc::data::ConstElementPtr json) {
     }
 }
 
+/// @brief Patch the server config to add multi-threading/enable-multi-threading
+/// @param json the server config
+inline void
+configureMultiThreading(bool enabled, isc::data::ConstElementPtr json) {
+    isc::data::ConstElementPtr multi_threading = json->get("multi-threading");
+    if (!multi_threading) {
+        isc::data::ElementPtr mutable_cfg =
+                boost::const_pointer_cast<isc::data::Element>(json);
+        multi_threading = isc::data::Element::createMap();
+        mutable_cfg->set("multi-threading", multi_threading);
+    }
+
+    isc::data::ElementPtr mutable_cfg =
+        boost::const_pointer_cast<isc::data::Element>(multi_threading);
+    if (enabled) {
+        mutable_cfg->set("enable-multi-threading", isc::data::Element::create(true));
+        mutable_cfg->set("thread-pool-size", isc::data::Element::create(4));
+        mutable_cfg->set("packet-queue-size", isc::data::Element::create(4));
+    } else {
+        mutable_cfg->set("enable-multi-threading", isc::data::Element::create(false));
+    }
+}
+
 /// @brief Runs parser in JSON mode, useful for parser testing
 ///
 /// @param in string to be parsed
 /// @return ElementPtr structure representing parsed JSON
 inline isc::data::ElementPtr
-parseJSON(const std::string& in)
-{
+parseJSON(const std::string& in) {
     isc::dhcp::Parser6Context ctx;
     return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_JSON));
 }
@@ -807,8 +892,7 @@ parseJSON(const std::string& in)
 /// @param verbose display the exception message when it fails
 /// @return ElementPtr structure representing parsed JSON
 inline isc::data::ElementPtr
-parseDHCP6(const std::string& in, bool verbose = false)
-{
+parseDHCP6(const std::string& in, bool verbose = false) {
     try {
         isc::dhcp::Parser6Context ctx;
         isc::data::ElementPtr json;
@@ -832,8 +916,7 @@ parseDHCP6(const std::string& in, bool verbose = false)
 /// @param verbose display the exception message when it fails
 /// @return ElementPtr structure representing parsed JSON
 inline isc::data::ElementPtr
-parseOPTION_DEFS(const std::string& in, bool verbose = false)
-{
+parseOPTION_DEFS(const std::string& in, bool verbose = false) {
     try {
         isc::dhcp::Parser6Context ctx;
         return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEFS));
@@ -846,8 +929,8 @@ parseOPTION_DEFS(const std::string& in, bool verbose = false)
     }
 }
 
-}; // end of isc::dhcp::test namespace
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+} // end of isc::dhcp::test namespace
+} // end of isc::dhcp namespace
+} // end of isc namespace
 
 #endif // DHCP6_TEST_UTILS_H
index 88caa689920cb1d9eaf2f8ea6ad091d8fdc655b4..cd485eed9397ecde3693bdbd13b7ef3f362789fa 100644 (file)
@@ -242,17 +242,69 @@ public:
         isc::stats::StatsMgr::instance().removeAll();
     }
 
+    /// @brief Check that server processes correctly a prefix hint sent by the
+    /// client. This test checks that the server doesn't allocate colliding
+    /// prefixes as a result of receiving hints from two clients which set the
+    /// non-significant bytes of the prefix in their hints. The server should
+    /// zero the non-significant bytes of the hint and allocate the prefix of
+    /// the correct (configured) length.
+    void directClientPrefixHint();
+
+    /// @brief This test verifies that the same options can be specified on the
+    /// global level, subnet level and pool level. The options associated with
+    /// pools are used when the lease is handed out from these pools.
+    void optionsInheritance();
+
+    /// @brief This test verifies that it is possible to specify an excluded
+    /// prefix (RFC 6603) and send it back to the client requesting prefix
+    /// delegation.
+    void directClientExcludedPrefix();
+
+    /// @brief Check that when the client includes the Rapid Commit option in
+    /// its Solicit, the server responds with Reply and commits the lease.
+    void rapidCommitEnable();
+
+    /// @brief Check that the server responds with Advertise if the client
+    /// hasn't included the Rapid Commit option in the Solicit.
+    void rapidCommitNoOption();
+
+    /// @brief Check that when the Rapid Commit support is disabled for the
+    /// subnet the server replies with an Advertise and ignores the Rapid Commit
+    /// option sent by the client.
+    void rapidCommitDisable();
+
+    /// @brief This test verifies that regular Solicit/Adv/Request/Reply
+    /// exchange will result in appropriately set statistics.
+    void sarrStats();
+
+    /// @brief This test verifies that pkt6-receive-drop is increased properly
+    /// when the client's packet is rejected due to mismatched server-id value.
+    void pkt6ReceiveDropStat1();
+
+    /// @brief This test verifies that pkt6-receive-drop is increased properly
+    /// when the client's packet is rejected due to being unicast communication.
+    void pkt6ReceiveDropStat2();
+
+    /// @brief This test verifies that pkt6-receive-drop is increased properly
+    /// when the client's packet is rejected due to having too many client-id
+    /// options (exactly one is expected).
+    void pkt6ReceiveDropStat3();
+
+    /// @brief This test verifies that in pool reservations are ignored when the
+    /// reservations-out-of-pool flag is set to true.
+    void reservationModeOutOfPool();
+
+    /// @brief This test verifies that the in-pool reservation can be assigned
+    /// to a client not owning this reservation when the
+    /// reservations-out-of-pool flag is set to true.
+    void reservationIgnoredInOutOfPoolMode();
+
     /// @brief Interface Manager's fake configuration control.
     IfaceMgrTestConfig iface_mgr_test_config_;
 };
 
-/// Check that server processes correctly a prefix hint sent by the client.
-/// This test checks that the server doesn't allocate colliding prefixes
-/// as a result of receiving hints from two clients which set the
-/// non-significant bytes of the prefix in their hints. The server should zero
-/// the non-significant bytes of the hint and allocate the prefix of the
-/// correct (configured) length.
-TEST_F(SARRTest, directClientPrefixHint) {
+void
+SARRTest::directClientPrefixHint() {
     Dhcp6Client client;
     // Configure client to request IA_PD.
     client.requestPrefix();
@@ -306,10 +358,18 @@ TEST_F(SARRTest, directClientPrefixHint) {
     ASSERT_TRUE(lease_server);
 }
 
-// This test verifies that the same options can be specified on the global
-// level, subnet level and pool level. The options associated with pools
-// are used when the lease is handed out from these pools.
-TEST_F(SARRTest, optionsInheritance) {
+TEST_F(SARRTest, directClientPrefixHint) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    directClientPrefixHint();
+}
+
+TEST_F(SARRTest, directClientPrefixHintMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    directClientPrefixHint();
+}
+
+void
+SARRTest::optionsInheritance() {
     Dhcp6Client client;
     // Request a single address and single prefix.
     ASSERT_NO_THROW(client.requestPrefix(0xabac, 64, IOAddress("2001:db8:4::")));
@@ -367,9 +427,18 @@ TEST_F(SARRTest, optionsInheritance) {
     ASSERT_TRUE(client.hasOptionWithAddress(D6O_SNTP_SERVERS, "3000:2::2"));
 }
 
-/// This test verifies that it is possible to specify an excluded prefix
-/// (RFC 6603) and send it back to the client requesting prefix delegation.
-TEST_F(SARRTest, directClientExcludedPrefix) {
+TEST_F(SARRTest, optionsInheritance) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    optionsInheritance();
+}
+
+TEST_F(SARRTest, optionsInheritanceMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    optionsInheritance();
+}
+
+void
+SARRTest::directClientExcludedPrefix() {
     Dhcp6Client client;
     // Configure client to request IA_PD.
     client.requestPrefix();
@@ -408,9 +477,18 @@ TEST_F(SARRTest, directClientExcludedPrefix) {
     EXPECT_EQ(120, static_cast<unsigned>(pd_exclude->getExcludedPrefixLength()));
 }
 
-// Check that when the client includes the Rapid Commit option in its
-// Solicit, the server responds with Reply and commits the lease.
-TEST_F(SARRTest, rapidCommitEnable) {
+TEST_F(SARRTest, directClientExcludedPrefix) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    directClientExcludedPrefix();
+}
+
+TEST_F(SARRTest, directClientExcludedPrefixMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    directClientExcludedPrefix();
+}
+
+void
+SARRTest::rapidCommitEnable() {
     Dhcp6Client client;
     // Configure client to request IA_NA
     client.requestAddress();
@@ -446,9 +524,18 @@ TEST_F(SARRTest, rapidCommitEnable) {
     EXPECT_EQ(1, CfgMgr::instance().getD2ClientMgr().getQueueSize());
 }
 
-// Check that the server responds with Advertise if the client hasn't
-// included the Rapid Commit option in the Solicit.
-TEST_F(SARRTest, rapidCommitNoOption) {
+TEST_F(SARRTest, rapidCommitEnable) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    rapidCommitEnable();
+}
+
+TEST_F(SARRTest, rapidCommitEnableMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    rapidCommitEnable();
+}
+
+void
+SARRTest::rapidCommitNoOption() {
     Dhcp6Client client;
     // Configure client to request IA_NA
     client.requestAddress();
@@ -476,10 +563,18 @@ TEST_F(SARRTest, rapidCommitNoOption) {
     EXPECT_EQ(0, CfgMgr::instance().getD2ClientMgr().getQueueSize());
 }
 
-// Check that when the Rapid Commit support is disabled for the subnet
-// the server replies with an Advertise and ignores the Rapid Commit
-// option sent by the client.
-TEST_F(SARRTest, rapidCommitDisable) {
+TEST_F(SARRTest, rapidCommitNoOption) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    rapidCommitNoOption();
+}
+
+TEST_F(SARRTest, rapidCommitNoOptionMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    rapidCommitNoOption();
+}
+
+void
+SARRTest::rapidCommitDisable() {
     Dhcp6Client client;
     // The subnet assigned to eth1 has Rapid Commit disabled.
     client.setInterface("eth1");
@@ -511,9 +606,18 @@ TEST_F(SARRTest, rapidCommitDisable) {
     EXPECT_EQ(0, CfgMgr::instance().getD2ClientMgr().getQueueSize());
 }
 
-// This test verifies that regular Solicit/Adv/Request/Reply exchange will
-// result in appropriately set statistics.
-TEST_F(SARRTest, sarrStats) {
+TEST_F(SARRTest, rapidCommitDisable) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    rapidCommitDisable();
+}
+
+TEST_F(SARRTest, rapidCommitDisableMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    rapidCommitDisable();
+}
+
+void
+SARRTest::sarrStats() {
 
     // Let's use one of the existing configurations and tell the client to
     // ask for an address.
@@ -577,9 +681,18 @@ TEST_F(SARRTest, sarrStats) {
     EXPECT_EQ(2, pkt6_sent->getInteger().first);
 }
 
-// This test verifies that pkt6-receive-drop is increased properly when the
-// client's packet is rejected due to mismatched server-id value.
-TEST_F(SARRTest, pkt6ReceiveDropStat1) {
+TEST_F(SARRTest, sarrStats) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    sarrStats();
+}
+
+TEST_F(SARRTest, sarrStatsMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    sarrStats();
+}
+
+void
+SARRTest::pkt6ReceiveDropStat1() {
 
     // Dummy server-id (0xff repeated 10 times)
     std::vector<uint8_t> data(10, 0xff);
@@ -606,9 +719,18 @@ TEST_F(SARRTest, pkt6ReceiveDropStat1) {
     EXPECT_EQ(1, pkt6_recv_drop->getInteger().first);
 }
 
-// This test verifies that pkt6-receive-drop is increased properly when the
-// client's packet is rejected due to being unicast communication.
-TEST_F(SARRTest, pkt6ReceiveDropStat2) {
+TEST_F(SARRTest, pkt6ReceiveDropStat1) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    pkt6ReceiveDropStat1();
+}
+
+TEST_F(SARRTest, pkt6ReceiveDropStat1MultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    pkt6ReceiveDropStat1();
+}
+
+void
+SARRTest::pkt6ReceiveDropStat2() {
 
     // Let's use one of the existing configurations and tell the client to
     // ask for an address.
@@ -630,10 +752,18 @@ TEST_F(SARRTest, pkt6ReceiveDropStat2) {
     EXPECT_EQ(1, pkt6_recv_drop->getInteger().first);
 }
 
-// This test verifies that pkt6-receive-drop is increased properly when the
-// client's packet is rejected due to having too many client-id options
-// (exactly one is expected).
-TEST_F(SARRTest, pkt6ReceiveDropStat3) {
+TEST_F(SARRTest, pkt6ReceiveDropStat2) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    pkt6ReceiveDropStat2();
+}
+
+TEST_F(SARRTest, pkt6ReceiveDropStat2MultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    pkt6ReceiveDropStat2();
+}
+
+void
+SARRTest::pkt6ReceiveDropStat3() {
 
     // Let's use one of the existing configurations and tell the client to
     // ask for an address.
@@ -658,9 +788,18 @@ TEST_F(SARRTest, pkt6ReceiveDropStat3) {
     EXPECT_EQ(1, pkt6_recv_drop->getInteger().first);
 }
 
-// This test verifies that in pool reservations are ignored when the
-// reservations-out-of-pool flag is set to true.
-TEST_F(SARRTest, reservationModeOutOfPool) {
+TEST_F(SARRTest, pkt6ReceiveDropStat3) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    pkt6ReceiveDropStat3();
+}
+
+TEST_F(SARRTest, pkt6ReceiveDropStat3MultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    pkt6ReceiveDropStat3();
+}
+
+void
+SARRTest::reservationModeOutOfPool() {
     // Create the first client for which we have a reservation out of the
     // dynamic pool.
     Dhcp6Client client;
@@ -694,10 +833,18 @@ TEST_F(SARRTest, reservationModeOutOfPool) {
     ASSERT_EQ("2001:db8:1::3", lease.addr_.toText());
 }
 
-// This test verifies that the in-pool reservation can be assigned to a client
-// not owning this reservation when the reservations-out-of-pool flag is set to
-// true.
-TEST_F(SARRTest, reservationIgnoredInOutOfPoolMode) {
+TEST_F(SARRTest, reservationModeOutOfPool) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    reservationModeOutOfPool();
+}
+
+TEST_F(SARRTest, reservationModeOutOfPoolMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    reservationModeOutOfPool();
+}
+
+void
+SARRTest::reservationIgnoredInOutOfPoolMode() {
     // Create the first client for which we have a reservation out of the
     // dynamic pool.
     Dhcp6Client client;
@@ -716,4 +863,14 @@ TEST_F(SARRTest, reservationIgnoredInOutOfPoolMode) {
     ASSERT_EQ("2001:db8:1::5", lease.addr_.toText());
 }
 
+TEST_F(SARRTest, reservationIgnoredInOutOfPoolMode) {
+    Dhcpv6SrvMTTestGuard guard(*this, false);
+    reservationIgnoredInOutOfPoolMode();
+}
+
+TEST_F(SARRTest, reservationIgnoredInOutOfPoolModeMultiThreading) {
+    Dhcpv6SrvMTTestGuard guard(*this, true);
+    reservationIgnoredInOutOfPoolMode();
+}
+
 } // end of anonymous namespace