AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -Werror
AM_CXXFLAGS = $(KEA_CXXFLAGS)
/// This class must be inherited by scenario classes.
class AbstractScen : public boost::noncopyable {
public:
+ /// \brief Default and the only constructor of AbstractScen.
+ ///
+ /// \param options reference to command options,
+ /// \param socket reference to a socket.
+ AbstractScen(CommandOptions& options, BasePerfSocket &socket) :
+ options_(options),
+ tc_(options, socket) {};
+
/// \brief Run performance test.
///
/// Method runs whole performance test.
+ ///
+ /// \return execution status.
virtual int run() = 0;
/// \brief Trivial virtual destructor.
virtual ~AbstractScen() {};
protected:
+ CommandOptions& options_;
TestControl tc_; ///< Object for controling sending and receiving packets.
};
int
AvalancheScen::resendPackets(ExchangeType xchg_type) {
- CommandOptions& options = CommandOptions::instance();
const StatsMgr& stats_mgr(tc_.getStatsMgr());
// get list of sent packets that potentially need to be resent
total_resent_++;
// do resend packet
- if (options.getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
- IfaceMgr::instance().send(pkt4);
+ socket_.send(pkt4);
} else {
Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<Pkt6>(pkt);
- IfaceMgr::instance().send(pkt6);
+ socket_.send(pkt6);
}
// restore sending time of original packet
// and printed during runtime. The whole procedure is stopeed when
// all packets got reponses.
- CommandOptions& options = CommandOptions::instance();
-
- uint32_t clients_num = options.getClientsNum() == 0 ?
- 1 : options.getClientsNum();
+ uint32_t clients_num = options_.getClientsNum() == 0 ?
+ 1 : options_.getClientsNum();
StatsMgr& stats_mgr(tc_.getStatsMgr());
if (now - prev_cycle_time > milliseconds(200)) { // check if 0.2s elapsed
prev_cycle_time = now;
int still_left_cnt = 0;
- if (options.getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
still_left_cnt += resendPackets(ExchangeType::DO);
- still_left_cnt += resendPackets(ExchangeType::RA);
+ if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
+ still_left_cnt += resendPackets(ExchangeType::RA);
+ }
} else {
still_left_cnt += resendPackets(ExchangeType::SA);
- still_left_cnt += resendPackets(ExchangeType::RR);
+ if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
+ still_left_cnt += resendPackets(ExchangeType::RR);
+ }
}
if (still_left_cnt == 0) {
tc_.printStats();
// Print packet timestamps
- if (testDiags('t')) {
+ if (options_.testDiags('t')) {
stats_mgr.printTimestamps();
}
// Print server id.
- if (testDiags('s') && tc_.serverIdReceived()) {
+ if (options_.testDiags('s') && tc_.serverIdReceived()) {
std::cout << "Server id: " << tc_.getServerId() << std::endl;
}
// Diagnostics flag 'e' means show exit reason.
- if (testDiags('e')) {
+ if (options_.testDiags('e')) {
std::cout << "Interrupted" << std::endl;
}
+ // Calculate total stats.
+ int total_sent_pkts = total_resent_;
+ int total_rcvd_pkts = 0;
+ if (options_.getIpVersion() == 4) {
+ total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO);
+ total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO);
+ if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
+ total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA);
+ total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA);
+ }
+ } else {
+ total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA);
+ total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA);
+ if (options_.getExchangeMode() == CommandOptions::DORA_SARR) {
+ total_sent_pkts += tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR);
+ total_rcvd_pkts += tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR);
+ }
+ }
+
std::cout << "It took " << duration.length() << " to provision " << clients_num
- << " clients. " << (clients_num * 2 + total_resent_)
- << " packets were sent, " << total_resent_
- << " retransmissions needed, received " << (clients_num * 2)
- << " responses." << std::endl;
+ << " clients. " << std::endl
+ << "Requests sent + resent: " << total_sent_pkts << std::endl
+ << "Requests resent: " << total_resent_ << std::endl
+ << "Responses received: " << total_rcvd_pkts << std::endl;
return (0);
}
/// Full DORA and SARR message sequences are expected.
class AvalancheScen : public AbstractScen {
public:
- /// Default and the only constructor of AvalancheScen.
- AvalancheScen(): total_resent_(0) {};
+ /// \brief Default and the only constructor of AvalancheScen.
+ ///
+ /// \param options reference to command options,
+ /// \param socket reference to a socket.
+ AvalancheScen(CommandOptions& options, BasePerfSocket &socket):
+ AbstractScen(options, socket),
+ socket_(socket),
+ total_resent_(0) {};
/// brief\ Run performance test.
///
/// Method runs whole performance test.
- int run();
+ ///
+ /// \return execution status.
+ int run() override;
private:
+ // A reference to socket;
+ BasePerfSocket &socket_;
+
/// A map xchg type -> (a map of trans id -> retransmissions count.
std::unordered_map<ExchangeType, std::unordered_map<uint32_t, int>> retransmissions_;
/// A map xchg type -> (a map of trans id -> time of sending first packet.
/// Total number of resent packets.
int total_resent_;
- /// Resend packets for given exchange type that did not receive
+ /// \\brief Resend packets.
+ ///
+ /// It resends packets for given exchange type that did not receive
/// a response yet.
+ ///
+ /// \param xchg_type exchange type that should be looked for.
+ /// \return number of packets still waiting for resending.
int resendPackets(ExchangeType xchg_type);
};
const StatsMgr& stats_mgr(tc_.getStatsMgr());
- CommandOptions& options = CommandOptions::instance();
bool test_period_reached = false;
// Check if test period passed.
- if (options.getPeriod() != 0) {
+ if (options_.getPeriod() != 0) {
time_period period(stats_mgr.getTestPeriod());
- if (period.length().total_seconds() >= options.getPeriod()) {
+ if (period.length().total_seconds() >= options_.getPeriod()) {
test_period_reached = true;
}
}
if (test_period_reached) {
- if (testDiags('e')) {
+ if (options_.testDiags('e')) {
std::cout << "reached test-period." << std::endl;
}
if (!tc_.waitToExit()) {
bool max_requests = false;
// Check if we reached maximum number of DISCOVER/SOLICIT sent.
- if (options.getNumRequests().size() > 0) {
- if (options.getIpVersion() == 4) {
+ if (options_.getNumRequests().size() > 0) {
+ if (options_.getIpVersion() == 4) {
if (stats_mgr.getSentPacketsNum(ExchangeType::DO) >=
- options.getNumRequests()[0]) {
+ options_.getNumRequests()[0]) {
max_requests = true;
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if (stats_mgr.getSentPacketsNum(ExchangeType::SA) >=
- options.getNumRequests()[0]) {
+ options_.getNumRequests()[0]) {
max_requests = true;
}
}
}
// Check if we reached maximum number REQUEST packets.
- if (options.getNumRequests().size() > 1) {
- if (options.getIpVersion() == 4) {
+ if (options_.getNumRequests().size() > 1) {
+ if (options_.getIpVersion() == 4) {
if (stats_mgr.getSentPacketsNum(ExchangeType::RA) >=
- options.getNumRequests()[1]) {
+ options_.getNumRequests()[1]) {
max_requests = true;
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if (stats_mgr.getSentPacketsNum(ExchangeType::RR) >=
- options.getNumRequests()[1]) {
+ options_.getNumRequests()[1]) {
max_requests = true;
}
}
}
if (max_requests) {
- if (testDiags('e')) {
+ if (options_.testDiags('e')) {
std::cout << "Reached max requests limit." << std::endl;
}
if (!tc_.waitToExit()) {
// Check if we reached maximum number of drops of OFFER/ADVERTISE packets.
bool max_drops = false;
- if (options.getMaxDrop().size() > 0) {
- if (options.getIpVersion() == 4) {
+ if (options_.getMaxDrop().size() > 0) {
+ if (options_.getIpVersion() == 4) {
if (stats_mgr.getDroppedPacketsNum(ExchangeType::DO) >=
- options.getMaxDrop()[0]) {
+ options_.getMaxDrop()[0]) {
max_drops = true;
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if (stats_mgr.getDroppedPacketsNum(ExchangeType::SA) >=
- options.getMaxDrop()[0]) {
+ options_.getMaxDrop()[0]) {
max_drops = true;
}
}
}
// Check if we reached maximum number of drops of ACK/REPLY packets.
- if (options.getMaxDrop().size() > 1) {
- if (options.getIpVersion() == 4) {
+ if (options_.getMaxDrop().size() > 1) {
+ if (options_.getIpVersion() == 4) {
if (stats_mgr.getDroppedPacketsNum(ExchangeType::RA) >=
- options.getMaxDrop()[1]) {
+ options_.getMaxDrop()[1]) {
max_drops = true;
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if (stats_mgr.getDroppedPacketsNum(ExchangeType::RR) >=
- options.getMaxDrop()[1]) {
+ options_.getMaxDrop()[1]) {
max_drops = true;
}
}
}
if (max_drops) {
- if (testDiags('e')) {
+ if (options_.testDiags('e')) {
std::cout << "Reached maximum drops number." << std::endl;
}
if (!tc_.waitToExit()) {
// Check if we reached maximum drops percentage of OFFER/ADVERTISE packets.
bool max_pdrops = false;
- if (options.getMaxDropPercentage().size() > 0) {
- if (options.getIpVersion() == 4) {
+ if (options_.getMaxDropPercentage().size() > 0) {
+ if (options_.getIpVersion() == 4) {
if ((stats_mgr.getSentPacketsNum(ExchangeType::DO) > 10) &&
((100. * stats_mgr.getDroppedPacketsNum(ExchangeType::DO) /
stats_mgr.getSentPacketsNum(ExchangeType::DO)) >=
- options.getMaxDropPercentage()[0])) {
+ options_.getMaxDropPercentage()[0])) {
max_pdrops = true;
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if ((stats_mgr.getSentPacketsNum(ExchangeType::SA) > 10) &&
((100. * stats_mgr.getDroppedPacketsNum(ExchangeType::SA) /
stats_mgr.getSentPacketsNum(ExchangeType::SA)) >=
- options.getMaxDropPercentage()[0])) {
+ options_.getMaxDropPercentage()[0])) {
max_pdrops = true;
}
}
}
// Check if we reached maximum drops percentage of ACK/REPLY packets.
- if (options.getMaxDropPercentage().size() > 1) {
- if (options.getIpVersion() == 4) {
+ if (options_.getMaxDropPercentage().size() > 1) {
+ if (options_.getIpVersion() == 4) {
if ((stats_mgr.getSentPacketsNum(ExchangeType::RA) > 10) &&
((100. * stats_mgr.getDroppedPacketsNum(ExchangeType::RA) /
stats_mgr.getSentPacketsNum(ExchangeType::RA)) >=
- options.getMaxDropPercentage()[1])) {
+ options_.getMaxDropPercentage()[1])) {
max_pdrops = true;
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if ((stats_mgr.getSentPacketsNum(ExchangeType::RR) > 10) &&
((100. * stats_mgr.getDroppedPacketsNum(ExchangeType::RR) /
stats_mgr.getSentPacketsNum(ExchangeType::RR)) >=
- options.getMaxDropPercentage()[1])) {
+ options_.getMaxDropPercentage()[1])) {
max_pdrops = true;
}
}
}
if (max_pdrops) {
- if (testDiags('e')) {
+ if (options_.testDiags('e')) {
std::cout << "Reached maximum percentage of drops." << std::endl;
}
if (!tc_.waitToExit()) {
int
BasicScen::run() {
- CommandOptions& options = CommandOptions::instance();
-
- basic_rate_control_.setRate(options.getRate());
- renew_rate_control_.setRate(options.getRenewRate());
- release_rate_control_.setRate(options.getReleaseRate());
-
StatsMgr& stats_mgr(tc_.getStatsMgr());
// Preload server with the number of packets.
- if (options.getPreload() > 0) {
- tc_.sendPackets(options.getPreload(), true);
+ if (options_.getPreload() > 0) {
+ tc_.sendPackets(options_.getPreload(), true);
}
// Fork and run command specified with -w<wrapped-command>
- if (!options.getWrapped().empty()) {
+ if (!options_.getWrapped().empty()) {
tc_.runWrapped();
}
// Calculate number of packets to be sent to stay
// catch up with rate.
uint64_t packets_due = basic_rate_control_.getOutboundMessageCount();
- if ((packets_due == 0) && testDiags('i')) {
+ if ((packets_due == 0) && options_.testDiags('i')) {
stats_mgr.incrementCounter("shortwait");
}
// If there is nothing to do in this loop iteration then do some sleep to make
// CPU idle for a moment, to not consume 100% CPU all the time
// but only if it is not that high request rate expected.
- if (options.getRate() < 10000 && packets_due == 0 && pkt_count == 0) {
+ if (options_.getRate() < 10000 && packets_due == 0 && pkt_count == 0) {
/// @todo: need to implement adaptive time here, so the sleep time
/// is not fixed, but adjusts to current situation.
usleep(1);
// If -f<renew-rate> option was specified we have to check how many
// Renew packets should be sent to catch up with a desired rate.
- if (options.getRenewRate() != 0) {
+ if (options_.getRenewRate() != 0) {
uint64_t renew_packets_due =
renew_rate_control_.getOutboundMessageCount();
// Send multiple renews to satisfy the desired rate.
- if (options.getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
tc_.sendMultipleRequests(renew_packets_due);
} else {
tc_.sendMultipleMessages6(DHCPV6_RENEW, renew_packets_due);
// If -F<release-rate> option was specified we have to check how many
// Release messages should be sent to catch up with a desired rate.
- if ((options.getIpVersion() == 6) && (options.getReleaseRate() != 0)) {
+ if ((options_.getIpVersion() == 6) && (options_.getReleaseRate() != 0)) {
uint64_t release_packets_due =
release_rate_control_.getOutboundMessageCount();
// Send Release messages.
// Report delay means that user requested printing number
// of sent/received/dropped packets repeatedly.
- if (options.getReportDelay() > 0) {
+ if (options_.getReportDelay() > 0) {
tc_.printIntermediateStats();
}
tc_.printStats();
- if (!options.getWrapped().empty()) {
+ if (!options_.getWrapped().empty()) {
// true means that we execute wrapped command with 'stop' argument.
tc_.runWrapped(true);
}
// Print packet timestamps
- if (testDiags('t')) {
+ if (options_.testDiags('t')) {
stats_mgr.printTimestamps();
}
// Print server id.
- if (testDiags('s') && tc_.serverIdReceived()) {
+ if (options_.testDiags('s') && tc_.serverIdReceived()) {
std::cout << "Server id: " << tc_.getServerId() << std::endl;
}
// Diagnostics flag 'e' means show exit reason.
- if (testDiags('e')) {
+ if (options_.testDiags('e')) {
std::cout << "Interrupted" << std::endl;
}
// Print packet templates. Even if -T options have not been specified the
// dynamically build packet will be printed if at least one has been sent.
- if (testDiags('T')) {
+ if (options_.testDiags('T')) {
tc_.printTemplates();
}
/// is continuously loaded with DHCP messages according to given rate.
class BasicScen : public AbstractScen {
public:
- /// Default and the only constructor of BasicScen.
- BasicScen() {};
+ /// \brief Default and the only constructor of BasicScen.
+ ///
+ /// \param options reference to command options,
+ /// \param socket reference to a socket.
+ BasicScen(CommandOptions& options, BasePerfSocket &socket):
+ AbstractScen(options, socket)
+ {
+ basic_rate_control_.setRate(options_.getRate());
+ renew_rate_control_.setRate(options_.getRenewRate());
+ release_rate_control_.setRate(options_.getReleaseRate());
+ };
/// brief\ Run performance test.
///
///
/// \throw isc::InvalidOperation if command line options are not parsed.
/// \throw isc::Unexpected if internal Test Controller error occurred.
- /// \return error_code, 3 if number of received packets is not equal
- /// to number of sent packets, 0 if everything is ok.
- int run();
+ /// \return execution status.
+ int run() override;
-private:
+protected:
/// \brief A rate control class for Discover and Solicit messages.
RateControl basic_rate_control_;
/// \brief A rate control class for Renew messages.
}
}
-CommandOptions&
-CommandOptions::instance() {
- static CommandOptions options;
- return (options);
-}
-
void
CommandOptions::reset() {
// Default mac address used in DHCP messages
}
void
-CommandOptions::validate() const {
+CommandOptions::validate() {
check((getIpVersion() != 4) && (isBroadcast() != 0),
"-B is not compatible with IPv6 (-6)");
check((getIpVersion() != 6) && (isRapidCommit() != 0),
<< "WARNING: Better results are achieved when run in multi-threaded mode." << std::endl
<< "WARNING: To switch use -g multi option." << std::endl;
}
+
+ if (scenario_ == Scenario::AVALANCHE) {
+ check(getClientsNum() <= 0,
+ "in case of avalanche scenario number\nof clients must be specified"
+ " using -R option explicitly");
+
+ // in case of AVALANCHE drops ie. long responses should not be observed by perfdhcp
+ double dt[2] = { 1000.0, 1000.0 };
+ drop_time_.assign(dt, dt + 2);
+ if (drop_time_set_) {
+ std::cout << "INFO: in avalanche scenario drop time is ignored" << std::endl;
+ }
+ }
}
void
std::cout << "VERSION: " << VERSION << std::endl;
}
-bool
-testDiags(const char diag) {
- std::string diags(CommandOptions::instance().getDiags());
- if (diags.find(diag) != std::string::npos) {
- return (true);
- }
- return (false);
-}
-
} // namespace perfdhcp
} // namespace isc
class CommandOptions : public boost::noncopyable {
public:
+ /// \brief Default Constructor.
+ ///
+ /// Private constructor as this is a singleton class.
+ /// Use CommandOptions::instance() to get instance of it.
+ CommandOptions() {
+ reset();
+ }
+
/// @brief A vector holding MAC addresses.
typedef std::vector<std::vector<uint8_t> > MacAddrsVector;
DORA_SARR
};
- /// CommandOptions is a singleton class. This method returns reference
- /// to its sole instance.
- ///
- /// \return the only existing instance of command options
- static CommandOptions& instance();
-
/// \brief Reset to defaults
///
/// Reset data members to default values. This is specifically
/// \return server name.
std::string getServerName() const { return server_name_; }
+
+ /// \brief Find if diagnostic flag has been set.
+ ///
+ /// \param diag diagnostic flag (a,e,i,s,r,t,T).
+ /// \return true if diagnostics flag has been set.
+ bool testDiags(const char diag) {
+ if (getDiags().find(diag) != std::string::npos) {
+ return (true);
+ }
+ return (false);
+ }
+
/// \brief Print command line arguments.
void printCommandLine() const;
void version() const;
private:
-
- /// \brief Default Constructor.
- ///
- /// Private constructor as this is a singleton class.
- /// Use CommandOptions::instance() to get instance of it.
- CommandOptions() {
- reset();
- }
-
/// \brief Initializes class members based on the command line.
///
/// Reads each command line parameter and sets class member values.
/// \brief Validates initialized options.
///
/// \throws isc::InvalidParameter if command line validation fails.
- void validate() const;
+ void validate();
/// \brief Throws !InvalidParameter exception if condition is true.
///
Scenario scenario_;
};
-/// \brief Find if diagnostic flag has been set.
-///
-/// \param diag diagnostic flag (a,e,i,s,r,t,T).
-/// \return true if diagnostics flag has been set.
-bool
-testDiags(const char diag);
-
} // namespace perfdhcp
} // namespace isc
int
main(int argc, char* argv[]) {
- CommandOptions& command_options = CommandOptions::instance();
+ CommandOptions command_options;
std::string diags(command_options.getDiags());
int ret_code = 0;
try {
} catch(isc::Exception& e) {
ret_code = 1;
command_options.usage();
- std::cerr << "Error parsing command line options: "
+ std::cerr << "\nERROR: parsing command line options: "
<< e.what() << std::endl;
if (diags.find('e') != std::string::npos) {
std::cerr << "Fatal error" << std::endl;
}
try{
auto scenario = command_options.getScenario();
+ PerfSocket socket(command_options);
if (scenario == Scenario::BASIC) {
- BasicScen scen;
+ BasicScen scen(command_options, socket);
ret_code = scen.run();
} else if (scenario == Scenario::AVALANCHE) {
- AvalancheScen scen;
+ AvalancheScen scen(command_options, socket);
ret_code = scen.run();
}
} catch (std::exception& e) {
ret_code = 1;
- std::cerr << "Error running perfdhcp: " << e.what() << std::endl;
+ std::cerr << "\nERROR: running perfdhcp: " << e.what() << std::endl;
if (diags.find('e') != std::string::npos) {
std::cerr << "Fatal error" << std::endl;
}
namespace isc {
namespace perfdhcp {
-PerfSocket::PerfSocket() :
- SocketInfo(asiolink::IOAddress("127.0.0.1"), 0, openSocket()),
- ifindex_(0)
-{
+PerfSocket::PerfSocket(CommandOptions& options) {
+ sockfd_ = openSocket(options);
initSocketData();
}
int
-PerfSocket::openSocket() const {
- CommandOptions& options = CommandOptions::instance();
+PerfSocket::openSocket(CommandOptions& options) const {
std::string localname = options.getLocalName();
std::string servername = options.getServerName();
uint16_t port = options.getLocalPort();
isc_throw(BadValue, "interface for specified socket descriptor not found");
}
+Pkt4Ptr
+PerfSocket::receive4(uint32_t timeout_sec, uint32_t timeout_usec) {
+ Pkt4Ptr pkt = IfaceMgr::instance().receive4(timeout_sec, timeout_usec);
+ if (pkt) {
+ /// @todo: Add packet exception handling here. Right now any
+ /// malformed packet will cause perfdhcp to abort.
+ pkt->unpack();
+ }
+ return (pkt);
+}
+
+Pkt6Ptr
+PerfSocket::receive6(uint32_t timeout_sec, uint32_t timeout_usec) {
+ Pkt6Ptr pkt = IfaceMgr::instance().receive6(timeout_sec, timeout_usec);
+ if (pkt) {
+ /// @todo: Add packet exception handling here. Right now any
+ /// malformed packet will cause perfdhcp to abort.
+ pkt->unpack();
+ }
+ return (pkt);
+}
+
+bool
+PerfSocket::send(const Pkt4Ptr& pkt) {
+ return IfaceMgr::instance().send(pkt);
+}
+
+bool
+PerfSocket::send(const Pkt6Ptr& pkt) {
+ return IfaceMgr::instance().send(pkt);
+}
+
+IfacePtr
+PerfSocket::getIface() {
+ return (IfaceMgr::instance().getIface(ifindex_));
+}
+
}
}
#ifndef PERF_SOCKET_H
#define PERF_SOCKET_H
+#include <perfdhcp/command_options.h>
+
+#include <dhcp/pkt4.h>
+#include <dhcp/pkt6.h>
#include <dhcp/socket_info.h>
+#include <dhcp/iface_mgr.h>
namespace isc {
namespace perfdhcp {
+class BasePerfSocket : public dhcp::SocketInfo {
+public:
+ /// Interface index.
+ uint16_t ifindex_;
+
+ BasePerfSocket() :
+ SocketInfo(asiolink::IOAddress("127.0.0.1"), 0, 0),
+ ifindex_(0) {}
+
+ /// \brief Destructor of the socket wrapper class.
+ virtual ~BasePerfSocket() = default;
+
+ virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) = 0;
+ virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) = 0;
+ virtual bool send(const dhcp::Pkt4Ptr& pkt) = 0;
+ virtual bool send(const dhcp::Pkt6Ptr& pkt) = 0;
+ virtual dhcp::IfacePtr getIface() = 0;
+};
/// \brief Socket wrapper structure.
///
/// when exception occurs). This structure extends parent
/// structure with new field ifindex_ that holds interface
/// index where socket is bound to.
-struct PerfSocket : public dhcp::SocketInfo {
- /// Interface index.
- uint16_t ifindex_;
-
+class PerfSocket : public BasePerfSocket {
+public:
/// \brief Constructor of socket wrapper class.
///
/// This constructor uses provided socket descriptor to
/// find the name of the interface where socket has been
/// bound to.
- PerfSocket();
+ PerfSocket(CommandOptions& options);
/// \brief Destructor of the socket wrapper class.
///
/// Destructor closes wrapped socket.
virtual ~PerfSocket();
-private:
+ /// \brief Receive DHCPv4 packet from interface.
+ ///
+ /// \param timeout_sec number of seconds for waiting for a packet,
+ /// \param timeout_sec number of microseconds for waiting for a packet,
+ /// \return received packet or nullptr if timed out
+ virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override;
+
+ /// \brief Receive DHCPv6 packet from interface.
+ ///
+ /// \param timeout_sec number of seconds for waiting for a packet,
+ /// \param timeout_sec number of microseconds for waiting for a packet,
+ /// \return received packet or nullptr if timed out
+ virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override;
+
+ /// \brief Send DHCPv4 packet through interface.
+ ///
+ /// \param pkt a packet for sending
+ /// \return true if operation succeeded
+ virtual bool send(const dhcp::Pkt4Ptr& pkt) override;
+
+ /// \brief Send DHCPv6 packet through interface.
+ ///
+ /// \param pkt a packet for sending
+ /// \return true if operation succeeded
+ virtual bool send(const dhcp::Pkt6Ptr& pkt) override;
+
+ /// \brief Get interface from IfaceMgr.
+ ///
+ /// \return shared pointer to Iface.
+ virtual dhcp::IfacePtr getIface() override;
+
+protected:
/// \brief Initialize socket data.
///
/// This method initializes members of the class that Interface
/// for the v6 socket.
/// \throw isc::Unexpected if internal unexpected error occurred.
/// \return socket descriptor.
- int openSocket() const;
+ int openSocket(CommandOptions& options) const;
};
}
// In multi thread mode read packet from the queue which is feed by Receiver thread.
util::thread::Mutex::Locker lock(pkt_queue_mutex_);
if (pkt_queue_.empty()) {
- if (CommandOptions::instance().getIpVersion() == 4) {
+ if (ip_version_ == 4) {
return Pkt4Ptr();
} else {
return Pkt6Ptr();
timeout = 1000;
}
try {
- if (CommandOptions::instance().getIpVersion() == 4) {
- pkt = IfaceMgr::instance().receive4(0, timeout);
+ if (ip_version_ == 4) {
+ pkt = socket_.receive4(0, timeout);
} else {
- pkt = IfaceMgr::instance().receive6(0, timeout);
+ pkt = socket_.receive6(0, timeout);
}
} catch (const Exception& e) {
cerr << "Failed to receive DHCP packet: " << e.what() << endl;
}
- if (pkt) {
- /// @todo: Add packet exception handling here. Right now any
- /// malformed packet will cause perfdhcp to abort.
- pkt->unpack();
- }
-
return (pkt);
}
/// \brief Mutex for controlling access to the queue.
util::thread::Mutex pkt_queue_mutex_;
+ BasePerfSocket &socket_;
+
/// \brief Single- or thread-mode indicator.
bool single_threaded_;
+ uint8_t ip_version_;
+
public:
/// \brief Receiver constructor.
///
/// \param socket A socket for receiving packets.
- Receiver() :
- single_threaded_(CommandOptions::instance().isSingleThreaded()) {
+ /// \param single_threaded A flag indicating running mode.
+ /// \param ip_version An IP version: 4 or 6
+ Receiver(BasePerfSocket &socket, bool single_threaded, uint8_t ip_version) :
+ socket_(socket),
+ single_threaded_(single_threaded),
+ ip_version_(ip_version) {
}
/// \brief Destructor.
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <perfdhcp/stats_mgr.h>
-#include <perfdhcp/command_options.h>
namespace isc {
rcvd_time.is_not_a_date_time()) {
isc_throw(Unexpected,
"Timestamp must be set for sent and "
- "received packet to measure RTT");
+ "received packet to measure RTT,"
+ << " sent: " << sent_time
+ << " recv: " << rcvd_time);
}
boost::posix_time::time_period period(sent_time, rcvd_time);
// We don't bother calculating deltas in nanoseconds. It is much
}
}
-StatsMgr::StatsMgr() :
+StatsMgr::StatsMgr(CommandOptions& options) :
exchanges_(),
- boot_time_(boost::posix_time::microsec_clock::universal_time())
+ boot_time_(boost::posix_time::microsec_clock::universal_time()),
+ options_(options)
{
- CommandOptions& options = CommandOptions::instance();
-
// Check if packet archive mode is required. If user
// requested diagnostics option -x t we have to enable
// it so as StatsMgr preserves all packets.
- archive_enabled_ = testDiags('t') ? true : false;
+ archive_enabled_ = options.testDiags('t') ? true : false;
if (options.getIpVersion() == 4) {
addExchangeStats(ExchangeType::DO, options.getDropTime()[0]);
addExchangeStats(ExchangeType::RL);
}
}
- if (testDiags('i')) {
+ if (options.testDiags('i')) {
addCustomCounter("shortwait", "Short waits for packets");
}
}
#include <dhcp/pkt.h>
#include <exceptions/exceptions.h>
+#include <perfdhcp/command_options.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
/// the test. If this is not selected archiving should be disabled
/// for performance reasons and to avoid waste of memory for storing
/// large list of archived packets.
- StatsMgr();
+ StatsMgr(CommandOptions& options);
/// \brief Specify new exchange type.
///
bool archive_enabled_;
boost::posix_time::ptime boot_time_; ///< Time when test is started.
+
+ CommandOptions& options_;
};
/// Pointer to Statistics Manager;
bool
TestControl::waitToExit() const {
static ptime exit_time = ptime(not_a_date_time);
- CommandOptions& options = CommandOptions::instance();
- uint32_t wait_time = options.getExitWaitTime();
+ uint32_t wait_time = options_.getExitWaitTime();
// If we care and not all packets are in yet
if (wait_time && !haveAllPacketsBeenReceived()) {
bool
TestControl::haveAllPacketsBeenReceived() const {
- const CommandOptions& options = CommandOptions::instance();
- const uint8_t& ipversion = options.getIpVersion();
- const std::vector<int>& num_request = options.getNumRequests();
+ const uint8_t& ipversion = options_.getIpVersion();
+ const std::vector<int>& num_request = options_.getNumRequests();
const size_t& num_request_size = num_request.size();
if (num_request_size == 0) {
void
TestControl::cleanCachedPackets() {
- CommandOptions& options = CommandOptions::instance();
// When Renews are not sent, Reply packets are not cached so there
// is nothing to do.
- if (options.getRenewRate() == 0) {
+ if (options_.getRenewRate() == 0) {
return;
}
// since we want to randomize leases to be renewed so leave 5
// times more packets to randomize from.
/// @todo The cache size might be controlled from the command line.
- if (reply_storage_.size() > 5 * options.getRenewRate()) {
+ if (reply_storage_.size() > 5 * options_.getRenewRate()) {
reply_storage_.clear(reply_storage_.size() -
- 5 * options.getRenewRate());
+ 5 * options_.getRenewRate());
}
// Remember when we performed a cleanup for the last time.
// We want to do the next cleanup not earlier than in one second.
" for the copyIaOptions function");
}
// IA_NA
- if (CommandOptions::instance().getLeaseType()
+ if (options_.getLeaseType()
.includes(CommandOptions::LeaseType::ADDRESS)) {
OptionPtr option = pkt_from->getOption(D6O_IA_NA);
if (!option) {
pkt_to->addOption(option);
}
// IA_PD
- if (CommandOptions::instance().getLeaseType()
+ if (options_.getLeaseType()
.includes(CommandOptions::LeaseType::PREFIX)) {
OptionPtr option = pkt_from->getOption(D6O_IA_PD);
if (!option) {
std::vector<uint8_t>
TestControl::generateMacAddress(uint8_t& randomized) {
- CommandOptions& options = CommandOptions::instance();
-
- const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
+ const CommandOptions::MacAddrsVector& macs = options_.getMacsFromFile();
// if we are using the -M option return a random one from the list...
if (macs.size() > 0) {
uint16_t r = number_generator_();
} else {
// ... otherwise use the standard behavior
- uint32_t clients_num = options.getClientsNum();
+ uint32_t clients_num = options_.getClientsNum();
if (clients_num < 2) {
- return (options.getMacTemplate());
+ return (options_.getMacTemplate());
}
// Get the base MAC address. We are going to randomize part of it.
- std::vector<uint8_t> mac_addr(options.getMacTemplate());
+ std::vector<uint8_t> mac_addr(options_.getMacTemplate());
if (mac_addr.size() != HW_ETHER_LEN) {
isc_throw(BadValue, "invalid MAC address template specified");
}
std::vector<uint8_t>
TestControl::generateDuid(uint8_t& randomized) {
- CommandOptions& options = CommandOptions::instance();
std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
- const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
+ const CommandOptions::MacAddrsVector& macs = options_.getMacsFromFile();
// pick a random mac address if we are using option -M..
if (macs.size() > 0) {
uint16_t r = number_generator_();
std::copy(mac.begin(), mac.end(), duid.begin() + 4);
return (duid);
} else {
- uint32_t clients_num = options.getClientsNum();
+ uint32_t clients_num = options_.getClientsNum();
if ((clients_num == 0) || (clients_num == 1)) {
- return (options.getDuidTemplate());
+ return (options_.getDuidTemplate());
}
// Get the base DUID. We are going to randomize part of it.
- std::vector<uint8_t> duid(options.getDuidTemplate());
+ std::vector<uint8_t> duid(options_.getDuidTemplate());
/// @todo: add support for DUIDs of different sizes.
duid.resize(duid.size());
std::copy(mac_addr.begin(), mac_addr.end(),
int
TestControl::getElapsedTimeOffset() const {
- int elp_offset = CommandOptions::instance().getIpVersion() == 4 ?
+ int elp_offset = options_.getIpVersion() == 4 ?
DHCPV4_ELAPSED_TIME_OFFSET : DHCPV6_ELAPSED_TIME_OFFSET;
- if (CommandOptions::instance().getElapsedTimeOffset() > 0) {
- elp_offset = CommandOptions::instance().getElapsedTimeOffset();
+ if (options_.getElapsedTimeOffset() > 0) {
+ elp_offset = options_.getElapsedTimeOffset();
}
return (elp_offset);
}
int
TestControl::getRandomOffset(const int arg_idx) const {
- int rand_offset = CommandOptions::instance().getIpVersion() == 4 ?
+ int rand_offset = options_.getIpVersion() == 4 ?
DHCPV4_RANDOMIZATION_OFFSET : DHCPV6_RANDOMIZATION_OFFSET;
- if (CommandOptions::instance().getRandomOffset().size() > arg_idx) {
- rand_offset = CommandOptions::instance().getRandomOffset()[arg_idx];
+ if (options_.getRandomOffset().size() > arg_idx) {
+ rand_offset = options_.getRandomOffset()[arg_idx];
}
return (rand_offset);
}
int
TestControl::getRequestedIpOffset() const {
- int rip_offset = CommandOptions::instance().getIpVersion() == 4 ?
+ int rip_offset = options_.getIpVersion() == 4 ?
DHCPV4_REQUESTED_IP_OFFSET : DHCPV6_IA_NA_OFFSET;
- if (CommandOptions::instance().getRequestedIpOffset() > 0) {
- rip_offset = CommandOptions::instance().getRequestedIpOffset();
+ if (options_.getRequestedIpOffset() > 0) {
+ rip_offset = options_.getRequestedIpOffset();
}
return (rip_offset);
}
int
TestControl::getServerIdOffset() const {
- int srvid_offset = CommandOptions::instance().getIpVersion() == 4 ?
+ int srvid_offset = options_.getIpVersion() == 4 ?
DHCPV4_SERVERID_OFFSET : DHCPV6_SERVERID_OFFSET;
- if (CommandOptions::instance().getServerIdOffset() > 0) {
- srvid_offset = CommandOptions::instance().getServerIdOffset();
+ if (options_.getServerIdOffset() > 0) {
+ srvid_offset = options_.getServerIdOffset();
}
return (srvid_offset);
}
int
TestControl::getTransactionIdOffset(const int arg_idx) const {
- int xid_offset = CommandOptions::instance().getIpVersion() == 4 ?
+ int xid_offset = options_.getIpVersion() == 4 ?
DHCPV4_TRANSID_OFFSET : DHCPV6_TRANSID_OFFSET;
- if (CommandOptions::instance().getTransactionIdOffset().size() > arg_idx) {
- xid_offset = CommandOptions::instance().getTransactionIdOffset()[arg_idx];
+ if (options_.getTransactionIdOffset().size() > arg_idx) {
+ xid_offset = options_.getTransactionIdOffset()[arg_idx];
}
return (xid_offset);
}
template_packets_v4_.clear();
template_packets_v6_.clear();
template_buffers_.clear();
- CommandOptions& options = CommandOptions::instance();
- std::vector<std::string> template_files = options.getTemplateFiles();
+ std::vector<std::string> template_files = options_.getTemplateFiles();
for (std::vector<std::string>::const_iterator it = template_files.begin();
it != template_files.end(); ++it) {
readPacketTemplate(*it);
void
TestControl::sendPackets(const uint64_t packets_num,
const bool preload /* = false */) {
- CommandOptions& options = CommandOptions::instance();
for (uint64_t i = packets_num; i > 0; --i) {
- if (options.getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
// No template packets means that no -T option was specified.
// We have to build packets ourselves.
if (template_buffers_.empty()) {
void
TestControl::printDiagnostics() const {
- CommandOptions& options = CommandOptions::instance();
- if (testDiags('a')) {
+ if (options_.testDiags('a')) {
// Print all command line parameters.
- options.printCommandLine();
+ options_.printCommandLine();
// Print MAC and DUID.
- std::cout << "Set MAC to " << vector2Hex(options.getMacTemplate(), "::")
+ std::cout << "Set MAC to " << vector2Hex(options_.getMacTemplate(), "::")
<< std::endl;
- if (options.getDuidTemplate().size() > 0) {
- std::cout << "Set DUID to " << vector2Hex(options.getDuidTemplate()) << std::endl;
+ if (options_.getDuidTemplate().size() > 0) {
+ std::cout << "Set DUID to " << vector2Hex(options_.getDuidTemplate()) << std::endl;
}
}
}
TestControl::printTemplate(const uint8_t packet_type) const {
std::string hex_buf;
int arg_idx = 0;
- if (CommandOptions::instance().getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
if (packet_type == DHCPREQUEST) {
arg_idx = 1;
}
std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.getLength());
hex_buf = vector2Hex(buf);
}
- } else if (CommandOptions::instance().getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
if (packet_type == DHCPV6_REQUEST) {
arg_idx = 1;
}
void
TestControl::printTemplates() const {
- CommandOptions& options = CommandOptions::instance();
- if (options.getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
printTemplate(DHCPDISCOVER);
printTemplate(DHCPREQUEST);
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
printTemplate(DHCPV6_SOLICIT);
printTemplate(DHCPV6_REQUEST);
}
void
TestControl::printRate() const {
double rate = 0;
- CommandOptions& options = CommandOptions::instance();
std::string exchange_name = "4-way exchanges";
ExchangeType xchg_type = ExchangeType::DO;
- if (options.getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
xchg_type =
- options.getExchangeMode() == CommandOptions::DO_SA ?
+ options_.getExchangeMode() == CommandOptions::DO_SA ?
ExchangeType::DO : ExchangeType::RA;
if (xchg_type == ExchangeType::DO) {
exchange_name = "DISCOVER-OFFER";
}
- } else if (options.getIpVersion() == 6) {
+ } else if (options_.getIpVersion() == 6) {
xchg_type =
- options.getExchangeMode() == CommandOptions::DO_SA ?
+ options_.getExchangeMode() == CommandOptions::DO_SA ?
ExchangeType::SA : ExchangeType::RR;
if (xchg_type == ExchangeType::SA) {
- exchange_name = options.isRapidCommit() ? "Solicit-Reply" :
+ exchange_name = options_.isRapidCommit() ? "Solicit-Reply" :
"Solicit-Advertise";
}
}
std::ostringstream s;
s << "***Rate statistics***" << std::endl;
s << "Rate: " << rate << " " << exchange_name << "/second";
- if (options.getRate() > 0) {
- s << ", expected rate: " << options.getRate() << std::endl;
+ if (options_.getRate() > 0) {
+ s << ", expected rate: " << options_.getRate() << std::endl;
}
std::cout << s.str() << std::endl;
void
TestControl::printIntermediateStats() {
- CommandOptions& options = CommandOptions::instance();
- int delay = options.getReportDelay();
+ int delay = options_.getReportDelay();
ptime now = microsec_clock::universal_time();
time_period time_since_report(last_report_, now);
if (time_since_report.length().total_seconds() >= delay) {
TestControl::printStats() const {
printRate();
stats_mgr_.printStats();
- if (testDiags('i')) {
+ if (options_.testDiags('i')) {
stats_mgr_.printCustomCounters();
}
}
if (pkt4->getType() == DHCPOFFER) {
PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::DO, pkt4);
Pkt4Ptr discover_pkt4(boost::dynamic_pointer_cast<Pkt4>(pkt));
- CommandOptions::ExchangeMode xchg_mode =
- CommandOptions::instance().getExchangeMode();
+ CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
if (template_buffers_.size() < 2) {
sendRequest4(discover_pkt4, pkt4);
if (packet_type == DHCPV6_ADVERTISE) {
PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::SA, pkt6);
Pkt6Ptr solicit_pkt6(boost::dynamic_pointer_cast<Pkt6>(pkt));
- CommandOptions::ExchangeMode xchg_mode =
- CommandOptions::instance().getExchangeMode();
+ CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
/// @todo check whether received ADVERTISE packet is sane.
/// We might want to check if STATUS_CODE option is non-zero
PktPtr pkt;
while ((pkt = receiver_.getPkt())) {
pkt_count += 1;
- if (CommandOptions::instance().getIpVersion() == 4) {
+ if (options_.getIpVersion() == 4) {
Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
processReceivedPacket4(pkt4);
} else {
void
TestControl::registerOptionFactories() const {
- CommandOptions& options = CommandOptions::instance();
- switch(options.getIpVersion()) {
+ switch(options_.getIpVersion()) {
case 4:
registerOptionFactories4();
break;
interrupted_ = false;
}
-TestControl::TestControl() :
- number_generator_(0, CommandOptions::instance().getMacsFromFile().size())
+TestControl::TestControl(CommandOptions& options, BasePerfSocket &socket) :
+ number_generator_(0, options.getMacsFromFile().size()),
+ socket_(socket),
+ receiver_(socket, options.isSingleThreaded(), options.getIpVersion()),
+ stats_mgr_(options),
+ options_(options)
{
// Reset singleton state before test starts.
reset();
- CommandOptions& options = CommandOptions::instance();
// Ip version is not set ONLY in case the command options
// were not parsed. This surely means that parse() function
// was not called prior to starting the test. This is fatal
// error.
- if (options.getIpVersion() == 0) {
+ if (options_.getIpVersion() == 0) {
isc_throw(InvalidOperation,
"command options must be parsed before running a test");
- } else if (options.getIpVersion() == 4) {
+ } else if (options_.getIpVersion() == 4) {
// Turn off packet queueing.
IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, data::ElementPtr());
setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator()));
setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator(0x00FFFFFF)));
}
- uint32_t clients_num = options.getClientsNum() == 0 ?
- 1 : options.getClientsNum();
+ uint32_t clients_num = options_.getClientsNum() == 0 ?
+ 1 : options_.getClientsNum();
setMacAddrGenerator(NumberGeneratorPtr(new SequentialGenerator(clients_num)));
// Diagnostics are command line options mainly.
// Initialize packet templates.
initPacketTemplates();
// Initialize randomization seed.
- if (options.isSeeded()) {
- srandom(options.getSeed());
+ if (options_.isSeeded()) {
+ srandom(options_.getSeed());
} else {
// Seed with current time.
time_period duration(from_iso_string("20111231T235959"),
void
TestControl::runWrapped(bool do_stop /*= false */) const {
- CommandOptions& options = CommandOptions::instance();
- if (!options.getWrapped().empty()) {
+ if (!options_.getWrapped().empty()) {
pid_t pid = 0;
signal(SIGCHLD, handleChild);
pid = fork();
if (pid < 0) {
isc_throw(Unexpected, "unable to fork");
} else if (pid == 0) {
- execlp(options.getWrapped().c_str(),
+ execlp(options_.getWrapped().c_str(),
do_stop ? "stop" : "start",
NULL);
}
void
TestControl::saveFirstPacket(const Pkt4Ptr& pkt) {
- if (testDiags('T')) {
+ if (options_.testDiags('T')) {
if (template_packets_v4_.find(pkt->getType()) == template_packets_v4_.end()) {
template_packets_v4_[pkt->getType()] = pkt;
}
void
TestControl::saveFirstPacket(const Pkt6Ptr& pkt) {
- if (testDiags('T')) {
+ if (options_.testDiags('T')) {
if (template_packets_v6_.find(pkt->getType()) == template_packets_v6_.end()) {
template_packets_v6_[pkt->getType()] = pkt;
}
addExtraOpts(pkt4);
pkt4->pack();
- IfaceMgr::instance().send(pkt4);
+ socket_.send(pkt4);
if (!preload) {
stats_mgr_.passSentPacket(ExchangeType::DO, pkt4);
}
// Pack the input packet buffer to output buffer so as it can
// be sent to server.
pkt4->rawPack();
- IfaceMgr::instance().send(boost::static_pointer_cast<Pkt4>(pkt4));
+ socket_.send(boost::static_pointer_cast<Pkt4>(pkt4));
if (!preload) {
// Update packet stats.
stats_mgr_.passSentPacket(ExchangeType::DO,
msg->pack();
// And send it.
- IfaceMgr::instance().send(msg);
+ socket_.send(msg);
stats_mgr_.passSentPacket(ExchangeType::RNA, msg);
return (true);
}
msg->pack();
// And send it.
- IfaceMgr::instance().send(msg);
+ socket_.send(msg);
stats_mgr_.passSentPacket((msg_type == DHCPV6_RENEW ? ExchangeType::RN
: ExchangeType::RL), msg);
return (true);
// Use first flags indicates that we want to use the server
// id captured in first packet.
- if (CommandOptions::instance().isUseFirst() &&
+ if (options_.isUseFirst() &&
(first_packet_serverid_.size() > 0)) {
pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_SERVER_IDENTIFIER,
first_packet_serverid_));
pkt4->setSecs(static_cast<uint16_t>(elapsed_time / 1000));
// Prepare on wire data to send.
pkt4->pack();
- IfaceMgr::instance().send(pkt4);
+ socket_.send(pkt4);
stats_mgr_.passSentPacket(ExchangeType::RA, pkt4);
saveFirstPacket(pkt4);
}
size_t sid_offset = getServerIdOffset();
// Use first flags indicates that we want to use the server
// id captured in first packet.
- if (CommandOptions::instance().isUseFirst() &&
+ if (options_.isUseFirst() &&
(first_packet_serverid_.size() > 0)) {
boost::shared_ptr<LocalizedOption>
opt_serverid(new LocalizedOption(Option::V4,
// Prepare on-wire data.
pkt4->rawPack();
- IfaceMgr::instance().send(boost::static_pointer_cast<Pkt4>(pkt4));
+ socket_.send(boost::static_pointer_cast<Pkt4>(pkt4));
// Update packet stats.
stats_mgr_.passSentPacket(ExchangeType::RA,
boost::static_pointer_cast<Pkt4>(pkt4));
// Use first flags indicates that we want to use the server
// id captured in first packet.
- if (CommandOptions::instance().isUseFirst() &&
+ if (options_.isUseFirst() &&
(first_packet_serverid_.size() > 0)) {
pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID,
first_packet_serverid_));
// Prepare on-wire data.
pkt6->pack();
- IfaceMgr::instance().send(pkt6);
+ socket_.send(pkt6);
stats_mgr_.passSentPacket(ExchangeType::RR, pkt6);
saveFirstPacket(pkt6);
}
size_t sid_offset = getServerIdOffset();
// Use first flags indicates that we want to use the server
// id captured in first packet.
- if (CommandOptions::instance().isUseFirst() &&
+ if (options_.isUseFirst() &&
(first_packet_serverid_.size() > 0)) {
boost::shared_ptr<LocalizedOption>
opt_serverid(new LocalizedOption(Option::V6,
// Prepare on wire data.
pkt6->rawPack();
// Send packet.
- IfaceMgr::instance().send(pkt6);
+ socket_.send(pkt6);
// Update packet stats.
stats_mgr_.passSentPacket(ExchangeType::RR, pkt6);
// contents will be printed. Here we check if this packet has been already
// collected. If it hasn't we save this packet so as we can print its
// contents when test is finished.
- if (testDiags('T') &&
+ if (options_.testDiags('T') &&
(template_packets_v6_.find(DHCPV6_REQUEST) == template_packets_v6_.end())) {
template_packets_v6_[DHCPV6_REQUEST] = pkt6;
}
isc_throw(Unexpected, "failed to create SOLICIT packet");
}
pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
- if (CommandOptions::instance().isRapidCommit()) {
+ if (options_.isRapidCommit()) {
pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT));
}
pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
// IPv6 address (with IA_NA) or IPv6 prefix (IA_PD) or both.
// IA_NA
- if (CommandOptions::instance().getLeaseType()
- .includes(CommandOptions::LeaseType::ADDRESS)) {
+ if (options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
}
// IA_PD
- if (CommandOptions::instance().getLeaseType()
- .includes(CommandOptions::LeaseType::PREFIX)) {
+ if (options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
}
addExtraOpts(pkt6);
pkt6->pack();
- IfaceMgr::instance().send(pkt6);
+ socket_.send(pkt6);
if (!preload) {
stats_mgr_.passSentPacket(ExchangeType::SA, pkt6);
}
addExtraOpts(pkt6);
// Send solicit packet.
- IfaceMgr::instance().send(pkt6);
+ socket_.send(pkt6);
if (!preload) {
// Update packet stats.
stats_mgr_.passSentPacket(ExchangeType::SA, pkt6);
void
TestControl::setDefaults4(const Pkt4Ptr& pkt) {
- CommandOptions& options = CommandOptions::instance();
// Interface name.
- IfacePtr iface = IfaceMgr::instance().getIface(socket_.ifindex_);
+ IfacePtr iface = socket_.getIface();
if (iface == NULL) {
isc_throw(BadValue, "unable to find interface with given index");
}
// Local client's port (68)
pkt->setLocalPort(DHCP4_CLIENT_PORT);
// Server's port (67)
- if (options.getRemotePort()) {
- pkt->setRemotePort(options.getRemotePort());
+ if (options_.getRemotePort()) {
+ pkt->setRemotePort(options_.getRemotePort());
} else {
pkt->setRemotePort(DHCP4_SERVER_PORT);
}
// The remote server's name or IP.
- pkt->setRemoteAddr(IOAddress(options.getServerName()));
+ pkt->setRemoteAddr(IOAddress(options_.getServerName()));
// Set local address.
pkt->setLocalAddr(IOAddress(socket_.addr_));
// Set relay (GIADDR) address to local address.
void
TestControl::setDefaults6(const Pkt6Ptr& pkt) {
- CommandOptions& options = CommandOptions::instance();
// Interface name.
- IfacePtr iface = IfaceMgr::instance().getIface(socket_.ifindex_);
+ IfacePtr iface = socket_.getIface();
if (iface == NULL) {
isc_throw(BadValue, "unable to find interface with given index");
}
// Local client's port (547)
pkt->setLocalPort(DHCP6_CLIENT_PORT);
// Server's port (548)
- if (options.getRemotePort()) {
- pkt->setRemotePort(options.getRemotePort());
+ if (options_.getRemotePort()) {
+ pkt->setRemotePort(options_.getRemotePort());
} else {
pkt->setRemotePort(DHCP6_SERVER_PORT);
}
// Set local address.
pkt->setLocalAddr(socket_.addr_);
// The remote server's name or IP.
- pkt->setRemoteAddr(IOAddress(options.getServerName()));
+ pkt->setRemoteAddr(IOAddress(options_.getServerName()));
// only act as a relay agent when told so.
/// @todo: support more level of encapsulation, at the moment we only support
/// one, via -A1 option.
- if (options.isUseRelayedV6()) {
+ if (options_.isUseRelayedV6()) {
Pkt6::RelayInfo relay_info;
relay_info.msg_type_ = DHCPV6_RELAY_FORW;
relay_info.hop_count_ = 1;
void
TestControl::addExtraOpts(const Pkt4Ptr& pkt) {
// All all extra options that the user may have specified
- CommandOptions& options = CommandOptions::instance();
- const dhcp::OptionCollection& extra_opts = options.getExtraOpts();
+ const dhcp::OptionCollection& extra_opts = options_.getExtraOpts();
for (auto entry : extra_opts) {
pkt->addOption(entry.second);
}
void
TestControl::addExtraOpts(const Pkt6Ptr& pkt) {
// All all extra options that the user may have specified
- CommandOptions& options = CommandOptions::instance();
- const dhcp::OptionCollection& extra_opts = options.getExtraOpts();
+ const dhcp::OptionCollection& extra_opts = options_.getExtraOpts();
for (auto entry : extra_opts) {
pkt->addOption(entry.second);
}
#include <perfdhcp/rate_control.h>
#include <perfdhcp/stats_mgr.h>
#include <perfdhcp/receiver.h>
+#include <perfdhcp/command_options.h>
+#include <perfdhcp/perf_socket.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/dhcp6.h>
class TestControl : public boost::noncopyable {
public:
/// \brief Default constructor.
- TestControl();
+ TestControl(CommandOptions& options, BasePerfSocket &socket);
/// Packet template buffer.
typedef std::vector<uint8_t> TemplateBuffer;
/// spaces or hexadecimal digits.
void readPacketTemplate(const std::string& file_name);
- PerfSocket socket_;
+ BasePerfSocket &socket_;
Receiver receiver_;
boost::posix_time::ptime last_report_; ///< Last intermediate report time.
std::map<uint8_t, dhcp::Pkt6Ptr> template_packets_v6_;
static bool interrupted_; ///< Is program interrupted.
+
+ CommandOptions& options_;
};
} // namespace perfdhcp
AM_CPPFLAGS += -I$(srcdir)/.. -I$(builddir)/..
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\"
AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -Werror
AM_CXXFLAGS = $(KEA_CXXFLAGS)
if USE_STATIC_LINK
run_unittests_SOURCES += stats_mgr_unittest.cc
run_unittests_SOURCES += test_control_unittest.cc
run_unittests_SOURCES += receiver_unittest.cc
+run_unittests_SOURCES += perf_socket_unittest.cc
+run_unittests_SOURCES += basic_scen_unittest.cc
+run_unittests_SOURCES += avalanche_scen_unittest.cc
run_unittests_SOURCES += command_options_helper.h
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
--- /dev/null
+// Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include "command_options_helper.h"
+#include "../avalanche_scen.h"
+
+#include <asiolink/io_address.h>
+#include <exceptions/exceptions.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/iface_mgr.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/foreach.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <stdint.h>
+#include <string>
+#include <fstream>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace boost::posix_time;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::perfdhcp;
+
+/// \brief FakeScenPerfSocket class that mocks PerfSocket.
+///
+/// It stubs send and receive operations and collects statistics.
+/// Beside that it simulates DHCP server responses for received
+/// packets.
+class FakeScenPerfSocket: public BasePerfSocket {
+public:
+ /// \brief Default constructor for FakeScenPerfSocket.
+ FakeScenPerfSocket(CommandOptions &opt) :
+ opt_(opt),
+ iface_(boost::make_shared<Iface>("fake", 0)),
+ sent_cnt_(0),
+ recv_cnt_(0) {};
+
+ CommandOptions &opt_;
+
+ IfacePtr iface_; ///< Local fake interface.
+
+ int sent_cnt_; ///< Counter of sent packets.
+ int recv_cnt_; ///< Counter of received packets.
+
+ /// List of pairs <msg_type, trans_id> containing responses
+ /// planned to send to perfdhcp.
+ std::list<std::tuple<uint8_t, uint32_t>> planned_responses_;
+
+ /// \brief Simulate receiving DHCPv4 packet.
+ virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override {
+ (void)timeout_sec; // silence compile 'unused parameter' warning;
+ (void)timeout_usec; // silence compile 'unused parameter' warning;
+ recv_cnt_++;
+
+ if (planned_responses_.empty()) {
+ return Pkt4Ptr();
+ }
+ auto msg = planned_responses_.front();
+ planned_responses_.pop_front();
+ auto msg_type = std::get<0>(msg);
+ Pkt4Ptr pkt(new Pkt4(msg_type, std::get<1>(msg)));
+ OptionPtr opt_serverid = Option::factory(Option::V4,
+ DHO_DHCP_SERVER_IDENTIFIER,
+ OptionBuffer(4, 1));
+ pkt->setYiaddr(asiolink::IOAddress("127.0.0.1"));
+ pkt->addOption(opt_serverid);
+ pkt->updateTimestamp();
+ return (pkt);
+ };
+
+ /// \brief Simulate receiving DHCPv6 packet.
+ virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override {
+ (void)timeout_sec; // silence compile 'unused parameter' warning;
+ (void)timeout_usec; // silence compile 'unused parameter' warning;
+ recv_cnt_++;
+
+ if (planned_responses_.empty()) {
+ return Pkt6Ptr();
+ }
+ auto msg = planned_responses_.front();
+ planned_responses_.pop_front();
+ auto msg_type = std::get<0>(msg);
+ Pkt6Ptr pkt(new Pkt6(msg_type, std::get<1>(msg)));
+ // Add IA_NA if requested by the client.
+ if (opt_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
+ OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+ pkt->addOption(opt_ia_na);
+ }
+ // Add IA_PD if requested by the client.
+ if (opt_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
+ OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+ pkt->addOption(opt_ia_pd);
+ }
+ OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
+ std::vector<uint8_t> duid({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
+ OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
+ pkt->addOption(opt_serverid);
+ pkt->addOption(opt_clientid);
+ pkt->updateTimestamp();
+ return (pkt);
+ };
+
+ /// \brief Simulate sending DHCPv4 packet.
+ virtual bool send(const dhcp::Pkt4Ptr& pkt) override {
+ sent_cnt_++;
+ pkt->updateTimestamp();
+ if (pkt->getType() == DHCPDISCOVER) {
+ planned_responses_.push_back(std::make_tuple(DHCPOFFER, pkt->getTransid()));
+ } else if (pkt->getType() == DHCPREQUEST) {
+ planned_responses_.push_back(std::make_tuple(DHCPACK, pkt->getTransid()));
+ } else {
+ assert(0);
+ }
+ return true;
+ };
+
+ /// \brief Simulate sending DHCPv6 packet.
+ virtual bool send(const dhcp::Pkt6Ptr& pkt) override {
+ sent_cnt_++;
+ pkt->updateTimestamp();
+ if (pkt->getType() == DHCPV6_SOLICIT) {
+ planned_responses_.push_back(std::make_tuple(DHCPV6_ADVERTISE, pkt->getTransid()));
+ } else if (pkt->getType() == DHCPV6_REQUEST) {
+ planned_responses_.push_back(std::make_tuple(DHCPV6_REPLY, pkt->getTransid()));
+ } else {
+ assert(0);
+ }
+ return true;
+ };
+
+ /// \brief Override getting interface.
+ virtual IfacePtr getIface() override { return iface_; }
+
+ void reset() {
+ sent_cnt_ = 0;
+ recv_cnt_ = 0;
+ }
+};
+
+
+/// \brief NakedAvalancheScen class.
+///
+/// It exposes AvalancheScen internals for UT.
+class NakedAvalancheScen: public AvalancheScen {
+public:
+ using AvalancheScen::tc_;
+
+ FakeScenPerfSocket fake_sock_;
+
+ NakedAvalancheScen(CommandOptions &opt) : AvalancheScen(opt, fake_sock_), fake_sock_(opt) {};
+
+};
+
+
+/// \brief Test Fixture Class
+///
+/// This test fixture class is used to perform
+/// unit tests on perfdhcp AvalancheScenTest class.
+class AvalancheScenTest : public virtual ::testing::Test
+{
+public:
+ AvalancheScenTest() { }
+
+ /// \brief Parse command line string with CommandOptions.
+ ///
+ /// \param cmdline command line string to be parsed.
+ /// \throw isc::Unexpected if unexpected error occurred.
+ /// \throw isc::InvalidParameter if command line is invalid.
+ void processCmdLine(CommandOptions &opt, const std::string& cmdline) const {
+ CommandOptionsHelper::process(opt, cmdline);
+ }
+
+ /// \brief Get full path to a file in testdata directory.
+ ///
+ /// \param filename filename being appended to absolute
+ /// path to testdata directory
+ ///
+ /// \return full path to a file in testdata directory.
+ std::string getFullPath(const std::string& filename) const {
+ std::ostringstream stream;
+ stream << TEST_DATA_DIR << "/" << filename;
+ return (stream.str());
+ }
+};
+
+
+TEST_F(AvalancheScenTest, Packet4Exchange) {
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -4 -R 10 --scenario avalanche -g single 127.0.0.1");
+ NakedAvalancheScen as(opt);
+
+ as.run();
+
+ EXPECT_EQ(as.fake_sock_.sent_cnt_, 20); // Discovery + Request
+ EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10);
+ EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10);
+ EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 10);
+ EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 10);
+}
+
+
+TEST_F(AvalancheScenTest, Packet4ExchangeOnlyDO) {
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -4 -R 10 -i --scenario avalanche -g single 127.0.0.1");
+ NakedAvalancheScen as(opt);
+
+ as.run();
+
+ EXPECT_EQ(as.fake_sock_.sent_cnt_, 10); // Discovery + Request
+ EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10);
+ EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10);
+ EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 0);
+ EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 0);
+}
+
+
+TEST_F(AvalancheScenTest, Packet6Exchange) {
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -6 -R 10 --scenario avalanche -g single -R 20 -L 10547 ::1");
+ NakedAvalancheScen as(opt);
+
+ as.run();
+
+ EXPECT_GE(as.fake_sock_.sent_cnt_, 20); // Solicit + Request
+ EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10);
+ EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10);
+ EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 10);
+ EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 10);
+}
+
+
+TEST_F(AvalancheScenTest, Packet6ExchangeOnlySA) {
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -6 -R 10 -i --scenario avalanche -g single -R 20 -L 10547 ::1");
+ NakedAvalancheScen as(opt);
+
+ as.run();
+
+ EXPECT_GE(as.fake_sock_.sent_cnt_, 10); // Solicit + Request
+ EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10);
+ EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10);
+ EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 0);
+ EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 0);
+}
--- /dev/null
+// Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include "command_options_helper.h"
+#include "../basic_scen.h"
+
+#include <asiolink/io_address.h>
+#include <exceptions/exceptions.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/iface_mgr.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/foreach.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <stdint.h>
+#include <string>
+#include <fstream>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace boost::posix_time;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::perfdhcp;
+
+/// \brief FakeScenPerfSocket class that mocks PerfSocket.
+///
+/// It stubs send and receive operations and collects statistics.
+/// Beside that it simulates DHCP server responses for received
+/// packets.
+class FakeScenPerfSocket: public BasePerfSocket {
+public:
+ /// \brief Default constructor for FakeScenPerfSocket.
+ FakeScenPerfSocket(CommandOptions &opt) :
+ opt_(opt),
+ iface_(boost::make_shared<Iface>("fake", 0)),
+ sent_cnt_(0),
+ recv_cnt_(0),
+ start_dropping_after_cnt_(100000) {};
+
+ CommandOptions &opt_;
+
+ IfacePtr iface_; ///< Local fake interface.
+
+ int sent_cnt_; ///< Counter of sent packets.
+ int recv_cnt_; ///< Counter of received packets.
+
+ /// List of pairs <msg_type, trans_id> containing responses
+ /// planned to send to perfdhcp.
+ std::list<std::tuple<uint8_t, uint32_t>> planned_responses_;
+
+ /// Limit for sent packets. After this limit not more packets
+ /// are sent. This simulate dropping responses.
+ int start_dropping_after_cnt_;
+
+ /// \brief Simulate receiving DHCPv4 packet.
+ virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override {
+ (void)timeout_sec; // silence compile 'unused parameter' warning;
+ (void)timeout_usec; // silence compile 'unused parameter' warning;
+ recv_cnt_++;
+
+ if (planned_responses_.empty() || sent_cnt_ >= start_dropping_after_cnt_) {
+ return Pkt4Ptr();
+ }
+ auto msg = planned_responses_.front();
+ planned_responses_.pop_front();
+ auto msg_type = std::get<0>(msg);
+ Pkt4Ptr pkt(new Pkt4(msg_type, std::get<1>(msg)));
+ OptionPtr opt_serverid = Option::factory(Option::V4,
+ DHO_DHCP_SERVER_IDENTIFIER,
+ OptionBuffer(4, 1));
+ pkt->setYiaddr(asiolink::IOAddress("127.0.0.1"));
+ pkt->addOption(opt_serverid);
+ pkt->updateTimestamp();
+ return (pkt);
+ };
+
+ /// \brief Simulate receiving DHCPv6 packet.
+ virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override {
+ (void)timeout_sec; // silence compile 'unused parameter' warning;
+ (void)timeout_usec; // silence compile 'unused parameter' warning;
+ recv_cnt_++;
+
+ if (planned_responses_.empty() || sent_cnt_ >= start_dropping_after_cnt_) {
+ return Pkt6Ptr();
+ }
+ auto msg = planned_responses_.front();
+ planned_responses_.pop_front();
+ auto msg_type = std::get<0>(msg);
+ Pkt6Ptr pkt(new Pkt6(msg_type, std::get<1>(msg)));
+ // Add IA_NA if requested by the client.
+ if (opt_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
+ OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+ pkt->addOption(opt_ia_na);
+ }
+ // Add IA_PD if requested by the client.
+ if (opt_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
+ OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+ pkt->addOption(opt_ia_pd);
+ }
+ OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
+ std::vector<uint8_t> duid({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
+ OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
+ pkt->addOption(opt_serverid);
+ pkt->addOption(opt_clientid);
+ pkt->updateTimestamp();
+ return (pkt);
+ };
+
+ /// \brief Simulate sending DHCPv4 packet.
+ virtual bool send(const dhcp::Pkt4Ptr& pkt) override {
+ sent_cnt_++;
+ pkt->updateTimestamp();
+ if (sent_cnt_ >= start_dropping_after_cnt_) {
+ return true;
+ }
+ if (pkt->getType() == DHCPDISCOVER) {
+ planned_responses_.push_back(std::make_tuple(DHCPOFFER, pkt->getTransid()));
+ } else if (pkt->getType() == DHCPREQUEST) {
+ planned_responses_.push_back(std::make_tuple(DHCPACK, pkt->getTransid()));
+ } else {
+ assert(0);
+ }
+ return true;
+ };
+
+ /// \brief Simulate sending DHCPv6 packet.
+ virtual bool send(const dhcp::Pkt6Ptr& pkt) override {
+ sent_cnt_++;
+ pkt->updateTimestamp();
+ if (sent_cnt_ >= start_dropping_after_cnt_) {
+ return true;
+ }
+ if (pkt->getType() == DHCPV6_SOLICIT) {
+ planned_responses_.push_back(std::make_tuple(DHCPV6_ADVERTISE, pkt->getTransid()));
+ } else if (pkt->getType() == DHCPV6_REQUEST) {
+ planned_responses_.push_back(std::make_tuple(DHCPV6_REPLY, pkt->getTransid()));
+ } else {
+ assert(0);
+ }
+ return true;
+ };
+
+ /// \brief Override getting interface.
+ virtual IfacePtr getIface() override { return iface_; }
+
+ void reset() {
+ sent_cnt_ = 0;
+ recv_cnt_ = 0;
+ }
+};
+
+
+/// \brief NakedBasicScen class.
+///
+/// It exposes BasicScen internals for UT.
+class NakedBasicScen: public BasicScen {
+public:
+ using BasicScen::basic_rate_control_;
+ using BasicScen::renew_rate_control_;
+ using BasicScen::release_rate_control_;
+ using BasicScen::tc_;
+
+ FakeScenPerfSocket fake_sock_;
+
+ NakedBasicScen(CommandOptions &opt) : BasicScen(opt, fake_sock_), fake_sock_(opt) {};
+
+};
+
+
+/// \brief Test Fixture Class
+///
+/// This test fixture class is used to perform
+/// unit tests on perfdhcp BasicScenTest class.
+class BasicScenTest : public virtual ::testing::Test
+{
+public:
+ BasicScenTest() { }
+
+ /// \brief Parse command line string with CommandOptions.
+ ///
+ /// \param cmdline command line string to be parsed.
+ /// \throw isc::Unexpected if unexpected error occurred.
+ /// \throw isc::InvalidParameter if command line is invalid.
+ void processCmdLine(CommandOptions &opt, const std::string& cmdline) const {
+ CommandOptionsHelper::process(opt, cmdline);
+ }
+
+ /// \brief Get full path to a file in testdata directory.
+ ///
+ /// \param filename filename being appended to absolute
+ /// path to testdata directory
+ ///
+ /// \return full path to a file in testdata directory.
+ std::string getFullPath(const std::string& filename) const {
+ std::ostringstream stream;
+ stream << TEST_DATA_DIR << "/" << filename;
+ return (stream.str());
+ }
+};
+
+
+// This test verifies that the class members are reset to expected values.
+TEST_F(BasicScenTest, initial_settings) {
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -6 -l ethx -r 50 -f 30 -F 10 all");
+ NakedBasicScen bs(opt);
+
+ EXPECT_EQ(50, bs.basic_rate_control_.getRate());
+ EXPECT_EQ(30, bs.renew_rate_control_.getRate());
+ EXPECT_EQ(10, bs.release_rate_control_.getRate());
+}
+
+
+TEST_F(BasicScenTest, Packet4Exchange) {
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -r 100 -n 10 -g single 127.0.0.1");
+ NakedBasicScen bs(opt);
+ bs.run();
+ // The command line restricts the number of iterations to 10
+ // with -n 10 parameter.
+ EXPECT_GE(bs.fake_sock_.sent_cnt_, 20); // Discovery + Request
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10);
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10);
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 10);
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 10);
+}
+
+
+TEST_F(BasicScenTest, Packet4ExchangeMaxDrop10Proc) {
+ CommandOptions opt;
+
+ // With the following command line we restrict the maximum
+ // number of dropped packets to 10% of all.
+ // Use templates for this test.
+ processCmdLine(opt, "perfdhcp -l fake -r 100 -R 20 -n 100"
+ " -D 10% -L 10547 -g single"
+ // TODO: seems to be broken as it crashes building pkt
+ // " -T " + getFullPath("discover-example.hex")
+ // + " -T " + getFullPath("request4-example.hex")
+ " 127.0.0.1");
+ // The number iterations is restricted by the percentage of
+ // dropped packets (-D 10%).
+ NakedBasicScen bs(opt);
+ bs.fake_sock_.start_dropping_after_cnt_ = 10;
+ bs.run();
+ EXPECT_GE(bs.fake_sock_.sent_cnt_, 15); // Discovery + Request
+ EXPECT_LE(bs.fake_sock_.sent_cnt_, 20); // Discovery + Request
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 15);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 15);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 15);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 15);
+}
+
+
+TEST_F(BasicScenTest, Packet6Exchange) {
+ // Set number of iterations to 10.
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -6 -r 100 -n 10 -g single -R 20 -L 10547 ::1");
+ // Set number of received packets equal to number of iterations.
+ // This simulates no packet drops.
+ NakedBasicScen bs(opt);
+ bs.run();
+ EXPECT_GE(bs.fake_sock_.sent_cnt_, 20); // Solicit + Request
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10);
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10);
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 10);
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 10);
+}
+
+TEST_F(BasicScenTest, Packet6ExchangeMaxDrop3Pkt) {
+ CommandOptions opt;
+ // The maximum number of dropped packets is 3 (because of -D 3).
+ processCmdLine(opt, "perfdhcp -l fake"
+ " -6 -r 100 -n 100 -R 20 -D 3 -L 10547"
+ // TODO: seems to be broken as it crashes building pkt
+ // " -T " + getFullPath("solicit-example.hex")
+ // + " -T " + getFullPath("request6-example.hex")
+ " ::1");
+
+ // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
+ // The test function generates server's responses and passes it to the
+ // TestControl class methods for processing. The number of exchanges
+ // actually performed is controller by 'start_dropping_after_cnt_'.
+ // All exchanged packets carry the IA_NA option
+ // to simulate the IPv6 address acquisition and to verify that the
+ // IA_NA options returned by the server are processed correctly.
+ NakedBasicScen bs(opt);
+ bs.fake_sock_.start_dropping_after_cnt_ = 10;
+ bs.run();
+ EXPECT_GE(bs.fake_sock_.sent_cnt_, 10);
+ EXPECT_LE(bs.fake_sock_.sent_cnt_, 20);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 15);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 15);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 15);
+
+ EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 1);
+ EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 15);
+}
///
/// \param cmdline command line provided as single string.
/// \return true if program has been run in help or version mode ('h' or 'v' flag).
- static bool process(const std::string& cmdline) {
- CommandOptions& opt = CommandOptions::instance();
+ static bool process(CommandOptions& opt, const std::string& cmdline) {
int argc = 0;
char** argv = tokenizeString(cmdline, argc);
ArgvPtr args(argv, argc);
/// \param cmdline Command line to parse.
/// \throws std::bad allocation if tokenization failed.
/// \return true if program has been run in help or version mode ('h' or 'v' flag).
- bool process(const std::string& cmdline) {
- return (CommandOptionsHelper::process(cmdline));
+ bool process(CommandOptions& opt, const std::string& cmdline) {
+ return (CommandOptionsHelper::process(opt, cmdline));
}
/// \brief Get full path to a file in testdata directory.
stream << TEST_DATA_DIR << "/" << filename;
return (stream.str());
}
+};
+
+TEST_F(CommandOptionsTest, Defaults) {
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp 192.168.0.1"));
+ EXPECT_EQ(4, opt.getIpVersion());
+ EXPECT_EQ(CommandOptions::DORA_SARR, opt.getExchangeMode());
+ EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
+ EXPECT_EQ(0, opt.getRate());
+ EXPECT_EQ(0, opt.getRenewRate());
+ EXPECT_EQ(0, opt.getReleaseRate());
+ EXPECT_EQ(0, opt.getReportDelay());
+ EXPECT_EQ(0, opt.getClientsNum());
+ // default mac
+ const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 };
+ std::vector<uint8_t> v1 = opt.getMacTemplate();
+ ASSERT_EQ(6, v1.size());
+ EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
- /// \brief Check default initialized values
- ///
- /// Check if initialized values are correct
- void checkDefaults() {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp 192.168.0.1"));
- EXPECT_EQ(4, opt.getIpVersion());
- EXPECT_EQ(CommandOptions::DORA_SARR, opt.getExchangeMode());
- EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
- EXPECT_EQ(0, opt.getRate());
- EXPECT_EQ(0, opt.getRenewRate());
- EXPECT_EQ(0, opt.getReleaseRate());
- EXPECT_EQ(0, opt.getReportDelay());
- EXPECT_EQ(0, opt.getClientsNum());
-
- // default mac
- const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 };
- std::vector<uint8_t> v1 = opt.getMacTemplate();
- ASSERT_EQ(6, v1.size());
- EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
-
- // Check if DUID is initialized. The DUID-LLT is expected
- // to start with DUID_LLT value of 1 and hardware ethernet
- // type equal to 1 (HWETHER_TYPE).
- const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 };
- // We assume DUID-LLT length 14. This includes 4 octets of
- // DUID_LLT value, two octets of hardware type, 4 octets
- // of time value and 6 octets of variable link layer (MAC)
- // address.
- const int duid_llt_size = 14;
- // DUID is not given from the command line but it is supposed
- // to be initialized by the CommandOptions private method
- // generateDuidTemplate().
- std::vector<uint8_t> v2 = opt.getDuidTemplate();
- ASSERT_EQ(duid_llt_size, opt.getDuidTemplate().size());
- EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4,
- duid_llt_and_hw));
- // Check time field contents.
- ptime now = microsec_clock::universal_time();
- ptime duid_epoch(from_iso_string("20000101T000000"));
- time_period period(duid_epoch, now);
- uint32_t duration_sec = period.length().total_seconds();
- // Read time from the template generated.
- uint32_t duration_from_template = 0;
- memcpy(&duration_from_template, &v2[4], 4);
- duration_from_template = htonl(duration_from_template);
- // In special cases, we may have overflow in time field
- // so we give ourselves the margin of 10 seconds here.
- // If time value has been set more then 10 seconds back
- // it is safe to compare it with the time value generated
- // from now.
- if (duration_from_template > 10) {
- EXPECT_GE(duration_sec, duration_from_template);
- }
-
- EXPECT_EQ(0, opt.getBase().size());
- EXPECT_EQ(0, opt.getNumRequests().size());
- EXPECT_EQ(0, opt.getPeriod());
- for (size_t i = 0; i < opt.getDropTime().size(); ++i) {
- EXPECT_DOUBLE_EQ(1, opt.getDropTime()[i]);
- }
- ASSERT_EQ(opt.getMaxDrop().size(), opt.getMaxDropPercentage().size());
- for (size_t i = 0; i < opt.getMaxDrop().size(); ++i) {
- EXPECT_EQ(0, opt.getMaxDrop()[i]);
- EXPECT_EQ(0, opt.getMaxDropPercentage()[i]);
- }
- EXPECT_EQ("", opt.getLocalName());
- EXPECT_FALSE(opt.isInterface());
- EXPECT_EQ(0, opt.getPreload());
- EXPECT_EQ(0, opt.getLocalPort());
- EXPECT_FALSE(opt.isSeeded());
- EXPECT_EQ(0, opt.getSeed());
- EXPECT_FALSE(opt.isBroadcast());
- EXPECT_FALSE(opt.isRapidCommit());
- EXPECT_FALSE(opt.isUseFirst());
- EXPECT_EQ(0, opt.getTemplateFiles().size());
- EXPECT_EQ(0, opt.getTransactionIdOffset().size());
- EXPECT_EQ(0, opt.getRandomOffset().size());
- EXPECT_GT(0, opt.getElapsedTimeOffset());
- EXPECT_GT(0, opt.getServerIdOffset());
- EXPECT_GT(0, opt.getRequestedIpOffset());
- EXPECT_EQ("", opt.getDiags());
- EXPECT_EQ("", opt.getWrapped());
- EXPECT_EQ("192.168.0.1", opt.getServerName());
+ // Check if DUID is initialized. The DUID-LLT is expected
+ // to start with DUID_LLT value of 1 and hardware ethernet
+ // type equal to 1 (HWETHER_TYPE).
+ const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 };
+ // We assume DUID-LLT length 14. This includes 4 octets of
+ // DUID_LLT value, two octets of hardware type, 4 octets
+ // of time value and 6 octets of variable link layer (MAC)
+ // address.
+ const int duid_llt_size = 14;
+ // DUID is not given from the command line but it is supposed
+ // to be initialized by the CommandOptions private method
+ // generateDuidTemplate().
+ std::vector<uint8_t> v2 = opt.getDuidTemplate();
+ ASSERT_EQ(duid_llt_size, opt.getDuidTemplate().size());
+ EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4,
+ duid_llt_and_hw));
+ // Check time field contents.
+ ptime now = microsec_clock::universal_time();
+ ptime duid_epoch(from_iso_string("20000101T000000"));
+ time_period period(duid_epoch, now);
+ uint32_t duration_sec = period.length().total_seconds();
+ // Read time from the template generated.
+ uint32_t duration_from_template = 0;
+ memcpy(&duration_from_template, &v2[4], 4);
+ duration_from_template = htonl(duration_from_template);
+ // In special cases, we may have overflow in time field
+ // so we give ourselves the margin of 10 seconds here.
+ // If time value has been set more then 10 seconds back
+ // it is safe to compare it with the time value generated
+ // from now.
+ if (duration_from_template > 10) {
+ EXPECT_GE(duration_sec, duration_from_template);
}
-};
-TEST_F(CommandOptionsTest, Defaults) {
- EXPECT_NO_THROW(process("perfdhcp all"));
- checkDefaults();
+ EXPECT_EQ(0, opt.getBase().size());
+ EXPECT_EQ(0, opt.getNumRequests().size());
+ EXPECT_EQ(0, opt.getPeriod());
+ for (size_t i = 0; i < opt.getDropTime().size(); ++i) {
+ EXPECT_DOUBLE_EQ(1, opt.getDropTime()[i]);
+ }
+ ASSERT_EQ(opt.getMaxDrop().size(), opt.getMaxDropPercentage().size());
+ for (size_t i = 0; i < opt.getMaxDrop().size(); ++i) {
+ EXPECT_EQ(0, opt.getMaxDrop()[i]);
+ EXPECT_EQ(0, opt.getMaxDropPercentage()[i]);
+ }
+ EXPECT_EQ("", opt.getLocalName());
+ EXPECT_FALSE(opt.isInterface());
+ EXPECT_EQ(0, opt.getPreload());
+ EXPECT_EQ(0, opt.getLocalPort());
+ EXPECT_FALSE(opt.isSeeded());
+ EXPECT_EQ(0, opt.getSeed());
+ EXPECT_FALSE(opt.isBroadcast());
+ EXPECT_FALSE(opt.isRapidCommit());
+ EXPECT_FALSE(opt.isUseFirst());
+ EXPECT_EQ(0, opt.getTemplateFiles().size());
+ EXPECT_EQ(0, opt.getTransactionIdOffset().size());
+ EXPECT_EQ(0, opt.getRandomOffset().size());
+ EXPECT_GT(0, opt.getElapsedTimeOffset());
+ EXPECT_GT(0, opt.getServerIdOffset());
+ EXPECT_GT(0, opt.getRequestedIpOffset());
+ EXPECT_EQ("", opt.getDiags());
+ EXPECT_EQ("", opt.getWrapped());
+ EXPECT_EQ("192.168.0.1", opt.getServerName());
}
TEST_F(CommandOptionsTest, HelpVersion) {
// The parser is supposed to return true if 'h' or 'v' options
// are specified.
- EXPECT_TRUE(process("perfdhcp -h"));
- EXPECT_TRUE(process("perfdhcp -v"));
- EXPECT_TRUE(process("perfdhcp -h -v"));
- EXPECT_TRUE(process("perfdhcp -6 -l ethx -h all"));
- EXPECT_TRUE(process("perfdhcp -l ethx -v all"));
+ CommandOptions opt;
+ EXPECT_TRUE(process(opt, "perfdhcp -h"));
+ EXPECT_TRUE(process(opt, "perfdhcp -v"));
+ EXPECT_TRUE(process(opt, "perfdhcp -h -v"));
+ EXPECT_TRUE(process(opt, "perfdhcp -6 -l ethx -h all"));
+ EXPECT_TRUE(process(opt, "perfdhcp -l ethx -v all"));
// No 'h' or 'v' option specified. The false value
// should be returned.
- EXPECT_FALSE(process("perfdhcp -l ethx all"));
+ EXPECT_FALSE(process(opt, "perfdhcp -l ethx all"));
}
TEST_F(CommandOptionsTest, UseFirst) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -1 -B -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -1 -B -l ethx all"));
EXPECT_TRUE(opt.isUseFirst());
}
TEST_F(CommandOptionsTest, UseRelayV6) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -6 -A1 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 -l ethx all"));
EXPECT_TRUE(opt.isUseRelayedV6());
// -4 and -A must not coexist
- EXPECT_THROW(process("perfdhcp -4 -A1 -l ethx all"), isc::InvalidParameter);
+ EXPECT_THROW(process(opt, "perfdhcp -4 -A1 -l ethx all"), isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, IpVersion) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -6 -l ethx -c -i all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -l ethx -c -i all"));
EXPECT_EQ(6, opt.getIpVersion());
EXPECT_EQ("ethx", opt.getLocalName());
EXPECT_TRUE(opt.isRapidCommit());
EXPECT_FALSE(opt.isBroadcast());
- process("perfdhcp -4 -B -l ethx all");
+ process(opt, "perfdhcp -4 -B -l ethx all");
EXPECT_EQ(4, opt.getIpVersion());
EXPECT_TRUE(opt.isBroadcast());
EXPECT_FALSE(opt.isRapidCommit());
// Negative test cases
// -4 and -6 must not coexist
- EXPECT_THROW(process("perfdhcp -4 -6 -l ethx all"), isc::InvalidParameter);
+ EXPECT_THROW(process(opt, "perfdhcp -4 -6 -l ethx all"), isc::InvalidParameter);
// -6 and -B must not coexist
- EXPECT_THROW(process("perfdhcp -6 -B -l ethx all"), isc::InvalidParameter);
+ EXPECT_THROW(process(opt, "perfdhcp -6 -B -l ethx all"), isc::InvalidParameter);
// -c and -4 (default) must not coexist
- EXPECT_THROW(process("perfdhcp -c -l ethx all"), isc::InvalidParameter);
+ EXPECT_THROW(process(opt, "perfdhcp -c -l ethx all"), isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, LeaseType) {
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
// Check that the -e address-only works for IPv6.
- ASSERT_NO_THROW(process("perfdhcp -6 -l etx -e address-only all"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -6 -l etx -e address-only all"));
EXPECT_EQ(6, opt.getIpVersion());
EXPECT_EQ("etx", opt.getLocalName());
EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
// Check that the -e address-only works for IPv4.
- ASSERT_NO_THROW(process("perfdhcp -4 -l etx -e address-only all"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -4 -l etx -e address-only all"));
EXPECT_EQ(4, opt.getIpVersion());
EXPECT_EQ("etx", opt.getLocalName());
EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
// Check that the -e prefix-only works.
- ASSERT_NO_THROW(process("perfdhcp -6 -l etx -e prefix-only all"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -6 -l etx -e prefix-only all"));
EXPECT_EQ(6, opt.getIpVersion());
EXPECT_EQ("etx", opt.getLocalName());
EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::PREFIX));
// Check that -e prefix-only must not coexist with -4 option.
- EXPECT_THROW(process("perfdhcp -4 -l ethx -e prefix-only all"),
+ EXPECT_THROW(process(opt, "perfdhcp -4 -l ethx -e prefix-only all"),
InvalidParameter);
// Check that -e prefix-only must not coexist with -T options.
- EXPECT_THROW(process("perfdhcp -6 -l ethx -e prefix-only -T file1.hex"
+ EXPECT_THROW(process(opt, "perfdhcp -6 -l ethx -e prefix-only -T file1.hex"
" -T file2.hex -E 4 all"), InvalidParameter);
}
TEST_F(CommandOptionsTest, Rate) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -4 -r 10 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -4 -r 10 -l ethx all"));
EXPECT_EQ(10, opt.getRate());
// Negative test cases
// Rate must not be 0
- EXPECT_THROW(process("perfdhcp -4 -r 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -4 -r 0 -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, RenewRate) {
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
// If -f is specified together with -r the command line should
// be accepted and the renew rate should be set.
- EXPECT_NO_THROW(process("perfdhcp -6 -r 10 -f 10 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -f 10 -l ethx all"));
EXPECT_EQ(10, opt.getRenewRate());
// Check that the release rate can be set to different value than
// rate specified as -r<rate>. Also, swap -f and -r to make sure
// that order doesn't matter.
- EXPECT_NO_THROW(process("perfdhcp -6 -f 5 -r 10 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -f 5 -r 10 -l ethx all"));
EXPECT_EQ(5, opt.getRenewRate());
// Renew rate should also be accepted for DHCPv4 case.
- EXPECT_NO_THROW(process("perfdhcp -4 -f 5 -r 10 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -4 -f 5 -r 10 -l ethx all"));
EXPECT_EQ(5, opt.getRenewRate());
// The renew rate should not be greater than the rate.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -f 11 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 11 -l ethx all"),
isc::InvalidParameter);
// The renew-rate of 0 is invalid.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -f 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 0 -l ethx all"),
isc::InvalidParameter);
// The negative renew-rate is invalid.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -f -5 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f -5 -l ethx all"),
isc::InvalidParameter);
// If -r<rate> is not specified the -f<renew-rate> should not
// be accepted.
- EXPECT_THROW(process("perfdhcp -6 -f 10 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -f 10 -l ethx all"),
isc::InvalidParameter);
// Renew rate should be specified.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -f -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f -l ethx all"),
isc::InvalidParameter);
// -f and -i are mutually exclusive
- EXPECT_THROW(process("perfdhcp -6 -r 10 -f 10 -l ethx -i all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 10 -l ethx -i all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, ReleaseRate) {
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
// If -F is specified together with -r the command line should
// be accepted and the release rate should be set.
- EXPECT_NO_THROW(process("perfdhcp -6 -r 10 -F 10 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -F 10 -l ethx all"));
EXPECT_EQ(10, opt.getReleaseRate());
// Check that the release rate can be set to different value than
// rate specified as -r<rate>. Also, swap -F and -r to make sure
// that order doesn't matter.
- EXPECT_NO_THROW(process("perfdhcp -6 -F 5 -r 10 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -F 5 -r 10 -l ethx all"));
EXPECT_EQ(5, opt.getReleaseRate());
// The release rate should not be greater than the rate.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -F 11 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 11 -l ethx all"),
isc::InvalidParameter);
// The release-rate of 0 is invalid.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -F 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 0 -l ethx all"),
isc::InvalidParameter);
// The negative release-rate is invalid.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -F -5 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F -5 -l ethx all"),
isc::InvalidParameter);
// If -r<rate> is not specified the -F<release-rate> should not
// be accepted.
- EXPECT_THROW(process("perfdhcp -6 -F 10 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -F 10 -l ethx all"),
isc::InvalidParameter);
// Currently the -F<release-rate> can be specified for IPv6 mode
// only.
- EXPECT_THROW(process("perfdhcp -4 -r 10 -F 10 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -4 -r 10 -F 10 -l ethx all"),
isc::InvalidParameter);
// Release rate should be specified.
- EXPECT_THROW(process("perfdhcp -6 -r 10 -F -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F -l ethx all"),
isc::InvalidParameter);
// -F and -i are mutually exclusive
- EXPECT_THROW(process("perfdhcp -6 -r 10 -F 10 -l ethx -i all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 10 -l ethx -i all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, ReleaseRenew) {
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
// It should be possible to specify the -F, -f and -r options.
- EXPECT_NO_THROW(process("perfdhcp -6 -r 10 -F 3 -f 5 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -F 3 -f 5 -l ethx all"));
EXPECT_EQ(10, opt.getRate());
EXPECT_EQ(3, opt.getReleaseRate());
EXPECT_EQ(5, opt.getRenewRate());
// It should be possible to specify the -F and -f with the values which
// sum is equal to the rate specified as -r<rate>.
- EXPECT_NO_THROW(process("perfdhcp -6 -r 8 -F 3 -f 5 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 8 -F 3 -f 5 -l ethx all"));
EXPECT_EQ(8, opt.getRate());
EXPECT_EQ(3, opt.getReleaseRate());
EXPECT_EQ(5, opt.getRenewRate());
// Check that the sum of the release and renew rate is not greater
// than the rate specified as -r<rate>.
- EXPECT_THROW(process("perfdhcp -6 -F 6 -f 5 -r 10 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -F 6 -f 5 -r 10 -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, ReportDelay) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -t 17 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -t 17 -l ethx all"));
EXPECT_EQ(17, opt.getReportDelay());
// Negative test cases
// -t must be positive integer
- EXPECT_THROW(process("perfdhcp -t -8 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -t -8 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -t 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -t 0 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -t s -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -t s -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, ClientsNum) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -R 200 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -R 200 -l ethx all"));
EXPECT_EQ(200, opt.getClientsNum());
- process("perfdhcp -R 0 -l ethx all");
+ process(opt, "perfdhcp -R 0 -l ethx all");
EXPECT_EQ(0, opt.getClientsNum());
// Negative test cases
// Number of clients must be non-negative integer
- EXPECT_THROW(process("perfdhcp -R -5 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -R -5 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -R gs -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -R gs -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Base) {
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 };
uint8_t duid[14] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 };
// Test DUID and MAC together.
- EXPECT_NO_THROW(process("perfdhcp -b DUID=0101010101010101010110111F14"
+ EXPECT_NO_THROW(process(opt, "perfdhcp -b DUID=0101010101010101010110111F14"
" -b MAC=10::20::30::40::50::60"
" -l 127.0.0.1 all"));
std::vector<uint8_t> v1 = opt.getMacTemplate();
EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
// Test valid DUID.
EXPECT_NO_THROW(
- process("perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all")
+ process(opt, "perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all")
);
ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size());
EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
// Test mix of upper/lower case letters.
- EXPECT_NO_THROW(process("perfdhcp -b DuiD=0101010101010101010110111F14"
+ EXPECT_NO_THROW(process(opt, "perfdhcp -b DuiD=0101010101010101010110111F14"
" -b Mac=10::20::30::40::50::60"
" -l 127.0.0.1 all"));
v1 = opt.getMacTemplate();
EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
// Use "ether" instead of "mac".
- EXPECT_NO_THROW(process("perfdhcp -b ether=10::20::30::40::50::60"
+ EXPECT_NO_THROW(process(opt, "perfdhcp -b ether=10::20::30::40::50::60"
" -l 127.0.0.1 all"));
v1 = opt.getMacTemplate();
EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
// Use "ETHER" in upper case.
- EXPECT_NO_THROW(process("perfdhcp -b ETHER=10::20::30::40::50::60"
+ EXPECT_NO_THROW(process(opt, "perfdhcp -b ETHER=10::20::30::40::50::60"
" -l 127.0.0.1 all"));
v1 = opt.getMacTemplate();
EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
// "t" is invalid character in DUID
- EXPECT_THROW(process("perfdhcp -6 -l ethx -b "
+ EXPECT_THROW(process(opt, "perfdhcp -6 -l ethx -b "
"duid=010101010101010101t110111F14 all"),
isc::InvalidParameter);
// "3x" is invalid value in MAC address
- EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"),
isc::InvalidParameter);
// Base is not specified
- EXPECT_THROW(process("perfdhcp -b -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -b -l ethx all"),
isc::InvalidParameter);
// Typo: should be mac= instead of mc=
- EXPECT_THROW(process("perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"),
isc::InvalidParameter);
// Too short DUID (< 6).
- EXPECT_THROW(process("perfdhcp -l ethx -b duid=00010203 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -b duid=00010203 all"),
isc::InvalidParameter);
// Odd number of digits.
- EXPECT_THROW(process("perfdhcp -l ethx -b duid=000102030405060 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -b duid=000102030405060 all"),
isc::InvalidParameter);
// Too short MAC (!= 6).
- EXPECT_THROW(process("perfdhcp -l ethx -b mac=00:01:02:04 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -b mac=00:01:02:04 all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, DropTime) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -l ethx -d 12 all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -d 12 all"));
ASSERT_EQ(2, opt.getDropTime().size());
EXPECT_DOUBLE_EQ(12, opt.getDropTime()[0]);
EXPECT_DOUBLE_EQ(1, opt.getDropTime()[1]);
- EXPECT_NO_THROW(process("perfdhcp -l ethx -d 2 -d 4.7 all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -d 2 -d 4.7 all"));
ASSERT_EQ(2, opt.getDropTime().size());
EXPECT_DOUBLE_EQ(2, opt.getDropTime()[0]);
EXPECT_DOUBLE_EQ(4.7, opt.getDropTime()[1]);
// Negative test cases
// Drop time must not be negative
- EXPECT_THROW(process("perfdhcp -l ethx -d -2 -d 4.7 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -d -2 -d 4.7 all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -l ethx -d -9.1 -d 0 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -d -9.1 -d 0 all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, TimeOffset) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -l ethx -T file1.x -T file2.x -E 4 all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -T file1.x -T file2.x -E 4 all"));
EXPECT_EQ(4, opt.getElapsedTimeOffset());
// Negative test cases
// Argument -E must be used with -T
- EXPECT_THROW(process("perfdhcp -l ethx -E 3 -i all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -E 3 -i all"),
isc::InvalidParameter);
// Value in -E not specified
- EXPECT_THROW(process("perfdhcp -l ethx -T file.x -E -i all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -T file.x -E -i all"),
isc::InvalidParameter);
// Value for -E must not be negative
- EXPECT_THROW(process("perfdhcp -l ethx -E -3 -T file.x all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -E -3 -T file.x all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, ExchangeMode) {
- CommandOptions& opt = CommandOptions::instance();
- process("perfdhcp -l ethx -i all");
+ CommandOptions opt;
+ process(opt, "perfdhcp -l ethx -i all");
EXPECT_EQ(CommandOptions::DO_SA, opt.getExchangeMode());
// Negative test cases
// No template file specified
- EXPECT_THROW(process("perfdhcp -i -l ethx -X 3 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -X 3 all"),
isc::InvalidParameter);
// Offsets can't be used in simple exchanges (-i)
- EXPECT_THROW(process("perfdhcp -i -l ethx -O 2 -T file.x all"),
+ EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -O 2 -T file.x all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -i -l ethx -E 3 -T file.x all"),
+ EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -E 3 -T file.x all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -i -l ethx -S 1 -T file.x all"),
+ EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -S 1 -T file.x all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -i -l ethx -I 2 -T file.x all"),
+ EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -I 2 -T file.x all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Offsets) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -E5 -4 -I 2 -S3 -O 30 -X7 -l ethx "
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -E5 -4 -I 2 -S3 -O 30 -X7 -l ethx "
"-X3 -T file1.x -T file2.x all"));
EXPECT_EQ(2, opt.getRequestedIpOffset());
EXPECT_EQ(5, opt.getElapsedTimeOffset());
// Negative test cases
// IP offset/IA_NA offset must be positive
- EXPECT_THROW(process("perfdhcp -6 -I 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -I 0 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -6 -I -4 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -I -4 -l ethx all"),
isc::InvalidParameter);
// TODO - other negative cases
}
TEST_F(CommandOptionsTest, LocalPort) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -l ethx -L 2000 all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -L 2000 all"));
EXPECT_EQ(2000, opt.getLocalPort());
// Negative test cases
// Local port must be between 0..65535
- EXPECT_THROW(process("perfdhcp -l ethx -L -2 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -L -2 all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -l ethx -L all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -L all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -l ethx -L 65540 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -L 65540 all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Preload) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -1 -P 3 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -1 -P 3 -l ethx all"));
EXPECT_EQ(3, opt.getPreload());
// Negative test cases
// Number of preload packages must not be negative integer
- EXPECT_THROW(process("perfdhcp -P -1 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -P -1 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -P -3 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -P -3 -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Seed) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -6 -P 2 -s 23 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -P 2 -s 23 -l ethx all"));
EXPECT_EQ(23, opt.getSeed());
EXPECT_TRUE(opt.isSeeded());
- EXPECT_NO_THROW(process("perfdhcp -6 -P 2 -s 0 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -6 -P 2 -s 0 -l ethx all"));
EXPECT_EQ(0, opt.getSeed());
EXPECT_FALSE(opt.isSeeded());
// Negative test cases
// Seed must be non-negative integer
- EXPECT_THROW(process("perfdhcp -6 -P 2 -s -5 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -P 2 -s -5 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -6 -P 2 -s -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -6 -P 2 -s -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, TemplateFiles) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -T file1.x -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -T file1.x -l ethx all"));
ASSERT_EQ(1, opt.getTemplateFiles().size());
EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]);
- EXPECT_NO_THROW(process("perfdhcp -T file1.x -s 12 -w start -T file2.x -4 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -T file1.x -s 12 -w start -T file2.x -4 -l ethx all"));
ASSERT_EQ(2, opt.getTemplateFiles().size());
EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]);
EXPECT_EQ("file2.x", opt.getTemplateFiles()[1]);
// Negative test cases
// No template file specified
- EXPECT_THROW(process("perfdhcp -s 12 -T -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -s 12 -T -l ethx all"),
isc::InvalidParameter);
// Too many template files specified
- EXPECT_THROW(process("perfdhcp -s 12 -l ethx -T file.x "
+ EXPECT_THROW(process(opt, "perfdhcp -s 12 -l ethx -T file.x "
"-T file.x -T file.x all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Wrapped) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -B -w start -i -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -B -w start -i -l ethx all"));
EXPECT_EQ("start", opt.getWrapped());
// Negative test cases
// Missing command after -w, expected start/stop
- EXPECT_THROW(process("perfdhcp -B -i -l ethx -w all"),
+ EXPECT_THROW(process(opt, "perfdhcp -B -i -l ethx -w all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Diagnostics) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -l ethx -i -x asTe all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -i -x asTe all"));
EXPECT_EQ("asTe", opt.getDiags());
// Negative test cases
// No diagnostics string specified
- EXPECT_THROW(process("perfdhcp -l ethx -i -x all"),
+ EXPECT_THROW(process(opt, "perfdhcp -l ethx -i -x all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, MaxDrop) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -D 25 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -D 25 -l ethx all"));
EXPECT_EQ(25, opt.getMaxDrop()[0]);
- EXPECT_NO_THROW(process("perfdhcp -D 25 -l ethx -D 15 all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -D 25 -l ethx -D 15 all"));
EXPECT_EQ(25, opt.getMaxDrop()[0]);
EXPECT_EQ(15, opt.getMaxDrop()[1]);
- EXPECT_NO_THROW(process("perfdhcp -D 15% -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -D 15% -l ethx all"));
EXPECT_EQ(15, opt.getMaxDropPercentage()[0]);
- EXPECT_NO_THROW(process("perfdhcp -D 15% -D25% -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -D 15% -D25% -l ethx all"));
EXPECT_EQ(15, opt.getMaxDropPercentage()[0]);
EXPECT_EQ(25, opt.getMaxDropPercentage()[1]);
- EXPECT_NO_THROW(process("perfdhcp -D 1% -D 99% -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -D 1% -D 99% -l ethx all"));
EXPECT_EQ(1, opt.getMaxDropPercentage()[0]);
EXPECT_EQ(99, opt.getMaxDropPercentage()[1]);
// Negative test cases
// Too many -D<value> options
- EXPECT_THROW(process("perfdhcp -D 0% -D 1 -l ethx -D 3 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -D 0% -D 1 -l ethx -D 3 all"),
isc::InvalidParameter);
// Too many -D<value%> options
- EXPECT_THROW(process("perfdhcp -D 99% -D 13% -l ethx -D 10% all"),
+ EXPECT_THROW(process(opt, "perfdhcp -D 99% -D 13% -l ethx -D 10% all"),
isc::InvalidParameter);
// Percentage is out of bounds
- EXPECT_THROW(process("perfdhcp -D101% -D 13% -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -D101% -D 13% -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -D0% -D 13% -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -D0% -D 13% -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, NumRequest) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -n 1000 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -n 1000 -l ethx all"));
EXPECT_EQ(1000, opt.getNumRequests()[0]);
- EXPECT_NO_THROW(process("perfdhcp -n 5 -n 500 -l ethx all"));
+ EXPECT_NO_THROW(process(opt, "perfdhcp -n 5 -n 500 -l ethx all"));
EXPECT_EQ(5, opt.getNumRequests()[0]);
EXPECT_EQ(500, opt.getNumRequests()[1]);
// Negative test cases
// Too many -n<value> parameters, expected maximum 2
- EXPECT_THROW(process("perfdhcp -n 1 -n 2 -l ethx -n3 all"),
+ EXPECT_THROW(process(opt, "perfdhcp -n 1 -n 2 -l ethx -n3 all"),
isc::InvalidParameter);
// Num request must be positive integer
- EXPECT_THROW(process("perfdhcp -n 1 -n -22 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -n 1 -n -22 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -n 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -n 0 -l ethx all"),
isc::InvalidParameter);
}
TEST_F(CommandOptionsTest, Period) {
- CommandOptions& opt = CommandOptions::instance();
- EXPECT_NO_THROW(process("perfdhcp -p 120 -l ethx all"));
+ CommandOptions opt;
+ EXPECT_NO_THROW(process(opt, "perfdhcp -p 120 -l ethx all"));
EXPECT_EQ(120, opt.getPeriod());
// Negative test cases
// Test period must be positive integer
- EXPECT_THROW(process("perfdhcp -p 0 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -p 0 -l ethx all"),
isc::InvalidParameter);
- EXPECT_THROW(process("perfdhcp -p -3 -l ethx all"),
+ EXPECT_THROW(process(opt, "perfdhcp -p -3 -l ethx all"),
isc::InvalidParameter);
}
dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance();
const dhcp::IfaceMgr::IfaceCollection& ifaces = iface_mgr.getIfaces();
std::string iface_name;
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
// The local loopback interface should be available.
// If no interface have been found for any reason we should
// not fail this test.
// Get the name of the interface we detected.
iface_name = (*ifaces.begin())->getName();
// Use the name in the command parser.
- ASSERT_NO_THROW(process("perfdhcp -4 -l " + iface_name + " abc"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -4 -l " + iface_name + " abc"));
// We expect that command parser will detect that argument
// specified along with '-l' is the interface name.
EXPECT_TRUE(opt.isInterface());
// If neither interface nor server is specified then
// exception is expected to be thrown.
- EXPECT_THROW(process("perfdhcp -4"), isc::InvalidParameter);
+ EXPECT_THROW(process(opt, "perfdhcp -4"), isc::InvalidParameter);
}
}
TEST_F(CommandOptionsTest, Server) {
- CommandOptions& opt = CommandOptions::instance();
+ CommandOptions opt;
// There is at least server parameter needed. If server is not
// specified the local interface must be specified.
// The server value equal to 'all' means use broadcast.
- ASSERT_NO_THROW(process("perfdhcp all"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp all"));
// Once command line is parsed we expect that server name is
// set to broadcast address because 'all' was specified.
EXPECT_TRUE(opt.isBroadcast());
// When all is specified for DHCPv6 mode we expect
// FF02::1:2 as a server name which means All DHCP
// servers and relay agents in local network segment
- ASSERT_NO_THROW(process("perfdhcp -6 all"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -6 all"));
EXPECT_EQ(ALL_DHCP_RELAY_AGENTS_AND_SERVERS, opt.getServerName());
// When server='servers' in DHCPv6 mode we expect
// FF05::1:3 as server name which means All DHCP
// servers in local network.
- ASSERT_NO_THROW(process("perfdhcp -6 servers"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -6 servers"));
EXPECT_EQ(ALL_DHCP_SERVERS, opt.getServerName());
// If server name is neither 'all' nor 'servers'
// the given argument value is expected to be
// returned.
- ASSERT_NO_THROW(process("perfdhcp -6 abc"));
+ ASSERT_NO_THROW(process(opt, "perfdhcp -6 abc"));
EXPECT_EQ("abc", opt.getServerName());
}
TEST_F(CommandOptionsTest, LoadMacsFromFile) {
- CommandOptions &opt = CommandOptions::instance();
+ CommandOptions opt;
- std::string mac_list_full_path = getFullPath("mac-list.txt");
- std::ostringstream cmd;
- cmd << "perfdhcp -M " << mac_list_full_path << " abc";
- EXPECT_NO_THROW(process(cmd.str()));
- EXPECT_EQ(mac_list_full_path, opt.getMacListFile());
+ std::string mac_list_full_path = getFullPath("mac-list.txt");
+ std::ostringstream cmd;
+ cmd << "perfdhcp -M " << mac_list_full_path << " abc";
+ EXPECT_NO_THROW(process(opt, cmd.str()));
+ EXPECT_EQ(mac_list_full_path, opt.getMacListFile());
- const CommandOptions::MacAddrsVector& m = opt.getMacsFromFile();
- EXPECT_EQ(4, m.size());
+ const CommandOptions::MacAddrsVector& m = opt.getMacsFromFile();
+ EXPECT_EQ(4, m.size());
}
TEST_F(CommandOptionsTest, LoadMacsFromFileNegativeCases) {
- // Negative test cases
- // Too many -M parameters, expected only 1
- EXPECT_THROW(process("perfdhcp -M foo -M foo1 all"), isc::InvalidParameter);
- // -M option can't use with -b option
- EXPECT_THROW(process("perfdhcp -M foo -b mac=1234 all"),
- isc::InvalidParameter);
+ CommandOptions opt;
+ // Negative test cases
+ // Too many -M parameters, expected only 1
+ EXPECT_THROW(process(opt, "perfdhcp -M foo -M foo1 all"), isc::InvalidParameter);
+ // -M option can't use with -b option
+ EXPECT_THROW(process(opt, "perfdhcp -M foo -b mac=1234 all"),
+ isc::InvalidParameter);
}
--- /dev/null
+// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include "command_options_helper.h"
+#include "../perf_socket.h"
+
+#include <asiolink/io_address.h>
+#include <exceptions/exceptions.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/iface_mgr.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/foreach.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <stdint.h>
+#include <string>
+#include <fstream>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace boost::posix_time;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::perfdhcp;
+
+
+/// \brief Test Fixture Class
+///
+/// This test fixture class is used to perform
+/// unit tests on perfdhcp PerfSocketTest class.
+class PerfSocketTest : public virtual ::testing::Test
+{
+public:
+ PerfSocketTest() { }
+};
+
+
+TEST_F(PerfSocketTest, Basic) {
+ CommandOptions opt;
+
+ // make sure we catch -6 paired with v4 address
+ CommandOptionsHelper::process(opt, "perfdhcp -l 127.0.0.1 -6 192.168.1.1");
+ EXPECT_THROW(PerfSocket sock(opt), isc::InvalidParameter);
+
+ // make sure we catch -4 paired with v6 address
+ CommandOptionsHelper::process(opt, "perfdhcp -l 127.0.0.1 -4 ff02::1:2");
+ EXPECT_THROW(PerfSocket sock(opt), isc::InvalidParameter);
+}
using namespace isc::perfdhcp;
TEST(Receiver, singleThreaded) {
- CommandOptionsHelper::process("perfdhcp -g single -l 127.0.0.1 all");
- ASSERT_TRUE(CommandOptions::instance().isSingleThreaded());
+ CommandOptions opt;
+ CommandOptionsHelper::process(opt, "perfdhcp -g single -l 127.0.0.1 all");
+ ASSERT_TRUE(opt.isSingleThreaded());
- PerfSocket sock(123);
-
- Receiver receiver(sock);
+ PerfSocket socket(opt);
+ Receiver receiver(socket, opt.isSingleThreaded(), opt.getIpVersion());
ASSERT_NO_THROW(receiver.start());
TEST(Receiver, multiThreaded) {
- CommandOptionsHelper::process("perfdhcp -g multi -l 127.0.0.1 all");
- ASSERT_FALSE(CommandOptions::instance().isSingleThreaded());
-
- PerfSocket sock(123);
+ CommandOptions opt;
+ CommandOptionsHelper::process(opt, "perfdhcp -g multi -l 127.0.0.1 all");
+ ASSERT_FALSE(opt.isSingleThreaded());
- Receiver receiver(sock);
+ PerfSocket socket(opt);
+ Receiver receiver(socket, opt.isSingleThreaded(), opt.getIpVersion());
ASSERT_NO_THROW(receiver.start());
#include <config.h>
-#include <boost/shared_ptr.hpp>
+#include "command_options_helper.h"
+
+#include <perfdhcp/stats_mgr.h>
#include <exceptions/exceptions.h>
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
-#include "../stats_mgr.h"
#include <gtest/gtest.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
using namespace std;
using namespace isc;
namespace {
-typedef StatsMgr<dhcp::Pkt4> StatsMgr4;
-typedef StatsMgr<dhcp::Pkt6> StatsMgr6;
-
const uint32_t common_transid = 123;
/// @brief Number of packets to be used for testing packets collecting.
/// \param num_packets packets to be passed to Statistics Manager.
/// \param receive simulated packets are received (if true)
/// or sent (if false)
- void passMultiplePackets6(const boost::shared_ptr<StatsMgr6> stats_mgr,
- StatsMgr6::ExchangeType xchg_type,
+ void passMultiplePackets6(const boost::shared_ptr<StatsMgr> stats_mgr,
+ ExchangeType xchg_type,
const uint8_t packet_type,
const int num_packets,
const bool receive = false) {
///
/// \param stats_mgr Statistics Manager instance.
/// \param delay delay in seconds between DISCOVER and OFFER packets.
- void passDOPacketsWithDelay(const boost::shared_ptr<StatsMgr4> stats_mgr,
+ void passDOPacketsWithDelay(const boost::shared_ptr<StatsMgr> stats_mgr,
unsigned int delay,
uint32_t transid) {
boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER,
transid));
ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
);
- // There is way to differentiate timestamps of two packets other than
- // sleep for before we create another packet. Packet is using current
- // time to update its timestamp.
- // Sleeping for X seconds will guarantee that delay between packets
- // will be greater than 1 second. Note that posix time value is
- // transformed to double value and it makes it hard to determine
- // actual value to expect.
- std::cout << "Sleeping for " << delay << "s to test packet delays"
- << std::endl;
- sleep(delay);
+ // Simulate time difference by changing time of sent packet
+ auto ts = sent_packet->getTimestamp() - boost::posix_time::seconds(delay);
+ sent_packet->setTimestamp(ts);
boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER,
transid));
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet);
);
// Calculate period between packets.
/// @param transid_index Index in the table of transaction ids which
/// points to the transaction id to be selected for the DHCPOFFER.
void testSendReceiveCollected(const size_t transid_index) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+ CommandOptions opt;
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
// The second parameter indicates that transactions older than
// 2 seconds should be removed and respective packets collected.
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO, 2);
+ stats_mgr->addExchangeStats(ExchangeType::DO, 2);
// Transaction ids of packets to be sent. All transaction ids
// belong to the same bucket (match the transid & 1023 hashing
sent_packet->modifyTimestamp(-10);
}
ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
) << "failure for transaction id " << transid[i];
}
Pkt4ModifiablePtr rcvd_packet(createPacket4(DHCPOFFER,
transid[transid_index]));
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet);
);
// There is exactly one case (transaction id) for which perfdhcp
// will find a packet using ordered lookup. In this case, no
// packets will be collected. Otherwise, for any unordered lookup
// all packets from a bucket should be collected.
- if (stats_mgr->getUnorderedLookups(StatsMgr4::XCHG_DO) > 0) {
+ if (stats_mgr->getUnorderedLookups(ExchangeType::DO) > 0) {
// All packets in the bucket having transaction id
// index below TEST_COLLECTED_PKT_NUM / 2 should be removed.
EXPECT_EQ(TEST_COLLECTED_PKT_NUM / 2,
- stats_mgr->getCollectedNum(StatsMgr4::XCHG_DO));
+ stats_mgr->getCollectedNum(ExchangeType::DO));
}
// Make sure that we can still use the StatsMgr. It is possible
Pkt4ModifiablePtr rcvd_packet(createPacket4(DHCPOFFER,
transid[i] + 1));
ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
) << "failure for transaction id " << transid[i];
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet);
) << "failure for transaction id " << transid[i];
}
// timeout. Therefore, we have to count both received packets and
// orphans.
EXPECT_EQ(TEST_COLLECTED_PKT_NUM + 1,
- stats_mgr->getRcvdPacketsNum(StatsMgr4::XCHG_DO) +
- stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
+ stats_mgr->getRcvdPacketsNum(ExchangeType::DO) +
+ stats_mgr->getOrphans(ExchangeType::DO));
}
};
TEST_F(StatsMgrTest, Constructor) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
+ CommandOptions opt;
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
+ stats_mgr->addExchangeStats(ExchangeType::DO);
EXPECT_DOUBLE_EQ(
std::numeric_limits<double>::max(),
- stats_mgr->getMinDelay(StatsMgr4::XCHG_DO)
+ stats_mgr->getMinDelay(ExchangeType::DO)
);
- EXPECT_DOUBLE_EQ(0, stats_mgr->getMaxDelay(StatsMgr4::XCHG_DO));
- EXPECT_EQ(0, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
- EXPECT_EQ(0, stats_mgr->getOrderedLookups(StatsMgr4::XCHG_DO));
- EXPECT_EQ(0, stats_mgr->getUnorderedLookups(StatsMgr4::XCHG_DO));
- EXPECT_EQ(0, stats_mgr->getSentPacketsNum(StatsMgr4::XCHG_DO));
- EXPECT_EQ(0, stats_mgr->getRcvdPacketsNum(StatsMgr4::XCHG_DO));
- EXPECT_EQ(0, stats_mgr->getCollectedNum(StatsMgr4::XCHG_DO));
-
- EXPECT_THROW(stats_mgr->getAvgDelay(StatsMgr4::XCHG_DO), InvalidOperation);
- EXPECT_THROW(stats_mgr->getStdDevDelay(StatsMgr4::XCHG_DO),
+ EXPECT_DOUBLE_EQ(0, stats_mgr->getMaxDelay(ExchangeType::DO));
+ EXPECT_EQ(0, stats_mgr->getOrphans(ExchangeType::DO));
+ EXPECT_EQ(0, stats_mgr->getOrderedLookups(ExchangeType::DO));
+ EXPECT_EQ(0, stats_mgr->getUnorderedLookups(ExchangeType::DO));
+ EXPECT_EQ(0, stats_mgr->getSentPacketsNum(ExchangeType::DO));
+ EXPECT_EQ(0, stats_mgr->getRcvdPacketsNum(ExchangeType::DO));
+ EXPECT_EQ(0, stats_mgr->getCollectedNum(ExchangeType::DO));
+
+ EXPECT_THROW(stats_mgr->getAvgDelay(ExchangeType::DO), InvalidOperation);
+ EXPECT_THROW(stats_mgr->getStdDevDelay(ExchangeType::DO),
InvalidOperation);
- EXPECT_THROW(stats_mgr->getAvgUnorderedLookupSetSize(StatsMgr4::XCHG_DO),
+ EXPECT_THROW(stats_mgr->getAvgUnorderedLookupSetSize(ExchangeType::DO),
InvalidOperation);
}
TEST_F(StatsMgrTest, Exchange) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+ CommandOptions opt;
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER,
common_transid));
boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER,
common_transid));
// This is expected to throw because XCHG_DO was not yet
// added to Stats Manager for tracking.
- ASSERT_FALSE(stats_mgr->hasExchangeStats(StatsMgr4::XCHG_DO));
- ASSERT_FALSE(stats_mgr->hasExchangeStats(StatsMgr4::XCHG_RA));
+ ASSERT_FALSE(stats_mgr->hasExchangeStats(ExchangeType::DO));
+ ASSERT_FALSE(stats_mgr->hasExchangeStats(ExchangeType::RA));
EXPECT_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet),
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet),
BadValue
);
EXPECT_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet),
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet),
BadValue
);
// Adding DISCOVER-OFFER exchanges to be tracked by Stats Manager.
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
- ASSERT_TRUE(stats_mgr->hasExchangeStats(StatsMgr4::XCHG_DO));
- ASSERT_FALSE(stats_mgr->hasExchangeStats(StatsMgr4::XCHG_RA));
+ stats_mgr->addExchangeStats(ExchangeType::DO);
+ ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::DO));
+ ASSERT_FALSE(stats_mgr->hasExchangeStats(ExchangeType::RA));
// The following two attempts are expected to throw because
// invalid exchange types are passed (XCHG_RA instead of XCHG_DO)
EXPECT_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_RA, sent_packet),
+ stats_mgr->passSentPacket(ExchangeType::RA, sent_packet),
BadValue
);
EXPECT_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_RA, rcvd_packet),
+ stats_mgr->passRcvdPacket(ExchangeType::RA, rcvd_packet),
BadValue
);
// The following two attempts are expected to run fine because
// right exchange type is specified.
EXPECT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
);
EXPECT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet)
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet)
);
}
TEST_F(StatsMgrTest, MultipleExchanges) {
- boost::shared_ptr<StatsMgr6> stats_mgr(new StatsMgr6());
- stats_mgr->addExchangeStats(StatsMgr6::XCHG_SA);
- stats_mgr->addExchangeStats(StatsMgr6::XCHG_RR);
+ CommandOptions opt;
+ boost::shared_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
+ stats_mgr->addExchangeStats(ExchangeType::SA);
+ stats_mgr->addExchangeStats(ExchangeType::RR);
// Simulate sending number of solicit packets.
const int solicit_packets_num = 10;
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_SA, DHCPV6_SOLICIT,
+ passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_SOLICIT,
solicit_packets_num);
// Simulate sending number of request packets. It is important that
// packets. We can now check if right number packets went to
// the right exchange type group.
const int request_packets_num = 5;
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_RR, DHCPV6_REQUEST,
+ passMultiplePackets6(stats_mgr, ExchangeType::RR, DHCPV6_REQUEST,
request_packets_num);
// Check if all packets are successfully passed to packet lists.
EXPECT_EQ(solicit_packets_num,
- stats_mgr->getSentPacketsNum(StatsMgr6::XCHG_SA));
+ stats_mgr->getSentPacketsNum(ExchangeType::SA));
EXPECT_EQ(request_packets_num,
- stats_mgr->getSentPacketsNum(StatsMgr6::XCHG_RR));
+ stats_mgr->getSentPacketsNum(ExchangeType::RR));
// Simulate reception of multiple packets for both SOLICIT-ADVERTISE
// and REQUEST-REPLY exchanges. Assume no packet drops.
const bool receive_packets = true;
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_SA, DHCPV6_ADVERTISE,
+ passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_ADVERTISE,
solicit_packets_num, receive_packets);
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_RR, DHCPV6_REPLY,
+ passMultiplePackets6(stats_mgr, ExchangeType::RR, DHCPV6_REPLY,
request_packets_num, receive_packets);
// Verify that all received packets are counted.
EXPECT_EQ(solicit_packets_num,
- stats_mgr->getRcvdPacketsNum(StatsMgr6::XCHG_SA));
+ stats_mgr->getRcvdPacketsNum(ExchangeType::SA));
EXPECT_EQ(request_packets_num,
- stats_mgr->getRcvdPacketsNum(StatsMgr6::XCHG_RR));
+ stats_mgr->getRcvdPacketsNum(ExchangeType::RR));
}
TEST_F(StatsMgrTest, SendReceiveSimple) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+ CommandOptions opt;
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER,
common_transid));
boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER,
common_transid));
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
+ stats_mgr->addExchangeStats(ExchangeType::DO);
// The following attempt is expected to pass because the right
// exchange type is used.
ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
);
// It is ok, to pass to received packets here. First one will
// be matched with sent packet. The latter one will not be
// matched with sent packet but orphans counter will simply
// increase.
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet)
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet)
);
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet)
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet)
);
- EXPECT_EQ(1, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(1, stats_mgr->getOrphans(ExchangeType::DO));
}
TEST_F(StatsMgrTest, SendReceiveUnordered) {
+ CommandOptions opt;
const int packets_num = 10;
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
+ stats_mgr->addExchangeStats(ExchangeType::DO);
// Transaction ids of 10 packets to be sent and received.
uint32_t transid[packets_num] =
boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER,
transid[i]));
ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
);
}
rcvd_packet(createPacket4(DHCPDISCOVER,
transid[packets_num - 1 - i]));
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet);
);
}
// All packets are expected to match (we did not drop any)
- EXPECT_EQ(0, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(0, stats_mgr->getOrphans(ExchangeType::DO));
// Most of the time we have to do unordered lookups except for the last
// one. Packets are removed from the sent list every time we have a match
// so eventually we come up with the single packet that caching iterator
// is pointing to. This is counted as ordered lookup.
- EXPECT_EQ(1, stats_mgr->getOrderedLookups(StatsMgr4::XCHG_DO));
- EXPECT_EQ(9, stats_mgr->getUnorderedLookups(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(1, stats_mgr->getOrderedLookups(ExchangeType::DO));
+ EXPECT_EQ(9, stats_mgr->getUnorderedLookups(ExchangeType::DO));
}
TEST_F(StatsMgrTest, SendReceiveCollected) {
}
TEST_F(StatsMgrTest, Orphans) {
+ CommandOptions opt;
const int packets_num = 6;
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
+ stats_mgr->addExchangeStats(ExchangeType::DO);
// We skip every second packet to simulate drops.
for (int i = 0; i < packets_num; i += 2) {
boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER, i));
ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
+ stats_mgr->passSentPacket(ExchangeType::DO, sent_packet)
);
}
// We pass all received packets.
for (int i = 0; i < packets_num; ++i) {
boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER, i));
ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
+ stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet);
);
}
// The half of received packets are expected not to have matching
// sent packet.
- EXPECT_EQ(packets_num / 2, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(packets_num / 2, stats_mgr->getOrphans(ExchangeType::DO));
}
TEST_F(StatsMgrTest, Delays) {
-
- boost::shared_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO, 5);
+ CommandOptions opt;
+ boost::shared_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
+ stats_mgr->addExchangeStats(ExchangeType::DO, 5);
// Send DISCOVER, wait 2s and receive OFFER. This will affect
// counters in Stats Manager.
// Initially min delay is equal to MAX_DOUBLE. After first packets
// are passed, it is expected to set to actual value.
- EXPECT_LT(stats_mgr->getMinDelay(StatsMgr4::XCHG_DO),
+ EXPECT_LT(stats_mgr->getMinDelay(ExchangeType::DO),
std::numeric_limits<double>::max());
- EXPECT_GT(stats_mgr->getMinDelay(StatsMgr4::XCHG_DO), 1);
+ EXPECT_GT(stats_mgr->getMinDelay(ExchangeType::DO), 1);
// Max delay is supposed to the same value as minimum
// or maximum delay.
- EXPECT_GT(stats_mgr->getMaxDelay(StatsMgr4::XCHG_DO), 1);
+ EXPECT_GT(stats_mgr->getMaxDelay(ExchangeType::DO), 1);
// Delay sums are now the same as minimum or maximum delay.
- EXPECT_GT(stats_mgr->getAvgDelay(StatsMgr4::XCHG_DO), 1);
+ EXPECT_GT(stats_mgr->getAvgDelay(ExchangeType::DO), 1);
// Simulate another DISCOVER-OFFER exchange with delay between
// sent and received packets. Delay is now shorter than earlier
const unsigned int delay2 = 1;
passDOPacketsWithDelay(stats_mgr, delay2, common_transid + 1);
// Standard deviation is expected to be non-zero.
- EXPECT_GT(stats_mgr->getStdDevDelay(StatsMgr4::XCHG_DO), 0);
+ EXPECT_GT(stats_mgr->getStdDevDelay(ExchangeType::DO), 0);
}
TEST_F(StatsMgrTest, CustomCounters) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+ CommandOptions opt;
+ boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
// Specify counter keys and names.
const std::string too_short_key("tooshort");
}
// Check counter's current value and name.
- StatsMgr4::CustomCounterPtr tooshort_counter =
+ CustomCounterPtr tooshort_counter =
stats_mgr->getCounter(too_short_key);
EXPECT_EQ(too_short_name, tooshort_counter->getName());
EXPECT_EQ(tooshort_num, tooshort_counter->getValue());
// Check counter's current value and name.
- StatsMgr4::CustomCounterPtr toolate_counter =
+ CustomCounterPtr toolate_counter =
stats_mgr->getCounter(too_late_key);
EXPECT_EQ(too_late_name, toolate_counter->getName());
EXPECT_EQ(toolate_num, toolate_counter->getValue());
<< "capabilities. It is expected that some counters "
<< "will be printed during this test. It may also "
<< "cause spurious errors." << std::endl;
- boost::shared_ptr<StatsMgr6> stats_mgr(new StatsMgr6());
- stats_mgr->addExchangeStats(StatsMgr6::XCHG_SA);
+ CommandOptions opt;
+ boost::shared_ptr<StatsMgr> stats_mgr(new StatsMgr(opt));
+ stats_mgr->addExchangeStats(ExchangeType::SA);
// Simulate sending and receiving one packet. Otherwise printing
// functions will complain about lack of packets.
const int packets_num = 1;
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_SA, DHCPV6_SOLICIT,
+ passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_SOLICIT,
packets_num);
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_SA, DHCPV6_ADVERTISE,
+ passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_ADVERTISE,
packets_num, true);
// This function will print statistics even if packets are not
// Now, we create another statistics manager instance and enable
// packets archiving mode.
- const bool archive_packets = true;
- boost::shared_ptr<StatsMgr6> stats_mgr2(new StatsMgr6(archive_packets));
- stats_mgr2->addExchangeStats(StatsMgr6::XCHG_SA);
+ CommandOptionsHelper::process(opt, "perfdhcp -x t 127.0.0.1");
+ boost::shared_ptr<StatsMgr> stats_mgr2(new StatsMgr(opt));
+ stats_mgr2->addExchangeStats(ExchangeType::SA);
// Timestamps should now get printed because packets have been preserved.
EXPECT_NO_THROW(stats_mgr2->printTimestamps());
using namespace isc::dhcp;
using namespace isc::perfdhcp;
+/// \brief FakePerfSocket class that mocks PerfSocket.
+///
+/// It stubs send and receive operations and collects statistics.
+class FakePerfSocket: public BasePerfSocket {
+public:
+ /// \brief Default constructor for FakePerfSocket.
+ FakePerfSocket() :
+ iface_(boost::make_shared<Iface>("fake", 0)),
+ sent_cnt_(0),
+ recv_cnt_(0) {};
+
+ IfacePtr iface_; ///< Local fake interface.
+
+ int sent_cnt_; ///< Counter of sent packets
+ int recv_cnt_; ///< Counter of received packets.
+
+ /// \brief Simulate receiving DHCPv4 packet.
+ virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override {
+ (void)timeout_sec; // silence compile 'unused parameter' warning;
+ (void)timeout_usec; // silence compile 'unused parameter' warning;
+ recv_cnt_++;
+ return(dhcp::Pkt4Ptr());
+ };
+
+ /// \brief Simulate receiving DHCPv6 packet.
+ virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override {
+ (void)timeout_sec; // silence compile 'unused parameter' warning;
+ (void)timeout_usec; // silence compile 'unused parameter' warning;
+ recv_cnt_++;
+ return(dhcp::Pkt6Ptr());
+ };
+
+ /// \brief Simulate sending DHCPv4 packet.
+ virtual bool send(const dhcp::Pkt4Ptr& pkt) override {
+ sent_cnt_++;
+ pkt->updateTimestamp();
+ return true;
+ };
+
+ /// \brief Simulate sending DHCPv6 packet.
+ virtual bool send(const dhcp::Pkt6Ptr& pkt) override {
+ sent_cnt_++;
+ pkt->updateTimestamp();
+ return true;
+ };
+
+ /// \brief Override getting interface.
+ virtual IfacePtr getIface() override { return iface_; }
+
+ void reset() {
+ sent_cnt_ = 0;
+ recv_cnt_ = 0;
+ }
+};
+
+
/// \brief Test Control class with protected members made public.
///
/// This class makes protected TestControl class's members public
/// \brief Pointer to incremental generator.
typedef boost::shared_ptr<IncrementalGenerator> IncrementalGeneratorPtr;
- using TestControl::checkExitConditions;
using TestControl::createMessageFromReply;
using TestControl::createRequestFromAck;
using TestControl::factoryElapsedTime6;
using TestControl::generateMacAddress;
using TestControl::getTemplateBuffer;
using TestControl::initPacketTemplates;
- using TestControl::initializeStatsMgr;
- using TestControl::openSocket;
using TestControl::processReceivedPacket4;
using TestControl::processReceivedPacket6;
using TestControl::registerOptionFactories;
using TestControl::sendSolicit6;
using TestControl::setDefaults4;
using TestControl::setDefaults6;
- using TestControl::basic_rate_control_;
- using TestControl::renew_rate_control_;
- using TestControl::release_rate_control_;
+ using TestControl::socket_;
using TestControl::last_report_;
using TestControl::transid_gen_;
using TestControl::macaddr_gen_;
using TestControl::template_packets_v6_;
using TestControl::ack_storage_;
using TestControl::sendRequestFromAck;
+ using TestControl::options_;
+ using TestControl::stats_mgr_;
+
+ FakePerfSocket fake_sock_;
- NakedTestControl() : TestControl() {
- uint32_t clients_num = CommandOptions::instance().getClientsNum() == 0 ?
- 1 : CommandOptions::instance().getClientsNum();
+ NakedTestControl(CommandOptions &opt) : TestControl(opt, fake_sock_) {
+ uint32_t clients_num = opt.getClientsNum() == 0 ?
+ 1 : opt.getClientsNum();
setMacAddrGenerator(NumberGeneratorPtr(new TestControl::SequentialGenerator(clients_num)));
};
};
+
/// \brief Test Fixture Class
///
/// This test fixture class is used to perform
return (true);
}
- /// \brief Get local loopback interface name.
- ///
- /// Scan available network interfaces for local loopback
- /// interface and get its name. On Linux this interface is
- /// usually called 'lo' but on other systems, e.g. BSD
- /// it will have slightly different name. Local loopback
- /// interface is required for unit tests that require
- /// socket creation.
- ///
- /// \return local loopback interface name.
- std::string getLocalLoopback() const {
- BOOST_FOREACH(IfacePtr iface, IfaceMgr::instance().getIfaces()) {
- if (iface->flag_loopback_) {
- return (iface->getName());
- }
- }
- return ("");
- }
-
/// \brief Get full path to a file in testdata directory.
///
/// \param filename filename being appended to absolute
/// as the number of seconds since DUID time epoch. The parts
/// of MAC address has to change if multiple clients are simulated
/// and do not change if single client is simulated.
- void testDuid() const {
- int clients_num = CommandOptions::instance().getClientsNum();
+ void testDuid(CommandOptions &opt) const {
+ int clients_num = opt.getClientsNum();
// Initialize Test Control class.
- NakedTestControl tc;
+ NakedTestControl tc(opt);
// The old duid will be holding the previously generated DUID.
// It will be used to compare against the new one. If we have
// multiple clients we want to make sure that duids differ.
///
/// \param iterations_num number of exchanges to simulate.
/// \param receive_num number of received OFFER packets.
- /// \param iterations_performed actual number of iterations.
/// \param tc test control instance
void testPkt4Exchange(int iterations_num,
int receive_num,
bool use_templates,
- int& iterations_performed,
NakedTestControl& tc) const {
- int sock_handle = 0;
- tc.initializeStatsMgr();
+ //int sock_handle = 0;
// Use templates files to crate packets.
if (use_templates) {
tc.initPacketTemplates();
- ASSERT_NO_THROW(tc.getTemplateBuffer(0));
- ASSERT_NO_THROW(tc.getTemplateBuffer(1));
+ tc.getTemplateBuffer(0);
+ tc.getTemplateBuffer(1);
}
// Incremental transaction id generator will generate
NakedTestControl::IncrementalGeneratorPtr
generator(new NakedTestControl::IncrementalGenerator());
tc.setTransidGenerator(generator);
- // Socket is needed to send packets through the interface.
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
for (int i = 0; i < iterations_num; ++i) {
// Get next transaction id, without actually using it. The same
// id wll be used by the TestControl class for DHCPDISCOVER.
uint32_t transid = generator->getNext();
if (use_templates) {
- ASSERT_NO_THROW(tc.sendDiscover4(sock, tc.getTemplateBuffer(0)));
+ tc.sendDiscover4(tc.getTemplateBuffer(0));
} else {
- ASSERT_NO_THROW(tc.sendDiscover4(sock));
+ tc.sendDiscover4();
}
// Do not simulate responses for packets later
// packet drops.
if (i < receive_num) {
boost::shared_ptr<Pkt4> offer_pkt4(createOfferPkt4(transid));
- ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer_pkt4));
+ tc.processReceivedPacket4(offer_pkt4);
}
- if (tc.checkExitConditions()) {
- iterations_performed = i + 1;
- break;
- }
- iterations_performed = i + 1;
}
}
///
/// \param iterations_num number of exchanges to simulate.
/// \param receive_num number of received OFFER packets.
- /// \param iterations_performed actual number of iterations.
/// \param tc test control instance
void testPkt6Exchange(int iterations_num,
int receive_num,
bool use_templates,
- int& iterations_performed,
NakedTestControl& tc) const {
- int sock_handle = 0;
- tc.initializeStatsMgr();
+ //int sock_handle = 0;
// Use templates files to crate packets.
if (use_templates) {
tc.initPacketTemplates();
- ASSERT_NO_THROW(tc.getTemplateBuffer(0));
- ASSERT_NO_THROW(tc.getTemplateBuffer(1));
+ tc.getTemplateBuffer(0);
+ tc.getTemplateBuffer(1);
}
// Incremental transaction id generator will generate
TestControl::NumberGeneratorPtr
generator(new NakedTestControl::IncrementalGenerator());
tc.setTransidGenerator(generator);
- // Socket is needed to send packets through the interface.
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
uint32_t transid = 0;
for (int i = 0; i < iterations_num; ++i) {
// Do not simulate responses for packets later
// that specified as receive_num. This simulates
// packet drops.
if (use_templates) {
- ASSERT_NO_THROW(tc.sendSolicit6(sock, tc.getTemplateBuffer(0)));
+ tc.sendSolicit6(tc.getTemplateBuffer(0));
} else {
- ASSERT_NO_THROW(tc.sendSolicit6(sock));
+ tc.sendSolicit6();
}
++transid;
if (i < receive_num) {
boost::shared_ptr<Pkt6>
- advertise_pkt6(createAdvertisePkt6(transid));
+ advertise_pkt6(createAdvertisePkt6(tc, transid));
// Receive ADVERTISE and send REQUEST.
- ASSERT_NO_THROW(tc.processReceivedPacket6(sock,
- advertise_pkt6));
+ tc.processReceivedPacket6(advertise_pkt6);
++transid;
}
- if (tc.checkExitConditions()) {
- iterations_performed = i + 1;
- break;
- }
- iterations_performed = i + 1;
}
}
/// addresses are generated if number of simulated clients is
/// greater than 1. It also checks if the same MAC addresses is
/// generated if only 1 client is simulated.
- void testMacAddress() const {
- int clients_num = CommandOptions::instance().getClientsNum();
+ void testMacAddress(CommandOptions &opt) const {
+ int clients_num = opt.getClientsNum();
// The old_mac will be holding the value of previously generated
// MAC address. We will be comparing the newly generated one with it
// to see if it changes when multiple clients are simulated or if it
// does not change when single client is simulated.
- MacAddress old_mac(CommandOptions::instance().getMacTemplate());
+ MacAddress old_mac(opt.getMacTemplate());
// Holds the position if the octet on which two MAC addresses can
// be different. If number of clients is 256 or less it is last MAC
// octet (except for single client when subsequent MAC addresses
// Number of unique MACs.
size_t unique_macs = 0;
// Initialize Test Controller.
- NakedTestControl tc;
+ NakedTestControl tc(opt);
size_t total_dist = 0;
// Keep generated MACs in this container.
std::list<std::vector<uint8_t> > macs;
/// attempt to send more renew messages than the number of leases acquired
/// will fail.
void testSendRenew4() {
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Skipping the test because loopback interface could"
- " not be detected" << std::endl;
- return;
- }
// Build a command line. Depending on the message type, we will use
// -f<renew-rate> or -F<release-rate> parameter.
+ CommandOptions opt;
std::ostringstream s;
- s << "perfdhcp -4 -l " << loopback_iface << " -r 10 -f";
+ s << "perfdhcp -4 -l fake -r 10 -f";
s << " 10 -R 10 -L 10067 -n 10 127.0.0.1";
- ASSERT_NO_THROW(processCmdLine(s.str()));
+ processCmdLine(opt, s.str());
// Create a test controller class.
- NakedTestControl tc;
- tc.initializeStatsMgr();
+ NakedTestControl tc(opt);
// Set the transaction id generator to sequential to control to
// guarantee that transaction ids are predictable.
boost::shared_ptr<NakedTestControl::IncrementalGenerator>
generator(new NakedTestControl::IncrementalGenerator());
tc.setTransidGenerator(generator);
- // Socket has to be created so as we can actually send packets.
- int sock_handle = 0;
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
// Send a number of DHCPDISCOVER messages. Each generated message will
// be assigned a different transaction id, starting from 1 to 10.
- tc.sendPackets(sock, 10);
+ tc.sendPackets(10);
// Simulate DHCPOFFER responses from the server. Each DHCPOFFER is
// assigned a transaction id from the range of 1 to 10, so as they
// will trigger a corresponding DHCPREQUEST. They will be assigned
// transaction ids from the range from 11 to 20 (the range of
// 1 to 10 has been used by DHCPDISCOVER-DHCPOFFER).
- ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer));
+ tc.processReceivedPacket4(offer);
}
// Requests have been sent, so now let's simulate responses from the
// -f<renew-rate> option has been specified, received Reply
// messages are held so as renew messages can be sent for
// existing leases.
- ASSERT_NO_THROW(tc.processReceivedPacket4(sock, ack));
+ tc.processReceivedPacket4(ack);
}
uint64_t msg_num;
// Try to send 5 messages. It should be successful because 10
// DHCPREQUEST messages has been received. For each of them we
// should be able to send renewal.
- ASSERT_NO_THROW(
- msg_num = tc.sendMultipleRequests(sock, 5)
- );
+ msg_num = tc.sendMultipleRequests(5);
// Make sure that we have sent 5 messages.
EXPECT_EQ(5, msg_num);
// Try to do it again. We should still have 5 Reply packets for
// which renews haven't been sent yet.
- ASSERT_NO_THROW(
- msg_num = tc.sendMultipleRequests(sock, 5)
- );
+ msg_num = tc.sendMultipleRequests(5);
EXPECT_EQ(5, msg_num);
// We used all the DHCPACK packets (we sent renew or release for each of
// them already). Therefore, no further renew messages should be sent
// before we acquire new leases.
- ASSERT_NO_THROW(
- msg_num = tc.sendMultipleRequests(sock, 5)
- );
+ msg_num = tc.sendMultipleRequests(5);
// Make sure that no message has been sent.
EXPECT_EQ(0, msg_num);
}
void testCreateRequest() {
// This command line specifies that the Release/Renew messages should
// be sent with the same rate as the Solicit messages.
+ CommandOptions opt;
std::ostringstream s;
s << "perfdhcp -4 -l lo -r 10 -f 10";
s << " -R 10 -L 10067 -n 10 127.0.0.1";
- ASSERT_NO_THROW(processCmdLine(s.str()));
+ processCmdLine(opt, s.str());
// Create a test controller class.
- NakedTestControl tc;
+ NakedTestControl tc(opt);
// Set the transaction id generator which will be used by the
// createRenew or createRelease function to generate transaction id.
boost::shared_ptr<NakedTestControl::IncrementalGenerator>
// Create DHCPREQUEST from DHCPACK.
Pkt4Ptr request;
- ASSERT_NO_THROW(request = tc.createRequestFromAck(ack));
+ request = tc.createRequestFromAck(ack);
// Make sure that the DHCPACK has been successfully created and that
// it holds expected data.
void testCreateRenewRelease(const uint16_t msg_type) {
// This command line specifies that the Release/Renew messages should
// be sent with the same rate as the Solicit messages.
+ CommandOptions opt;
std::ostringstream s;
s << "perfdhcp -6 -l lo -r 10 ";
s << (msg_type == DHCPV6_RELEASE ? "-F" : "-f") << " 10 ";
s << "-R 10 -L 10547 -n 10 -e address-and-prefix ::1";
- ASSERT_NO_THROW(processCmdLine(s.str()));
+ processCmdLine(opt, s.str());
// Create a test controller class.
- NakedTestControl tc;
+ NakedTestControl tc(opt);
// Set the transaction id generator which will be used by the
// createRenew or createRelease function to generate transaction id.
boost::shared_ptr<NakedTestControl::IncrementalGenerator>
// Create a Reply packet. The createRelease or createReply function will
// need Reply packet to create a corresponding Release or Reply.
- Pkt6Ptr reply = createReplyPkt6(1);
+ Pkt6Ptr reply = createReplyPkt6(tc, 1);
Pkt6Ptr msg;
// Check that the message is created.
- ASSERT_NO_THROW(msg = tc.createMessageFromReply(msg_type, reply));
+ msg = tc.createMessageFromReply(msg_type, reply);
ASSERT_TRUE(msg);
// Check that the message type and transaction id is correct.
/// \param msg_type A type of the message which is simulated to be sent
/// (DHCPV6_RENEW or DHCPV6_RELEASE).
void testSendRenewRelease(const uint16_t msg_type) {
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Skipping the test because loopback interface could"
- " not be detected" << std::endl;
- return;
- }
// Build a command line. Depending on the message type, we will use
// -f<renew-rate> or -F<release-rate> parameter.
+ CommandOptions opt;
std::ostringstream s;
- s << "perfdhcp -6 -l " << loopback_iface << " -r 10 ";
+ s << "perfdhcp -6 -l fake -r 10 ";
s << (msg_type == DHCPV6_RENEW ? "-f" : "-F");
s << " 10 -R 10 -L 10547 -n 10 ::1";
- ASSERT_NO_THROW(processCmdLine(s.str()));
+ processCmdLine(opt, s.str());
// Create a test controller class.
- NakedTestControl tc;
- tc.initializeStatsMgr();
+ NakedTestControl tc(opt);
// Set the transaction id generator to sequential to control to
// guarantee that transaction ids are predictable.
boost::shared_ptr<NakedTestControl::IncrementalGenerator>
generator(new NakedTestControl::IncrementalGenerator());
tc.setTransidGenerator(generator);
- // Socket has to be created so as we can actually send packets.
- int sock_handle = 0;
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
// Send a number of Solicit messages. Each generated Solicit will be
// assigned a different transaction id, starting from 1 to 10.
- tc.sendPackets(sock, 10);
+ tc.sendPackets(10);
// Simulate Advertise responses from the server. Each advertise is
// assigned a transaction id from the range of 1 to 10, so as they
// match the transaction ids from the Solicit messages.
for (unsigned i = generator->getNext() - 10;
i < generator->getNext(); ++i) {
- Pkt6Ptr advertise(createAdvertisePkt6(i));
+ Pkt6Ptr advertise(createAdvertisePkt6(tc, i));
// If Advertise is matched with the Solicit the call below will
// trigger a corresponding Request. They will be assigned
// transaction ids from the range from 11 to 20 (the range of
// 1 to 10 has been used by Solicit-Advertise).
- ASSERT_NO_THROW(tc.processReceivedPacket6(sock, advertise));
+ tc.processReceivedPacket6(advertise);
}
// Requests have been sent, so now let's simulate responses from the
// ids from the range from 11 to 20.
for (unsigned i = generator->getNext() - 10;
i < generator->getNext(); ++i) {
- Pkt6Ptr reply(createReplyPkt6(i));
+ Pkt6Ptr reply(createReplyPkt6(tc, i));
// Each Reply packet corresponds to the new lease acquired. Since
// -f<renew-rate> option has been specified, received Reply
// messages are held so as Renew messages can be sent for
// existing leases.
- ASSERT_NO_THROW(tc.processReceivedPacket6(sock, reply));
+ tc.processReceivedPacket6(reply);
}
uint64_t msg_num;
// Try to send 5 messages. It should be successful because 10 Reply
// messages has been received. For each of them we should be able to
// send Renew or Release.
- ASSERT_NO_THROW(
- msg_num = tc.sendMultipleMessages6(sock, msg_type, 5)
- );
+ msg_num = tc.sendMultipleMessages6(msg_type, 5);
// Make sure that we have sent 5 messages.
EXPECT_EQ(5, msg_num);
// Try to do it again. We should still have 5 Reply packets for
// which Renews or Releases haven't been sent yet.
- ASSERT_NO_THROW(
- msg_num = tc.sendMultipleMessages6(sock, msg_type, 5)
- );
+ msg_num = tc.sendMultipleMessages6(msg_type, 5);
EXPECT_EQ(5, msg_num);
// We used all the Reply packets (we sent Renew or Release for each of
// them already). Therefore, no further Renew or Release messages should
// be sent before we acquire new leases.
- ASSERT_NO_THROW(
- msg_num = tc.sendMultipleMessages6(sock, msg_type, 5)
- );
+ msg_num = tc.sendMultipleMessages6(msg_type, 5);
// Make sure that no message has been sent.
EXPECT_EQ(0, msg_num);
/// \param cmdline command line string to be parsed.
/// \throw isc::Unexpected if unexpected error occurred.
/// \throw isc::InvalidParameter if command line is invalid.
- void processCmdLine(const std::string& cmdline) const {
- CommandOptionsHelper::process(cmdline);
+ void processCmdLine(CommandOptions &opt, const std::string& cmdline) const {
+ CommandOptionsHelper::process(opt, cmdline);
}
/// \brief Create DHCPOFFER or DHCPACK packet.
/// \param transid transaction id.
/// \return instance of the packet.
Pkt6Ptr
- createAdvertisePkt6(const uint32_t transid) const {
+ createAdvertisePkt6(NakedTestControl &tc, const uint32_t transid) const {
boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
// Add IA_NA if requested by the client.
- if (CommandOptions::instance().getLeaseType()
- .includes(CommandOptions::LeaseType::ADDRESS)) {
+ if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
advertise->addOption(opt_ia_na);
}
// Add IA_PD if requested by the client.
- if (CommandOptions::instance().getLeaseType()
- .includes(CommandOptions::LeaseType::PREFIX)) {
+ if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
advertise->addOption(opt_ia_pd);
}
OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
- NakedTestControl tc;
uint8_t randomized = 0;
std::vector<uint8_t> duid(tc.generateDuid(randomized));
OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
}
Pkt6Ptr
- createReplyPkt6(const uint32_t transid) const {
+ createReplyPkt6(NakedTestControl &tc, const uint32_t transid) const {
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, transid));
// Add IA_NA if requested by the client.
- if (CommandOptions::instance().getLeaseType()
- .includes(CommandOptions::LeaseType::ADDRESS)) {
+ if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
reply->addOption(opt_ia_na);
}
// Add IA_PD if requested by the client.
- if (CommandOptions::instance().getLeaseType()
- .includes(CommandOptions::LeaseType::PREFIX)) {
+ if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
reply->addOption(opt_ia_pd);
}
OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
- NakedTestControl tc;
uint8_t randomized = 0;
std::vector<uint8_t> duid(tc.generateDuid(randomized));
OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
// This test verifies that the class members are reset to expected values.
TEST_F(TestControlTest, reset) {
- ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l ethx -r 50 -f 30 -F 10 all"));
- NakedTestControl tc;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -4 127.0.0.1");
+ NakedTestControl tc(opt);
tc.reset();
- EXPECT_EQ(50, tc.basic_rate_control_.getRate());
- EXPECT_EQ(30, tc.renew_rate_control_.getRate());
- EXPECT_EQ(10, tc.release_rate_control_.getRate());
EXPECT_FALSE(tc.last_report_.is_not_a_date_time());
EXPECT_FALSE(tc.transid_gen_);
EXPECT_FALSE(tc.macaddr_gen_);
HWAddrPtr hwaddr_ptr(new HWAddr(hwaddr, 5));
// Use generated HW address to generate client id.
- NakedTestControl tc;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -4 127.0.0.1");
+ NakedTestControl tc(opt);
OptionPtr opt_client_id;
- ASSERT_NO_THROW(opt_client_id = tc.generateClientId(hwaddr_ptr));
+ opt_client_id = tc.generateClientId(hwaddr_ptr);
ASSERT_TRUE(opt_client_id);
// Extract the client id data.
TEST_F(TestControlTest, GenerateDuid) {
// Simple command line that simulates one client only. Always the
// same DUID will be generated.
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
- testDuid();
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 all");
+ testDuid(opt);
// Simulate 50 clients. Different DUID will be generated.
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all"));
- testDuid();
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 -R 50 all");
+ testDuid(opt);
// Checks that the random mac address returned by generateDuid
// is in the list of mac addresses in the mac-list.txt data file
std::string mac_list_full_path = getFullPath("mac-list.txt");
std::ostringstream cmd;
- cmd << "perfdhcp -M " << mac_list_full_path << " abc";
- ASSERT_NO_THROW(processCmdLine(cmd.str()));
+ cmd << "perfdhcp -M " << mac_list_full_path << " 127.0.0.1";
+ processCmdLine(opt, cmd.str());
// Initialize Test Controller.
- NakedTestControl tc;
+ NakedTestControl tc(opt);
uint8_t randomized = 0;
std::vector<uint8_t> generated_duid = tc.generateDuid(randomized);
ASSERT_EQ(duid->getType(), DUID::DUID_LL);
// Make sure it's on the list
- CommandOptions& options = CommandOptions::instance();
- const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
+ const CommandOptions::MacAddrsVector& macs = opt.getMacsFromFile();
// DUID LL comprises 2 bytes of duid type, 2 bytes of hardware type,
// then 6 bytes of HW address.
vector<uint8_t> mac(6);
ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end());
}
-TEST_F(TestControlTest, MisMatchVersionServer) {
- NakedTestControl tc;
-
- // make sure we catch -6 paired with v4 address
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -6 192.168.1.1"));
- EXPECT_THROW(tc.openSocket(), isc::InvalidParameter);
-
- // make sure we catch -4 paired with v6 address
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -4 ff02::1:2"));
- EXPECT_THROW(tc.openSocket(), isc::InvalidParameter);
-}
-
TEST_F(TestControlTest, GenerateMacAddress) {
+ CommandOptions opt;
// Simulate one client only. Always the same MAC address will be
// generated.
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
- testMacAddress();
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 all");
+ testMacAddress(opt);
// Simulate 50 clients. Different MAC addresses will be generated.
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all"));
- testMacAddress();
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 -R 50 all");
+ testMacAddress(opt);
// Checks that the random mac address returned by generateMacAddress
// is in the list of mac addresses in the mac-list.txt data file
std::string mac_list_full_path = getFullPath("mac-list.txt");
std::ostringstream cmd;
- cmd << "perfdhcp -M " << mac_list_full_path << " abc";
- ASSERT_NO_THROW(processCmdLine(cmd.str()));
+ cmd << "perfdhcp -M " << mac_list_full_path << " 127.0.0.1";
+ processCmdLine(opt, cmd.str());
// Initialize Test Controller.
- NakedTestControl tc;
+ NakedTestControl tc(opt);
uint8_t randomized = 0;
// Generate MAC address and sanity check its size.
std::vector<uint8_t> mac = tc.generateMacAddress(randomized);
ASSERT_EQ(6, mac.size());
// Make sure that the generated MAC address belongs to the MAC addresses
// read from a file.
- CommandOptions& options = CommandOptions::instance();
- const CommandOptions::MacAddrsVector& macs = options.getMacsFromFile();
+ const CommandOptions::MacAddrsVector& macs = opt.getMacsFromFile();
ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end());
}
TEST_F(TestControlTest, Options4) {
using namespace isc::dhcp;
- NakedTestControl tc;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -4 127.0.0.1");
+ NakedTestControl tc(opt);
// By default the IP version mode is V4 so there is no need to
// parse command line to override the IP version. Note that
// registerOptionFactories is used for both V4 and V6.
EXPECT_EQ(DHO_DHCP_MESSAGE_TYPE, opt_msg_type->getType());
// Validate the message type from the option we have now created.
uint8_t msg_type = 0;
- ASSERT_NO_THROW(msg_type = opt_msg_type->getUint8());
+ msg_type = opt_msg_type->getUint8();
EXPECT_EQ(DHCPDISCOVER, msg_type);
// Create another option: DHCP_PARAMETER_REQUEST_LIST
TEST_F(TestControlTest, Options6) {
using namespace isc::dhcp;
+ CommandOptions opt;
// Lets override the IP version to test V6 options (-6 parameter)
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -6 all"));
+ processCmdLine(opt, "perfdhcp -l lo -6 ::1");
- NakedTestControl tc;
+ NakedTestControl tc(opt);
tc.registerOptionFactories();
// Validate the D6O_ELAPSED_TIME option.
EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time->getType());
// The default value of elapsed time is zero.
uint16_t elapsed_time;
- ASSERT_NO_THROW(elapsed_time = opt_elapsed_time->getUint16());
+ elapsed_time = opt_elapsed_time->getUint16();
EXPECT_EQ(0, elapsed_time);
// With the factory function we may also specify the actual
EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time2->getType());
// Make sure the getUint16 does not throw exception. It wile throw
// buffer is shorter than 2 octets.
- ASSERT_NO_THROW(elapsed_time = opt_elapsed_time2->getUint16());
+ elapsed_time = opt_elapsed_time2->getUint16();
// Check the expected value of elapsed time.
EXPECT_EQ(0x0101, elapsed_time);
EXPECT_THROW(opt_rapid_commit->getUint8(), isc::OutOfRange);
// Validate the D6O_CLIENTID option.
- OptionBuffer duid(CommandOptions::instance().getDuidTemplate());
+ OptionBuffer duid(opt.getDuidTemplate());
OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
EXPECT_EQ(Option::V6, opt_clientid->getUniverse());
EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType());
}
TEST_F(TestControlTest, Packet4) {
- // Use Interface Manager to get the local loopback interface.
- // If interface can't be found we don't want to fail test.
- std::string loopback_iface(getLocalLoopback());
- if (!loopback_iface.empty()) {
- ASSERT_NO_THROW(processCmdLine("perfdhcp -l " + loopback_iface +
- " -L 10547 all"));
- NakedTestControl tc;
- int sock_handle = 0;
- // We have to create the socket to setup some parameters of
- // outgoing packet.
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
- uint32_t transid = 123;
- boost::shared_ptr<Pkt4> pkt4(new Pkt4(DHCPDISCOVER, transid));
- // Set parameters on outgoing packet.
- ASSERT_NO_THROW(tc.setDefaults4(sock, pkt4));
- // Validate that packet has been setup correctly.
- EXPECT_EQ(loopback_iface, pkt4->getIface());
- EXPECT_EQ(sock.ifindex_, pkt4->getIndex());
- EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort());
- EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort());
- EXPECT_EQ(1, pkt4->getHops());
- EXPECT_EQ(asiolink::IOAddress("255.255.255.255"),
- pkt4->getRemoteAddr());
- EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getLocalAddr());
- EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getGiaddr());
- } else {
- std::cout << "Unable to find the loopback interface. Skip test. "
- << std::endl;
- }
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -L 10547 all");
+ NakedTestControl tc(opt);
+ uint32_t transid = 123;
+ boost::shared_ptr<Pkt4> pkt4(new Pkt4(DHCPDISCOVER, transid));
+ // Set parameters on outgoing packet.
+ tc.setDefaults4(pkt4);
+ // Validate that packet has been setup correctly.
+ EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt4->getIface());
+ EXPECT_EQ(tc.fake_sock_.ifindex_, pkt4->getIndex());
+ EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort());
+ EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort());
+ EXPECT_EQ(1, pkt4->getHops());
+ EXPECT_EQ(asiolink::IOAddress("255.255.255.255"),
+ pkt4->getRemoteAddr());
+ EXPECT_EQ(asiolink::IOAddress(tc.socket_.addr_), pkt4->getLocalAddr());
+ EXPECT_EQ(asiolink::IOAddress(tc.socket_.addr_), pkt4->getGiaddr());
}
TEST_F(TestControlTest, Packet6) {
- // Use Interface Manager to get the local loopback interface.
- // If the interface can't be found we don't want to fail test.
- std::string loopback_iface(getLocalLoopback());
- if (!loopback_iface.empty()) {
- ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface +
- " -L 10547 servers"));
- NakedTestControl tc;
- int sock_handle = 0;
- // Create the socket. It will be needed to set packet's
- // parameters.
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
- uint32_t transid = 123;
- boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
- // Set packet's parameters.
- ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6));
- // Validate if parameters have been set correctly.
- EXPECT_EQ(loopback_iface, pkt6->getIface());
- EXPECT_EQ(sock.ifindex_, pkt6->getIndex());
- EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
- EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
- EXPECT_EQ(sock.addr_, pkt6->getLocalAddr());
- EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
- // Packet must not be relayed.
- EXPECT_TRUE(pkt6->relay_info_.empty());
-
- } else {
- std::cout << "Unable to find the loopback interface. Skip test. "
- << std::endl;
- }
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -6 -l fake -L 10547 servers");
+ NakedTestControl tc(opt);
+ uint32_t transid = 123;
+ boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
+ // Set packet's parameters.
+ tc.setDefaults6(pkt6);
+ // Validate if parameters have been set correctly.
+ EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt6->getIface());
+ EXPECT_EQ(tc.socket_.ifindex_, pkt6->getIndex());
+ EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
+ EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
+ EXPECT_EQ(tc.socket_.addr_, pkt6->getLocalAddr());
+ EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
+ // Packet must not be relayed.
+ EXPECT_TRUE(pkt6->relay_info_.empty());
}
TEST_F(TestControlTest, Packet6Relayed) {
- // Use Interface Manager to get the local loopback interface.
- // If the interface can't be found we don't want to fail test.
- std::string loopback_iface(getLocalLoopback());
- if (!loopback_iface.empty()) {
- ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface +
- " -A1 -L 10547 servers"));
- NakedTestControl tc;
- int sock_handle = 0;
- // Create the socket. It will be needed to set packet's
- // parameters.
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
- uint32_t transid = 123;
- boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
- // Set packet's parameters.
- ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6));
- // Validate if parameters have been set correctly.
- EXPECT_EQ(loopback_iface, pkt6->getIface());
- EXPECT_EQ(sock.ifindex_, pkt6->getIndex());
- EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
- EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
- EXPECT_EQ(sock.addr_, pkt6->getLocalAddr());
- EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
- // Packet should be relayed.
- EXPECT_EQ(pkt6->relay_info_.size(), 1);
- EXPECT_EQ(pkt6->relay_info_[0].hop_count_, 1);
- EXPECT_EQ(pkt6->relay_info_[0].msg_type_, DHCPV6_RELAY_FORW);
- EXPECT_EQ(pkt6->relay_info_[0].linkaddr_, sock.addr_);
- EXPECT_EQ(pkt6->relay_info_[0].peeraddr_, sock.addr_);
- } else {
- std::cout << "Unable to find the loopback interface. Skip test. "
- << std::endl;
- }
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -6 -l fake -A1 -L 10547 servers");
+ NakedTestControl tc(opt);
+ uint32_t transid = 123;
+ boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
+ // Set packet's parameters.
+ tc.setDefaults6(pkt6);
+ // Validate if parameters have been set correctly.
+ EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt6->getIface());
+ EXPECT_EQ(tc.socket_.ifindex_, pkt6->getIndex());
+ EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort());
+ EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort());
+ EXPECT_EQ(tc.socket_.addr_, pkt6->getLocalAddr());
+ EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr());
+ // Packet should be relayed.
+ EXPECT_EQ(pkt6->relay_info_.size(), 1);
+ EXPECT_EQ(pkt6->relay_info_[0].hop_count_, 1);
+ EXPECT_EQ(pkt6->relay_info_[0].msg_type_, DHCPV6_RELAY_FORW);
+ EXPECT_EQ(pkt6->relay_info_[0].linkaddr_, tc.socket_.addr_);
+ EXPECT_EQ(pkt6->relay_info_[0].peeraddr_, tc.socket_.addr_);
}
TEST_F(TestControlTest, Packet4Exchange) {
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test."
- << std::endl;
- return;
- }
-
- // Set number of iterations to some high value.
const int iterations_num = 100;
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -r 100 -n 10 -R 20 -L 10547 127.0.0.1");
- // The actual number of iterations will be stored in the
- // following variable.
- int iterations_performed = 0;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -r 100 -n 10 -R 20 -L 10547 127.0.0.1");
bool use_templates = false;
- NakedTestControl tc;
- testPkt4Exchange(iterations_num, iterations_num, use_templates, iterations_performed, tc);
- // The command line restricts the number of iterations to 10
- // with -n 10 parameter.
- EXPECT_EQ(10, iterations_performed);
-
- // With the following command line we restrict the maximum
- // number of dropped packets to 10% of all.
- // Use templates for this test.
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -r 100 -R 20 -n 20 -D 10% -L 10547"
- + " -T " + getFullPath("discover-example.hex")
+ NakedTestControl tc(opt);
+ testPkt4Exchange(iterations_num, iterations_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Discovery + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::DO), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::DO), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RA), 0);
+}
+
+TEST_F(TestControlTest, Packet4ExchangeFromTemplate) {
+ const int iterations_num = 100;
+ CommandOptions opt;
+
+ processCmdLine(opt, "perfdhcp -l fake -r 100 -R 20 -n 20 -L 10547"
+ " -T " + getFullPath("discover-example.hex")
+ " -T " + getFullPath("request4-example.hex")
+ " 127.0.0.1");
- // The number iterations is restricted by the percentage of
- // dropped packets (-D 10%). We also have to bump up the number
- // of iterations because the percentage limitation checks starts
- // at packet #10. We expect that at packet #12 the 10% threshold
- // will be reached.
const int received_num = 10;
- use_templates = true;
- testPkt4Exchange(iterations_num, received_num, use_templates, iterations_performed, tc);
- EXPECT_EQ(12, iterations_performed);
+ bool use_templates = true;
+ NakedTestControl tc(opt);
+ testPkt4Exchange(iterations_num, received_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num + received_num); // Discovery + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::DO), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::DO), received_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RA), received_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RA), 0);
}
-TEST_F(TestControlTest, Packet6ExchangeFromTemplate) {
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test."
- << std::endl;
- return;
- }
-
+TEST_F(TestControlTest, Packet6Exchange) {
const int iterations_num = 100;
- // Set number of iterations to 10.
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
- int iterations_performed = 0;
- // Set number of received packets equal to number of iterations.
- // This simulates no packet drops.
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -6 -r 100 -n 10 -R 20 -L 10547 ::1");
bool use_templates = false;
- NakedTestControl tc;
- testPkt6Exchange(iterations_num, iterations_num, use_templates,
- iterations_performed, tc);
- // Actual number of iterations should be 10.
- EXPECT_EQ(10, iterations_performed);
-
- // The maximum number of dropped packets is 3 (because of -D 3).
- use_templates = true;
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547"
- + " -T " + getFullPath("solicit-example.hex")
+ NakedTestControl tc(opt);
+ testPkt6Exchange(iterations_num, iterations_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0);
+}
+
+TEST_F(TestControlTest, Packet6ExchangeFromTemplate) {
+ const int iterations_num = 100;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -6 -r 100 -n 10 -R 20 -L 10547"
+ " -T " + getFullPath("solicit-example.hex")
+ " -T " + getFullPath("request6-example.hex ::1"));
+ NakedTestControl tc(opt);
+
// For the first 3 packets we are simulating responses from server.
// For other packets we don't so packet as 4,5,6 will be dropped and
// then test should be interrupted and actual number of iterations will
const int received_num = 3;
// Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
// The test function generates server's responses and passes it to the
- // TestControl class methods for processing. The number of exchanges
- // actually performed is returned in 'iterations_performed' argument. If
- // processing is successful, the number of performed iterations should be
- // equal to the number of exchanges specified with the '-n' command line
- // parameter (10 in this case). All exchanged packets carry the IA_NA option
- // to simulate the IPv6 address acquisition and to verify that the
- // IA_NA options returned by the server are processed correctly.
- testPkt6Exchange(iterations_num, received_num, use_templates,
- iterations_performed, tc);
- EXPECT_EQ(6, iterations_performed);
+ // TestControl class methods for processing. All exchanged packets carry
+ // the IA_NA option to simulate the IPv6 address acquisition and to verify
+ // that the IA_NA options returned by the server are processed correctly.
+ bool use_templates = true;
+ testPkt6Exchange(iterations_num, received_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num + received_num); // Solicit + Advertise
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), received_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), received_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0);
}
-TEST_F(TestControlTest, Packet6Exchange) {
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test."
- << std::endl;
- return;
- }
-
+TEST_F(TestControlTest, Packet6ExchangeAddressOnly) {
const int iterations_num = 100;
- // Set number of iterations to 10.
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -e address-only"
- + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
- int iterations_performed = 0;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -e address-only"
+ " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
// Set number of received packets equal to number of iterations.
// This simulates no packet drops.
bool use_templates = false;
// Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
// The test function generates server's responses and passes it to the
- // TestControl class methods for processing. The number of exchanges
- // actually performed is returned in 'iterations_performed' argument. If
- // processing is successful, the number of performed iterations should be
- // equal to the number of exchanges specified with the '-n' command line
- // parameter (10 in this case). All exchanged packets carry the IA_NA option
- // to simulate the IPv6 address acquisition and to verify that the IA_NA
- // options returned by the server are processed correctly.
- NakedTestControl tc;
- testPkt6Exchange(iterations_num, iterations_num, use_templates,
- iterations_performed, tc);
- // Actual number of iterations should be 10.
- EXPECT_EQ(10, iterations_performed);
+ // TestControl class methods for processing. All exchanged packets carry
+ // the IA_NA option to simulate the IPv6 address acquisition and to verify
+ // that the IA_NA options returned by the server are processed correctly.
+ NakedTestControl tc(opt);
+ testPkt6Exchange(iterations_num, iterations_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0);
}
TEST_F(TestControlTest, Packet6ExchangePrefixDelegation) {
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test."
- << std::endl;
- return;
- }
-
const int iterations_num = 100;
- // Set number of iterations to 10.
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -e prefix-only"
- + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
- int iterations_performed = 0;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -e prefix-only"
+ " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
// Set number of received packets equal to number of iterations.
// This simulates no packet drops.
bool use_templates = false;
// Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
// The test function generates server's responses and passes it to the
- // TestControl class methods for processing. The number of exchanges
- // actually performed is returned in 'iterations_performed' argument. If
- // processing is successful, the number of performed iterations should be
- // equal to the number of exchanges specified with the '-n' command line
- // parameter (10 in this case). All exchanged packets carry the IA_PD option
- // to simulate the Prefix Delegation and to verify that the IA_PD options
- // returned by the server are processed correctly.
- NakedTestControl tc;
- testPkt6Exchange(iterations_num, iterations_num, use_templates,
- iterations_performed, tc);
- // Actual number of iterations should be 10.
- EXPECT_EQ(10, iterations_performed);
+ // TestControl class methods for processing. All exchanged packets carry
+ // the IA_PD option to simulate the Prefix Delegation and to verify that
+ // the IA_PD options returned by the server are processed correctly.
+ NakedTestControl tc(opt);
+ testPkt6Exchange(iterations_num, iterations_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Discovery + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0);
}
TEST_F(TestControlTest, Packet6ExchangeAddressAndPrefix) {
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback_iface(getLocalLoopback());
- if (loopback_iface.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test."
- << std::endl;
- return;
- }
-
const int iterations_num = 100;
- // Set number of iterations to 10.
- processCmdLine("perfdhcp -l " + loopback_iface
- + " -e address-and-prefix"
- + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
- int iterations_performed = 0;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -e address-and-prefix"
+ " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
// Set number of received packets equal to number of iterations.
// This simulates no packet drops.
bool use_templates = false;
// Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
// The test function generates server's responses and passes it to the
- // TestControl class methods for processing. The number of exchanges
- // actually performed is returned in 'iterations_performed' argument. If
- // processing is successful, the number of performed iterations should be
- // equal to the number of exchanges specified with the '-n' command line
- // parameter (10 in this case). All exchanged packets carry either IA_NA
- // or IA_PD options to simulate the address and prefix acquisition with
- // the single message and to verify that the IA_NA and IA_PD options
- // returned by the server are processed correctly.
- NakedTestControl tc;
- testPkt6Exchange(iterations_num, iterations_num, use_templates,
- iterations_performed, tc);
- // Actual number of iterations should be 10.
- EXPECT_EQ(10, iterations_performed);
+ // TestControl class methods for processing. All exchanged packets carry
+ // either IA_NA or IA_PD options to simulate the address and prefix
+ // acquisition with the single message and to verify that the IA_NA
+ // and IA_PD options returned by the server are processed correctly.
+ NakedTestControl tc(opt);
+ testPkt6Exchange(iterations_num, iterations_num, use_templates, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0);
}
TEST_F(TestControlTest, PacketTemplates) {
ASSERT_TRUE(createTemplateFile(file1, template1, template1.size() * 2));
ASSERT_TRUE(createTemplateFile(file2, template2, template2.size() * 2));
- NakedTestControl tc;
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1"
+ " -T " + file1 + " -T " + file2 + " all");
+ NakedTestControl tc(opt);
- ASSERT_NO_THROW(
- processCmdLine("perfdhcp -l 127.0.0.1"
- " -T " + file1 + " -T " + file2 + " all")
- );
- ASSERT_NO_THROW(tc.initPacketTemplates());
+ tc.initPacketTemplates();
TestControl::TemplateBuffer buf1;
TestControl::TemplateBuffer buf2;
- ASSERT_NO_THROW(buf1 = tc.getTemplateBuffer(0));
- ASSERT_NO_THROW(buf2 = tc.getTemplateBuffer(1));
+ buf1 = tc.getTemplateBuffer(0);
+ buf2 = tc.getTemplateBuffer(1);
ASSERT_EQ(template1.size(), buf1.size());
ASSERT_EQ(template2.size(), buf2.size());
EXPECT_TRUE(std::equal(template1.begin(), template1.end(), buf1.begin()));
// Size of the file is 2 times larger than binary data size and it is always
// even number. Substracting 1 makes file size odd.
ASSERT_TRUE(createTemplateFile(file3, template1, template1.size() * 2 - 1));
- ASSERT_NO_THROW(
- processCmdLine("perfdhcp -l 127.0.0.1 -T " + file3 + " all")
- );
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 -T " + file3 + " all");
EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange);
// Try to read empty file.
std::string file4("test4.hex");
ASSERT_TRUE(createTemplateFile(file4, template2, 0));
- ASSERT_NO_THROW(
- processCmdLine("perfdhcp -l 127.0.0.1 -T " + file4 + " all")
- );
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 -T " + file4 + " all");
EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange);
// Try reading file with non hexadecimal characters.
std::string file5("test5.hex");
ASSERT_TRUE(createTemplateFile(file5, template1, template1.size() * 2, true));
- ASSERT_NO_THROW(
- processCmdLine("perfdhcp -l 127.0.0.1 -T " + file5 + " all")
- );
+ processCmdLine(opt, "perfdhcp -l 127.0.0.1 -T " + file5 + " all");
EXPECT_THROW(tc.initPacketTemplates(), isc::BadValue);
}
// -xT - save first packet of each type for templates (useful for packet inspection)
// -o 200,abcdef1234 - send option 200 with hex content: ab:cd:ef:12:34
// -o 201,00 - send option 201 with hex content: 00
- std::string loopback(getLocalLoopback());
- ASSERT_NO_THROW(processCmdLine("perfdhcp -4 -l " + loopback
- + " -xT -L 10068 -o 200,abcdef1234 -o 201,00 -r 1 127.0.0.1"));
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -4 -l fake -xT -L 10068"
+ " -o 200,abcdef1234 -o 201,00 -r 1 127.0.0.1");
// Create test control and set up some basic defaults.
- NakedTestControl tc;
- tc.initializeStatsMgr();
+ NakedTestControl tc(opt);
tc.registerOptionFactories();
NakedTestControl::IncrementalGeneratorPtr gen(new NakedTestControl::IncrementalGenerator());
tc.setTransidGenerator(gen);
- // Socket is needed to send packets through the interface.
- int sock_handle = 0;
- ASSERT_NO_THROW(sock_handle = tc.openSocket());
- PerfSocket sock(sock_handle);
-
// Make tc send the packet. The first packet of each type is saved in templates.
- ASSERT_NO_THROW(tc.sendDiscover4(sock));
+ tc.sendDiscover4();
// Let's find the packet and see if it includes the right option.
auto pkt_it = tc.template_packets_v4_.find(DHCPDISCOVER);
// Test checks if regular packet exchange inserts the extra v4 options
// specified on command line.
TEST_F(TestControlTest, Packet4ExchangeExtraOpts) {
-
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback(getLocalLoopback());
- if (loopback.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test." << std::endl;
- return;
- }
-
// Important paramters here:
// -xT - save first packet of each type for templates (useful for packet inspection)
// -o 200,abcdef1234 - send option 200 with hex content: ab:cd:ef:12:34
// -o 201,00 - send option 201 with hex content: 00
const int iterations_num = 1;
- processCmdLine("perfdhcp -l " + loopback + " -4 " +
- "-o 200,abcdef1234 -o 201,00 " +
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake -4 -o 200,abcdef1234 -o 201,00 "
"-r 100 -n 10 -R 20 -xT -L 10547 127.0.0.1");
- int iterations_performed = 0;
- NakedTestControl tc;
+ NakedTestControl tc(opt);
tc.registerOptionFactories();
// Do the actual exchange.
- testPkt4Exchange(iterations_num, iterations_num, false, iterations_performed, tc);
- EXPECT_EQ(1, iterations_performed);
+ testPkt4Exchange(iterations_num, iterations_num, false, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Discovery + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::DO), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::DO), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RA), 0);
// Check if Discover was recored and if it contains options 200 and 201.
auto disc = tc.template_packets_v4_.find(DHCPDISCOVER);
// Test checks if regular packet exchange inserts the extra v6 options
// specified on command line.
TEST_F(TestControlTest, Packet6ExchangeExtraOpts) {
- // Get the local loopback interface to open socket on
- // it and test packets exchanges. We don't want to fail
- // the test if interface is not available.
- std::string loopback(getLocalLoopback());
- if (loopback.empty()) {
- std::cout << "Unable to find the loopback interface. Skip test."
- << std::endl;
- return;
- }
-
// Important paramters here:
// -xT - save first packet of each type for templates (useful for packet inspection)
// -o 200,abcdef1234 - send option 200 with hex content: ab:cd:ef:12:34
// -o 201,00 - send option 201 with hex content: 00
const int iterations_num = 1;
- processCmdLine("perfdhcp -l " + loopback
- + " -6 -e address-only"
- + " -xT -o 200,abcdef1234 -o 201,00 "
- + " -r 100 -n 10 -R 20 -L 10547 ::1");
- int iterations_performed = 0;
- // Set number of received packets equal to number of iterations.
- // This simulates no packet drops.
+ CommandOptions opt;
+ processCmdLine(opt, "perfdhcp -l fake"
+ " -6 -e address-only"
+ " -xT -o 200,abcdef1234 -o 201,00 "
+ " -r 100 -n 10 -R 20 -L 10547 ::1");
// Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges.
// The test function generates server's responses and passes it to the
- // TestControl class methods for processing. The number of exchanges
- // actually performed is returned in 'iterations_performed' argument.
+ // TestControl class methods for processing.
// First packet of each type is recorded as a template packet. The check
// inspects this template to see if the expected options are really there.
- NakedTestControl tc;
- testPkt6Exchange(iterations_num, iterations_num, false,
- iterations_performed, tc);
+ NakedTestControl tc(opt);
+ testPkt6Exchange(iterations_num, iterations_num, false, tc);
+
+ EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num);
+ EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0);
// Check if Solicit was recored and if it contains options 200 and 201.
auto sol = tc.template_packets_v6_.find(DHCPV6_SOLICIT);
auto req = tc.template_packets_v6_.find(DHCPV6_REQUEST);
ASSERT_TRUE(req != tc.template_packets_v6_.end());
checkOptions20x(req->second);
-
}
/// @brief Set packet timestamp.
///
/// Sets packet timestamp to arbitrary value.
- /// It is used by perfdhcp tool and should be used elsewhere.
+ /// It is used by perfdhcp tool and should not be used elsewhere.
void setTimestamp(boost::posix_time::ptime& timestamp) {
timestamp_ = timestamp;
}