boost::multi_index::sequenced<>,
boost::multi_index::hashed_non_unique<
boost::multi_index::global_fun<
- boost::shared_ptr<T>, uint32_t, &ExchangeStats::transid_hash
+ boost::shared_ptr<T>,
+ uint32_t,
+ &ExchangeStats::transid_hash
>
>
>
square_sum_delay_(0.),
ordered_lookups_(0),
unordered_lookup_size_sum_(0),
- unordered_lookups_(0) {
+ unordered_lookups_(0),
+ sent_packets_num_(0),
+ rcvd_packets_num_(0) {
sent_packets_cache_ = sent_packets_.begin();
}
///
/// \param packet packet object to be added.
void appendSent(const boost::shared_ptr<T> packet) {
+ ++sent_packets_num_;
sent_packets_.template get<0>().push_back(packet);
}
///
/// \param packet packet object to be added.
void appendRcvd(const boost::shared_ptr<T> packet) {
+ ++rcvd_packets_num_;
rcvd_packets_.template get<0>().push_back(packet);
}
+ /// \brief Update delay counters.
+ ///
+ /// Method updates delay counters based on timestamps of
+ /// sent and received packets.
+ ///
+ /// \param sent_packet sent packet
+ /// \param rcvd_packet received packet
+ /// \throw isc::Unexpected if failed to calculate timestamps
+ void updateDelays(const boost::shared_ptr<T> sent_packet,
+ const boost::shared_ptr<T> rcvd_packet) {
+ boost::posix_time::ptime sent_time = sent_packet->getTimestamp();
+ boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp();
+
+ if (sent_time.is_not_a_date_time() ||
+ rcvd_time.is_not_a_date_time()) {
+ isc_throw(Unexpected,
+ "Timestamp must be set for sent and "
+ "received packet to measure RTT");
+ }
+ boost::posix_time::time_period period(sent_time, rcvd_time);
+ // We don't bother calculating deltas in nanoseconds. It is much
+ // more convenient to use seconds instead because we are going to
+ // sum them up.
+ double delta =
+ static_cast<double>(period.length().total_nanoseconds()) / 1e9;
+
+ if (delta < 0) {
+ isc_throw(Unexpected, "Sent packet's timestamp must not be "
+ "greater than received packet's timestamp");
+ }
+
+ // Record the minimum delay between sent and received packets.
+ if (delta < min_delay_) {
+ min_delay_ = delta;
+ }
+ // Record the maximum delay between sent and received packets.
+ if (delta > max_delay_) {
+ max_delay_ = delta;
+ }
+ // Update delay sum and square sum. That will be used to calculate
+ // mean delays.
+ sum_delay_ += delta;
+ square_sum_delay_ += delta * delta;
+ }
+
/// \brief Find packet on the list of sent packets.
///
/// Method finds packet with specified transaction id on the list
/// not found
boost::shared_ptr<T> findSent(const uint32_t transid) {
if (sent_packets_.size() == 0) {
+ // List of sent packets is empty so there is no sense
+ // to continue looking fo the packet. It also means
+ // that the received packet we got has no corresponding
+ // sent packet so orphans counter has to be updated.
++orphans_;
return boost::shared_ptr<T>();
} else if (sent_packets_cache_ == sent_packets_.end()) {
+ // Even if there are still many unmatched packets on the
+ // list we might hit the end of it because of unordered
+ // lookups. The next logical step is to reset cache.
sent_packets_cache_ = sent_packets_.begin();
}
+ // With this variable we will be signalling success or failure
+ // to find the packet.
bool packet_found = false;
+ // Most likely responses are sent from the server in the same
+ // order as client's requests to the server. We are caching
+ // next sent packet and first try to match with it the next
+ // incoming packet. We are successful if there is no
+ // packet drop or out of order packets sent. This is actually
+ // the fastest way to look for packets.
if ((*sent_packets_cache_)->getTransid() == transid) {
++ordered_lookups_;
packet_found = true;
} else {
+ // If we are here, it means that we were unable to match the
+ // next incoming packet with next sent packet so we need to
+ // take a little more expensive approach to look packets using
+ // alternative index (transaction id & 1023).
PktListTransidIndex& idx = sent_packets_.template get<1>();
+ // Packets are grouped using trasaction id masking with value
+ // of 1023. For instance, packets with transaction id equal to
+ // 1, 1024 ... will belong to the same group (a.k.a. bucket).
+ // When using alternative index we don't find the packet but
+ // bucket of packets and need to iterate through the bucket
+ // to find the one that has desired transaction id.
std::pair<PktListTransidIterator,PktListTransidIterator> p =
idx.equal_range(transid & 1023);
+ // We want to keep statistics of unordered lookups to make
+ // sure that there is a right balance before number of
+ // unordered lookups and ordered lookups. If number of unordered
+ // lookups is high it may mean that many packets are lost or
+ // sent out of order.
++unordered_lookups_;
+ // We also want to keep the mean value of the bucket. The lower
+ // bucket size the better. If bucket sizes appear to big we
+ // might want to increase number of buckets.
unordered_lookup_size_sum_ += std::distance(p.first, p.second);
for (PktListTransidIterator it = p.first; it != p.second;
++it) {
}
if (!packet_found) {
+ // If we are here, it means that both ordered lookup and
+ // unordered lookup failed. Searched packet is not on the list.
++orphans_;
return boost::shared_ptr<T>();
}
boost::shared_ptr<T> sent_packet(*sent_packets_cache_);
- ++sent_packets_cache_;
+ // If packet was found, we assume it will be never searched
+ // again. We want to delete this packet from the list to
+ // improve performance of future searches.
+ sent_packets_cache_ = eraseSent(sent_packets_cache_);
return sent_packet;
}
- /// \brief Update delay counters.
- ///
- /// Method updates delay counters based on timestamps of
- /// sent and received packets.
- ///
- /// \param sent_packet sent packet
- /// \param rcvd_packet received packet
- /// \throw isc::Unexpected if failed to calculate timestamps
- void updateDelays(const boost::shared_ptr<T> sent_packet,
- const boost::shared_ptr<T> rcvd_packet) {
- boost::posix_time::ptime sent_time = sent_packet->getTimestamp();
- boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp();
-
- if (sent_time.is_not_a_date_time() ||
- rcvd_time.is_not_a_date_time()) {
- isc_throw(Unexpected,
- "Timestamp must be set for sent and "
- "received packet to measure RTT");
- }
- boost::posix_time::time_period period(sent_time, rcvd_time);
- double delta =
- static_cast<double>(period.length().total_nanoseconds()) / 1e9;
-
- if (delta < 0) {
- isc_throw(Unexpected, "Sent packet's timestamp must not be "
- "greater than received packet's timestamp");
- }
-
- if (delta < min_delay_) {
- min_delay_ = delta;
- }
- if (delta > max_delay_) {
- max_delay_ = delta;
- }
- sum_delay_ += delta;
- square_sum_delay_ += delta * delta;
- }
-
/// \brief Return minumum delay between sent and received packet.
///
/// Method returns minimum delay between sent and received packet.
///
/// \return average unordered lookup set size.
double getAvgUnorderedLookupSetSize() const {
+ if (unordered_lookups_ == 0) {
+ return 0.;
+ }
return static_cast<double>(unordered_lookup_size_sum_) /
static_cast<double>(unordered_lookups_);
}
/// \return number of unordered lookups.
uint64_t getUnorderedLookups() const { return unordered_lookups_; }
-
/// \brief Return number of ordered sent packets lookups
///
/// Method returns number of ordered sent packet lookups.
///
/// \return number of ordered lookups.
uint64_t getOrderedLookups() const { return ordered_lookups_; }
+
+ /// \brief Return total number of sent packets
+ ///
+ /// Method returns total number of sent packets.
+ ///
+ /// \return number of sent packets.
+ uint64_t getSentPacketsNum() const {
+ return sent_packets_num_;
+ }
+
+ /// \brief Return total number of received packets
+ ///
+ /// Method returns total number of received packets.
+ ///
+ /// \return number of received packets.
+ uint64_t getRcvdPacketsNum() const {
+ return rcvd_packets_num_;
+ }
+
private:
/// \brief Private default constructor.
/// class to specify exchange type explicitely.
ExchangeStats();
+
+ /// \brief Erase packet from the list of sent packets.
+ ///
+ /// Method erases packet from the list of sent packets.
+ ///
+ /// \param it iterator pointing to packet to be erased.
+ /// \return iterator pointing to packet following erased
+ /// packet or sent_packets_.end() if packet not found.
+ PktListIterator eraseSent(const PktListIterator it) {
+ return sent_packets_.template get<0>().erase(it);
+ }
+
ExchangeType xchg_type_; ///< Packet exchange type.
PktList sent_packets_; ///< List of sent packets.
uint64_t ordered_lookups_; ///< Number of ordered sent packets
///< lookups.
+ uint64_t sent_packets_num_; ///< Total number of sent packets.
+ uint64_t rcvd_packets_num_; ///< Total number of received packets.
};
/// Pointer to ExchangeStats.
}
}
+ /// \brief Return minumum delay between sent and received packet.
+ ///
+ /// Method returns minimum delay between sent and received packet
+ /// for specified exchange type.
+ ///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
+ /// \return minimum delay between packets.
+ double getMinDelay(const ExchangeType xchg_type) const {
+ ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+ return xchg_stats->getMinDelay();
+ }
+
+ /// \brief Return maxmimum delay between sent and received packet.
+ ///
+ /// Method returns maximum delay between sent and received packet
+ /// for specified exchange type.
+ ///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
+ /// \return maximum delay between packets.
+ double getMaxDelay(const ExchangeType xchg_type) const {
+ ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+ return xchg_stats->getMaxDelay();
+ }
+
+ /// \brief Return sum of delays between sent and received packets.
+ ///
+ /// Method returns sum of delays between sent and received packets
+ /// for specified exchange type.
+ ///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
+ /// \return sum of delays between sent and received packets.
+ double getSumDelay(const ExchangeType xchg_type) const {
+ ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+ return xchg_stats->getSumDelay();
+ }
+
+ /// \brief Return square sum of delays between sent and received
+ /// packets.
+ ///
+ /// Method returns square sum of delays between sent and received
+ /// packets for specified exchange type.
+ ///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
+ /// \return square sum of delays between sent and received packets.
+ double getSquareSumDelay(const ExchangeType xchg_type) const {
+ ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+ return xchg_stats->getSquareSumDelay();
+ }
+
/// \brief Return number of orphant packets.
///
/// Method returns number of orphant packets for specified
/// unordered packet lookup using transaction id.
///
/// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
/// \return average unordered lookup set size.
double getAvgUnorderedLookupSetSize(const ExchangeType xchg_type) const {
ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
/// out of order by server - transaction id of received
/// packet does not match transaction id of next sent packet.
///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
/// \return number of unordered lookups.
uint64_t getUnorderedLookups(const ExchangeType xchg_type) const {
ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
/// If packets are skipped or received out of order, lookup
/// function will use unordered lookup (with hash table).
///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
/// \return number of ordered lookups.
uint64_t getOrderedLookups(const ExchangeType xchg_type) const {
ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
return xchg_stats->getOrderedLookups();
}
-private:
+ /// \brief Return total number of sent packets
+ ///
+ /// Method returns total number of sent packets for specified
+ /// exchange type.
+ ///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
+ /// \return number of sent packets.
+ uint64_t getSentPacketsNum(const ExchangeType xchg_type) const {
+ ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+ return xchg_stats->getSentPacketsNum();
+ }
+ /// \brief Return total number of received packets
+ ///
+ /// Method returns total number of received packets for specified
+ /// exchange type.
+ ///
+ /// \param xchg_type exchange type.
+ /// \throw isc::BadValue if invalid exchange type specified.
+ /// \return number of received packets.
+ uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const {
+ ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+ return xchg_stats->getRcvdPacketsNum();
+ }
+private:
/// \brief Return exchange stats object for given exchange type
///
/// Method returns exchange stats object for given exchange type.
#include <exceptions/exceptions.h>
#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
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;
}
+
+ 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;
+ }
+
+ 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)
+ );
+ }
+ }
+ }
+
};
TEST_F(StatsMgrTest, Constructor) {
boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+ stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
+ EXPECT_EQ(
+ std::numeric_limits<double>::max(),
+ stats_mgr->getMinDelay(StatsMgr4::XCHG_DO)
+ );
+ EXPECT_EQ(0, stats_mgr->getMaxDelay(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(0, stats_mgr->getSumDelay(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(0, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
+ EXPECT_EQ(0, stats_mgr->getSquareSumDelay(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));
+
+ double avg_size = 0.;
+ ASSERT_NO_THROW(
+ avg_size = stats_mgr->getAvgUnorderedLookupSetSize(StatsMgr4::XCHG_DO);
+ );
+ EXPECT_EQ(0., avg_size);
}
-TEST_F(StatsMgrTest, Exchanges) {
+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
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
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)
);
);
}
+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,
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)
);
- EXPECT_NO_THROW(
+ // 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)
);
- EXPECT_NO_THROW(
+ ASSERT_NO_THROW(
stats_mgr->passRcvdPacket(StatsMgr4::XCHG_DO, rcvd_packet)
);
+ EXPECT_EQ(1, stats_mgr->getOrphans(StatsMgr4::XCHG_DO));
}
TEST_F(StatsMgrTest, SendReceiveUnordered) {
boost::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
- uint32_t transid[packets_num] = { 1, 1024, 2, 1025, 3, 1026, 4, 1027, 5, 1028 };
+ // 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]));
);
}
+ // 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]));
+ 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));
- EXPECT_EQ(10, stats_mgr->getUnorderedLookups(StatsMgr4::XCHG_DO));
- std::cout << stats_mgr->getAvgUnorderedLookupSetSize(StatsMgr4::XCHG_DO) << std::endl;
+ // 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) {
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::scoped_ptr<StatsMgr4> stats_mgr(new StatsMgr4());
+ stats_mgr->addExchangeStats(StatsMgr4::XCHG_DO);
+
+ boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER,
+ common_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 two 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 2 seconds to test packet delays" << std::endl;
+ sleep(2);
+
+ boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER,
+ common_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());
+
+ boost::posix_time::time_period period(sent_time, rcvd_time);
+
+ // 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->getSumDelay(StatsMgr4::XCHG_DO), 1);
+ EXPECT_GT(stats_mgr->getSquareSumDelay(StatsMgr4::XCHG_DO), 1);
+}
+
}