mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-05 00:15:17 +00:00
[#991] added multi-threading unittests for v6 server
This commit is contained in:
@@ -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
|
||||
|
@@ -456,8 +456,6 @@ Dhcpv4SrvTest::TearDown() {
|
||||
<< " class after the test. Exception has been caught: "
|
||||
<< ex.what();
|
||||
}
|
||||
|
||||
setMultiThreading(false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -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_;
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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));
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user