123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <boost/shared_ptr.hpp>
- #include <exceptions/exceptions.h>
- #include <dhcp/dhcp4.h>
- #include <dhcp/dhcp6.h>
- #include <dhcp/pkt4.h>
- #include <dhcp/pkt6.h>
- #include <gtest/gtest.h>
- #include "../stats_mgr.h"
- using namespace std;
- using namespace isc;
- using namespace isc::dhcp;
- using namespace isc::perfdhcp;
- namespace {
- typedef StatsMgr<dhcp::Pkt4> StatsMgr4;
- typedef StatsMgr<dhcp::Pkt6> StatsMgr6;
- const uint32_t common_transid = 123;
- class StatsMgrTest : public ::testing::Test {
- public:
- StatsMgrTest() {
- }
- /// \brief Create DHCPv4 packet.
- ///
- /// Method creates DHCPv4 packet and updates its timestamp.
- ///
- /// \param msg_type DHCPv4 message type.
- /// \param transid transaction id for the packet.
- /// \return DHCPv4 packet.
- Pkt4* createPacket4(const uint8_t msg_type,
- const uint32_t transid) {
- Pkt4* pkt = new Pkt4(msg_type, transid);
- // Packet timestamp is normally updated by interface
- // manager on packets reception or send. Unit tests
- // do not use interface manager so we need to do it
- // ourselfs.
- pkt->updateTimestamp();
- return pkt;
- }
- /// \brief Create DHCPv6 packet.
- ///
- /// Method creates DHCPv6 packet and updates its timestamp.
- ///
- /// \param msg_type DHCPv6 message type.
- /// \param transid transaction id.
- /// \return DHCPv6 packet.
- Pkt6* createPacket6(const uint8_t msg_type,
- const uint32_t transid) {
- Pkt6* pkt = new Pkt6(msg_type, transid);
- // Packet timestamp is normally updated by interface
- // manager on packets reception or send. Unit tests
- // do not use interface manager so we need to do it
- // ourselfs.
- pkt->updateTimestamp();
- return pkt;
- }
- /// \brief Pass multiple DHCPv6 packets to Statistics Manager.
- ///
- /// Method simulates sending or receiving multiple DHCPv6 packets.
- ///
- /// \param stats_mgr Statistics Manager instance to be used.
- /// \param xchg_type packet exchange types.
- /// \param packet_type DHCPv6 packet type.
- /// \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,
- const StatsMgr6::ExchangeType xchg_type,
- const uint8_t packet_type,
- const int num_packets,
- const bool receive = false) {
- for (int i = 0; i < num_packets; ++i) {
- boost::shared_ptr<Pkt6>
- packet(createPacket6(packet_type, i));
- if (receive) {
- ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(xchg_type, packet);
- );
- } else {
- ASSERT_NO_THROW(
- stats_mgr->passSentPacket(xchg_type, packet)
- );
- }
- }
- }
- /// \brief Simulate DHCPv4 DISCOVER-OFFER with delay.
- ///
- /// Method simulates DHCPv4 DISCOVER-OFFER exchange. The OFFER packet
- /// creation is delayed by the specified number of seconds. This imposes
- /// different packet timestamps and affects delay counters in Statistics
- /// Manager.
- ///
- /// \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,
- 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)
- );
- // There is way to differentiate timstamps 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);
- boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER,
- transid));
- ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
- );
- // Calculate period between packets.
- boost::posix_time::ptime sent_time = sent_packet->getTimestamp();
- boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp();
- ASSERT_FALSE(sent_time.is_not_a_date_time());
- ASSERT_FALSE(rcvd_time.is_not_a_date_time());
- }
- };
- TEST_F(StatsMgrTest, Constructor) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
- EXPECT_DOUBLE_EQ(
- std::numeric_limits<double>::max(),
- stats_mgr->getMinDelay(StatsMgr4::XCHG_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_THROW(stats_mgr->getAvgDelay(StatsMgr4::XCHG_DO), InvalidOperation);
- EXPECT_THROW(stats_mgr->getStdDevDelay(StatsMgr4::XCHG_DO),
- InvalidOperation);
- EXPECT_THROW(stats_mgr->getAvgUnorderedLookupSetSize(StatsMgr4::XCHG_DO),
- InvalidOperation);
- }
- TEST_F(StatsMgrTest, Exchange) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- 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.
- EXPECT_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet),
- BadValue
- );
- EXPECT_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet),
- BadValue
- );
- // Adding DISCOVER-OFFER exchanges to be tracked by Stats Manager.
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
- // 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),
- BadValue
- );
- EXPECT_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_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)
- );
- EXPECT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_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);
- // Simulate sending number of solicit packets.
- const int solicit_packets_num = 10;
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_SA, DHCPV6_SOLICIT,
- solicit_packets_num);
- // Simulate sending number of request packets. It is important that
- // number of request packets is different then number of solicit
- // 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,
- request_packets_num);
- // Check if all packets are successfuly passed to packet lists.
- EXPECT_EQ(solicit_packets_num,
- stats_mgr->getSentPacketsNum(StatsMgr6::XCHG_SA));
- EXPECT_EQ(request_packets_num,
- stats_mgr->getSentPacketsNum(StatsMgr6::XCHG_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,
- solicit_packets_num, receive_packets);
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_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));
- EXPECT_EQ(request_packets_num,
- stats_mgr->getRcvdPacketsNum(StatsMgr6::XCHG_RR));
- }
- TEST_F(StatsMgrTest, SendReceiveSimple) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- 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);
- // The following attempt is expected to pass becase the right
- // exchange type is used.
- ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_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)
- );
- ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet)
- );
- EXPECT_EQ(1, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
- }
- TEST_F(StatsMgrTest, SendReceiveUnordered) {
- const int packets_num = 10;
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
- // Transaction ids of 10 packets to be sent and received.
- uint32_t transid[packets_num] =
- { 1, 1024, 2, 1025, 3, 1026, 4, 1027, 5, 1028 };
- for (int i = 0; i < packets_num; ++i) {
- boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER,
- transid[i]));
- ASSERT_NO_THROW(
- stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet)
- );
- }
- // We are simulating that received packets are coming in reverse order:
- // 1028, 5, 1027 ....
- for (int i = 0; i < packets_num; ++i) {
- boost::shared_ptr<Pkt4>
- rcvd_packet(createPacket4(DHCPDISCOVER,
- transid[packets_num - 1 - i]));
- ASSERT_NO_THROW(
- stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet);
- );
- }
- // All packets are expected to match (we did not drop any)
- EXPECT_EQ(0, stats_mgr->getOrphans(StatsMgr4::XCHG_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));
- }
- TEST_F(StatsMgrTest, Orphans) {
- const int packets_num = 6;
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_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)
- );
- }
- // 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);
- );
- }
- // The half of received packets are expected not to have matching
- // sent packet.
- EXPECT_EQ(packets_num / 2, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
- }
- TEST_F(StatsMgrTest, Delays) {
- boost::shared_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
- // Send DISCOVER, wait 2s and receive OFFER. This will affect
- // counters in Stats Manager.
- const unsigned int delay1 = 2;
- passDOPacketsWithDelay(stats_mgr, 2, common_transid);
- // 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),
- std::numeric_limits<double>::max());
- EXPECT_GT(stats_mgr->getMinDelay(StatsMgr4::XCHG_DO), 1);
- // Max delay is supposed to the same value as mininimum
- // or maximum delay.
- EXPECT_GT(stats_mgr->getMaxDelay(StatsMgr4::XCHG_DO), 1);
- // Delay sums are now the same as minimum or maximum delay.
- EXPECT_GT(stats_mgr->getAvgDelay(StatsMgr4::XCHG_DO), 1);
- // Simulate another DISCOVER-OFFER exchange with delay between
- // sent and received packets. Delay is now shorter than earlier
- // so standard deviation of delay will now increase.
- 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);
- }
- TEST_F(StatsMgrTest, CustomCounters) {
- boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
- // Specify counter keys and names.
- const std::string too_short_key("tooshort");
- const std::string too_short_name("Too short packets");
- const std::string too_late_key("toolate");
- const std::string too_late_name("Packets sent too late");
- // Add two custom counters.
- stats_mgr->addCustomCounter(too_short_key, too_short_name);
- stats_mgr->addCustomCounter(too_late_key, too_late_name);
- // Increment one of the counters 10 times.
- const uint64_t tooshort_num = 10;
- for (uint64_t i = 0; i < tooshort_num; ++i) {
- stats_mgr->IncrementCounter(too_short_key);
- }
- // Increment another counter by 5 times.
- const uint64_t toolate_num = 5;
- for (uint64_t i = 0; i < toolate_num; ++i) {
- stats_mgr->IncrementCounter(too_late_key);
- }
- // Check counter's current value and name.
- StatsMgr4::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 =
- stats_mgr->getCounter(too_late_key);
- EXPECT_EQ(too_late_name, toolate_counter->getName());
- EXPECT_EQ(toolate_num, toolate_counter->getValue());
- }
- TEST_F(StatsMgrTest, PrintStats) {
- std::cout << "This unit test is checking statistics printing "
- << "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);
- // 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,
- packets_num);
- passMultiplePackets6(stats_mgr, StatsMgr6::XCHG_SA, DHCPV6_ADVERTISE,
- packets_num, true);
- // This function will print statistics even if packets are not
- // archived because it relies on counters. There is at least one
- // exchange needed to count the average delay and std deviation.
- EXPECT_NO_THROW(stats_mgr->printStats());
- // Printing timestamps is expected to fail because by default we
- // disable packets archiving mode. Without packets we can't get
- // timestamps.
- EXPECT_THROW(stats_mgr->printTimestamps(), isc::InvalidOperation);
- // 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);
- // Timestamps should now get printed because packets have been preserved.
- EXPECT_NO_THROW(stats_mgr2->printTimestamps());
- }
- }
|