Browse Source

[3181] Moved perfdhcp rate control logic to a new class.

Marcin Siodelski 11 years ago
parent
commit
3c33b14cb4

+ 1 - 0
tests/tools/perfdhcp/Makefile.am

@@ -25,6 +25,7 @@ perfdhcp_SOURCES += perf_pkt6.cc perf_pkt6.h
 perfdhcp_SOURCES += perf_pkt4.cc perf_pkt4.h
 perfdhcp_SOURCES += packet_storage.h
 perfdhcp_SOURCES += pkt_transform.cc pkt_transform.h
+perfdhcp_SOURCES += rate_control.cc rate_control.h
 perfdhcp_SOURCES += stats_mgr.h
 perfdhcp_SOURCES += test_control.cc test_control.h
 libb10_perfdhcp___la_CXXFLAGS = $(AM_CXXFLAGS)

+ 46 - 116
tests/tools/perfdhcp/test_control.cc

@@ -98,6 +98,21 @@ TestControl::TestControl() {
 }
 
 void
+TestControl::checkLateMessages(RateControl& rate_control) {
+    // If diagnostics is disabled, there is no need to log late sent messages.
+    // If it is enabled and the rate control object indicates that the last
+    // sent message was late, bump up the counter in Stats Manager.
+    if (rate_control.isLateSent() && testDiags('i')) {
+        CommandOptions& options = CommandOptions::instance();
+        if (options.getIpVersion() == 4) {
+            stats_mgr4_->incrementCounter("latesend");
+        } else if (options.getIpVersion() == 6) {
+            stats_mgr6_->incrementCounter("latesend");
+        }
+    }
+}
+
+void
 TestControl::cleanCachedPackets() {
     CommandOptions& options = CommandOptions::instance();
     // When Renews are not sent, Reply packets are not cached so there
@@ -504,23 +519,25 @@ TestControl::getCurrentTimeout() const {
     ptime now(microsec_clock::universal_time());
     // Check that we haven't passed the moment to send the next set of
     // packets.
-    if (now >= send_due_ ||
-        (options.getRenewRate() != 0 && now >= renew_due_) ||
-        (options.getReleaseRate() != 0 && now >= release_due_)) {
+    if (now >= basic_rate_control_.getDue() ||
+        (options.getRenewRate() != 0 && now >= renew_rate_control_.getDue()) ||
+        (options.getReleaseRate() != 0 &&
+         now >= release_rate_control_.getDue())) {
         return (0);
     }
 
     // Let's assume that the due time for Solicit is the soonest.
-    ptime due = send_due_;
+    ptime due = basic_rate_control_.getDue();
     // If we are sending Renews and due time for Renew occurs sooner,
     // set the due time to Renew due time.
-    if ((options.getRenewRate()) != 0 && (renew_due_ < due)) {
-        due = renew_due_;
+    if ((options.getRenewRate()) != 0 && (renew_rate_control_.getDue() < due)) {
+        due = renew_rate_control_.getDue();
     }
     // If we are sending Releases and the due time for Release occurs
     // sooner than the current due time, let's use the due for Releases.
-    if ((options.getReleaseRate() != 0) && (release_due_ < due)) {
-        due = release_due_;
+    if ((options.getReleaseRate() != 0) &&
+        (release_rate_control_.getDue() < due)) {
+        due = release_rate_control_.getDue();
     }
     // Return the timeout in microseconds.
     return (time_period(now, due).length().total_microseconds());
@@ -554,49 +571,6 @@ TestControl::getElapsedTime(const T& pkt1, const T& pkt2) {
     return(elapsed_period.length().total_milliseconds());
 }
 
-
-uint64_t
-TestControl::getNextExchangesNum(const boost::posix_time::ptime& send_due,
-                                 const int rate) {
-    CommandOptions& options = CommandOptions::instance();
-    // Get current time.
-    ptime now(microsec_clock::universal_time());
-    if (now >= send_due) {
-        // Reset number of exchanges.
-        uint64_t due_exchanges = 0;
-        // If rate is specified from the command line we have to
-        // synchornize with it.
-        if (rate != 0) {
-            time_period period(send_due, now);
-            time_duration duration = period.length();
-            // due_factor indicates the number of seconds that
-            // sending next chunk of packets will take.
-            double due_factor = duration.fractional_seconds() /
-                time_duration::ticks_per_second();
-            due_factor += duration.total_seconds();
-            // Multiplying due_factor by expected rate gives the number
-            // of exchanges to be initiated.
-            due_exchanges = static_cast<uint64_t>(due_factor * rate);
-            // We want to make sure that at least one packet goes out.
-            if (due_exchanges == 0) {
-                due_exchanges = 1;
-            }
-            // We should not exceed aggressivity as it could have been
-            // restricted from command line.
-            if (due_exchanges > options.getAggressivity()) {
-                due_exchanges = options.getAggressivity();
-            }
-        } else {
-            // Rate is not specified so we rely on aggressivity
-            // which is the number of packets to be sent in
-            // one chunk.
-            due_exchanges = options.getAggressivity();
-        }
-        return (due_exchanges);
-    }
-    return (0);
-}
-
 int
 TestControl::getRandomOffset(const int arg_idx) const {
     int rand_offset = CommandOptions::instance().getIpVersion() == 4 ?
@@ -1280,14 +1254,16 @@ TestControl::registerOptionFactories() const {
 
 void
 TestControl::reset() {
-    send_due_ = microsec_clock::universal_time();
-    last_sent_ = send_due_;
-    last_report_ = send_due_;
-    renew_due_ = send_due_;
-    release_due_ = send_due_;
-    last_renew_ = send_due_;
-    last_release_ = send_due_;
+    CommandOptions& options = CommandOptions::instance();
+    basic_rate_control_.setAggressivity(options.getAggressivity());
+    basic_rate_control_.setRate(options.getRate());
+    renew_rate_control_.setAggressivity(options.getAggressivity());
+    renew_rate_control_.setRate(options.getRenewRate());
+    release_rate_control_.setAggressivity(options.getAggressivity());
+    release_rate_control_.setRate(options.getReleaseRate());
+
     transid_gen_.reset();
+    last_report_ = microsec_clock::universal_time();
     // Actual generators will have to be set later on because we need to
     // get command line parameters first.
     setTransidGenerator(NumberGeneratorPtr());
@@ -1353,11 +1329,10 @@ TestControl::run() {
     // Initialize Statistics Manager. Release previous if any.
     initializeStatsMgr();
     for (;;) {
-        // Calculate send due based on when last exchange was initiated.
-        updateSendDue(last_sent_, options.getRate(), send_due_);
         // Calculate number of packets to be sent to stay
         // catch up with rate.
-        uint64_t packets_due = getNextExchangesNum(send_due_, options.getRate());
+        uint64_t packets_due = basic_rate_control_.getOutboundMessageCount();
+        checkLateMessages(basic_rate_control_);
         if ((packets_due == 0) && testDiags('i')) {
             if (options.getIpVersion() == 4) {
                 stats_mgr4_->incrementCounter("shortwait");
@@ -1383,9 +1358,9 @@ TestControl::run() {
         // 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.getIpVersion() == 6) && (options.getRenewRate() != 0)) {
-            updateSendDue(last_renew_, options.getRenewRate(), renew_due_);
             uint64_t renew_packets_due =
-                getNextExchangesNum(renew_due_, options.getRenewRate());
+                renew_rate_control_.getOutboundMessageCount();
+            checkLateMessages(renew_rate_control_);
             // Send Renew messages.
             sendMultipleMessages6(socket, DHCPV6_RENEW, renew_packets_due);
         }
@@ -1393,10 +1368,9 @@ TestControl::run() {
         // 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)) {
-            updateSendDue(last_release_, options.getReleaseRate(),
-                          release_due_);
             uint64_t release_packets_due =
-                getNextExchangesNum(release_due_, options.getReleaseRate());
+                release_rate_control_.getOutboundMessageCount();
+            checkLateMessages(release_rate_control_);
             // Send Release messages.
             sendMultipleMessages6(socket, DHCPV6_RELEASE, release_packets_due);
         }
@@ -1494,7 +1468,7 @@ TestControl::saveFirstPacket(const Pkt6Ptr& pkt) {
 void
 TestControl::sendDiscover4(const TestControlSocket& socket,
                            const bool preload /*= false*/) {
-    last_sent_ = microsec_clock::universal_time();
+    basic_rate_control_.updateSendTime();
     // Generate the MAC address to be passed in the packet.
     uint8_t randomized = 0;
     std::vector<uint8_t> mac_address = generateMacAddress(randomized);
@@ -1539,9 +1513,7 @@ void
 TestControl::sendDiscover4(const TestControlSocket& socket,
                            const std::vector<uint8_t>& template_buf,
                            const bool preload /* = false */) {
-    // last_sent_ has to be updated for each function that initiates
-    // new transaction. The packet exchange synchronization relies on this.
-    last_sent_ = microsec_clock::universal_time();
+    basic_rate_control_.updateSendTime();
     // Get the first argument if mulitple the same arguments specified
     // in the command line. First one refers to DISCOVER packets.
     const uint8_t arg_idx = 0;
@@ -1599,9 +1571,9 @@ TestControl::sendMessageFromReply(const uint16_t msg_type,
     }
     // We track the timestamp of last Release and Renew in different variables.
     if (msg_type == DHCPV6_RENEW) {
-        last_renew_ = microsec_clock::universal_time();
+        renew_rate_control_.updateSendTime();
     } else {
-        last_release_ = microsec_clock::universal_time();
+        release_rate_control_.updateSendTime();
     }
     Pkt6Ptr reply = reply_storage_.getRandom();
     if (!reply) {
@@ -1960,7 +1932,7 @@ TestControl::sendRequest6(const TestControlSocket& socket,
 void
 TestControl::sendSolicit6(const TestControlSocket& socket,
                           const bool preload /*= false*/) {
-    last_sent_ = microsec_clock::universal_time();
+    basic_rate_control_.updateSendTime();
     // Generate DUID to be passed to the packet
     uint8_t randomized = 0;
     std::vector<uint8_t> duid = generateDuid(randomized);
@@ -2009,7 +1981,7 @@ void
 TestControl::sendSolicit6(const TestControlSocket& socket,
                           const std::vector<uint8_t>& template_buf,
                           const bool preload /*= false*/) {
-    last_sent_ = microsec_clock::universal_time();
+    basic_rate_control_.updateSendTime();
     const int arg_idx = 0;
     // Get transaction id offset.
     size_t transid_offset = getTransactionIdOffset(arg_idx);
@@ -2108,47 +2080,5 @@ TestControl::testDiags(const char diag) const {
     return (false);
 }
 
-void
-TestControl::updateSendDue(const boost::posix_time::ptime& last_sent,
-                           const int rate,
-                           boost::posix_time::ptime& send_due) {
-    // If default constructor was called, this should not happen but
-    // if somebody has changed default constructor it is better to
-    // keep this check.
-    if (last_sent.is_not_a_date_time()) {
-        isc_throw(Unexpected, "time of last sent packet not initialized");
-    }
-    // Get the expected exchange rate.
-    CommandOptions& options = CommandOptions::instance();
-    // If rate was not specified we will wait just one clock tick to
-    // send next packet. This simulates best effort conditions.
-    long duration = 1;
-    if (rate != 0) {
-        // We use number of ticks instead of nanoseconds because
-        // nanosecond resolution may not be available on some
-        // machines. Number of ticks guarantees the highest possible
-        // timer resolution.
-        duration = time_duration::ticks_per_second() / rate;
-    }
-    // Calculate due time to initiate next chunk of exchanges.
-    send_due = last_sent + time_duration(0, 0, 0, duration);
-    // Check if it is already due.
-    ptime now(microsec_clock::universal_time());
-    // \todo verify if this condition is not too tight. In other words
-    // verify if this will not produce too many late sends.
-    // We might want to look at this once we are done implementing
-    // microsecond timeouts in IfaceMgr.
-    if (now > send_due) {
-        if (testDiags('i')) {
-            if (options.getIpVersion() == 4) {
-                stats_mgr4_->incrementCounter("latesend");
-            } else if (options.getIpVersion() == 6) {
-                stats_mgr6_->incrementCounter("latesend");
-            }
-        }
-    }
-}
-
-
 } // namespace perfdhcp
 } // namespace isc

+ 19 - 43
tests/tools/perfdhcp/test_control.h

@@ -15,8 +15,9 @@
 #ifndef TEST_CONTROL_H
 #define TEST_CONTROL_H
 
-#include "packet_storage.h"
-#include "stats_mgr.h"
+#include <tests/tools/perfdhcp/packet_storage.h>
+#include <tests/tools/perfdhcp/rate_control.h>
+#include <tests/tools/perfdhcp/stats_mgr.h>
 
 #include <dhcp/iface_mgr.h>
 #include <dhcp/dhcp6.h>
@@ -491,21 +492,6 @@ protected:
     /// \return A current timeout in microseconds.
     uint32_t getCurrentTimeout() const;
 
-    /// \brief Returns number of exchanges to be started.
-    ///
-    /// Method returns number of new exchanges to be started as soon
-    /// as possible to satisfy expected rate. Calculation used here
-    /// is based on current time, due time calculated with
-    /// \ref updateSendDue function and expected rate.
-    ///
-    /// \param send_due Due time to initiate next chunk set exchanges.
-    /// \param rate A rate at which exchanges are initiated.
-    ///
-    /// \return number of exchanges to be started immediately.
-    static uint64_t
-    getNextExchangesNum(const boost::posix_time::ptime& send_due,
-                        const int rate);
-
     /// \brief Return template buffer.
     ///
     /// Method returns template buffer at specified index.
@@ -916,21 +902,18 @@ protected:
     /// \return true if diagnostics flag has been set.
     bool testDiags(const char diag) const;
 
-    /// \brief Update due time to initiate next chunk of exchanges.
+protected:
+
+    /// \brief Increments counter of late sent messages if required.
     ///
-    /// Method updates due time to initiate next chunk of exchanges.
-    /// Function takes current time, last sent packet's time and
-    /// expected rate in its calculations.
+    /// This function checks if the message or set of messages of a given type,
+    /// were sent later than their due time. If they were sent late, it is
+    /// an indication that the perfdhcp doesn't catch up with the desired rate
+    /// for sending messages.
     ///
-    /// \param last_sent A time when the last exchange was initiated.
-    /// \param rate A rate at which exchangesa re initiated
-    /// \param [out] send_due A reference to the time object to be updated
-    /// with the next due time.
-    void updateSendDue(const boost::posix_time::ptime& last_sent,
-                       const int rate,
-                       boost::posix_time::ptime& send_due);
-
-protected:
+    /// \param rate_control An object tracking due times for a particular
+    /// type of messages.
+    void checkLateMessages(RateControl& rate_control);
 
     /// \brief Copies IA_NA or IA_PD option from one packet to another.
     ///
@@ -1073,20 +1056,13 @@ protected:
     std::string vector2Hex(const std::vector<uint8_t>& vec,
                            const std::string& separator = "") const;
 
-protected:
+    /// \brief A rate control class for Discover and Solicit messages.
+    RateControl basic_rate_control_;
+    /// \brief A rate control class for Renew messages.
+    RateControl renew_rate_control_;
+    /// \brief A rate control class for Release messages.
+    RateControl release_rate_control_;
 
-    boost::posix_time::ptime send_due_;    ///< Due time to initiate next chunk
-                                           ///< of exchanges.
-    boost::posix_time::ptime last_sent_;   ///< Indicates when the last exchange
-                                           ///< was initiated.
-    boost::posix_time::ptime renew_due_;   ///< Due time to send next set of
-                                           ///< Renew requests.
-    boost::posix_time::ptime release_due_; ///< Due time to send next set of
-                                           ///< Release requests.
-    boost::posix_time::ptime last_renew_;  ///< Indicates when the last Renew
-                                           ///< was attempted.
-    boost::posix_time::ptime last_release_;///< Indicates when the last Release
-                                           ///< was attempted.
     boost::posix_time::ptime last_report_; ///< Last intermediate report time.
 
     StatsMgr4Ptr stats_mgr4_;  ///< Statistics Manager 4.

+ 2 - 0
tests/tools/perfdhcp/tests/Makefile.am

@@ -26,6 +26,7 @@ run_unittests_SOURCES += perf_pkt6_unittest.cc
 run_unittests_SOURCES += perf_pkt4_unittest.cc
 run_unittests_SOURCES += localized_option_unittest.cc
 run_unittests_SOURCES += packet_storage_unittest.cc
+run_unittests_SOURCES += rate_control_unittest.cc
 run_unittests_SOURCES += stats_mgr_unittest.cc
 run_unittests_SOURCES += test_control_unittest.cc
 run_unittests_SOURCES += command_options_helper.h
@@ -33,6 +34,7 @@ run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/command_options.cc
 run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/pkt_transform.cc
 run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt6.cc
 run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt4.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/rate_control.cc
 run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/test_control.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)

+ 187 - 0
tests/tools/perfdhcp/tests/rate_control_unittest.cc

@@ -0,0 +1,187 @@
+// Copyright (C) 2013 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 <exceptions/exceptions.h>
+#include <tests/tools/perfdhcp/rate_control.h>
+#include <gtest/gtest.h>
+
+
+using namespace isc;
+using namespace isc::perfdhcp;
+
+/// \brief A class which exposes protected methods and members of the
+/// RateControl class (under test).
+class NakedRateControl : public RateControl {
+public:
+
+    /// \brief Default constructor.
+    NakedRateControl()
+        : RateControl() {
+    }
+
+    /// \brief Constructor which sets up the rate and aggressivity.
+    ///
+    /// \param rate A rate at which messages are sent.
+    /// \param aggressivity A value of aggressivity. This value controls the
+    /// maximal number of messages sent in one chunk.
+    NakedRateControl(const int rate, const int aggressivity)
+        : RateControl(rate, aggressivity) {
+    }
+
+    using RateControl::currentTime;
+    using RateControl::updateSendTime;
+    using RateControl::updateSendDue;
+    using RateControl::send_due_;
+    using RateControl::last_sent_;
+    using RateControl::late_sent_;
+
+};
+
+// Test default constructor.
+TEST(RateControl, constructorDefault) {
+    NakedRateControl rc;
+    EXPECT_EQ(1, rc.getAggressivity());
+    EXPECT_EQ(0, rc.getRate());
+    EXPECT_FALSE(rc.getDue().is_not_a_date_time());
+    EXPECT_FALSE(rc.last_sent_.is_not_a_date_time());
+    EXPECT_FALSE(rc.isLateSent());
+}
+
+// Test the constructor which sets the rate and aggressivity.
+TEST(RateControl, constructor) {
+    // Call the constructor and verify that it sets the appropriate
+    // values.
+    NakedRateControl rc1(3, 2);
+    EXPECT_EQ(2, rc1.getAggressivity());
+    EXPECT_EQ(3, rc1.getRate());
+    EXPECT_FALSE(rc1.getDue().is_not_a_date_time());
+    EXPECT_FALSE(rc1.last_sent_.is_not_a_date_time());
+    EXPECT_FALSE(rc1.isLateSent());
+
+    // Call the constructor again and make sure that different values
+    // will be set correctly.
+    NakedRateControl rc2(5, 6);
+    EXPECT_EQ(6, rc2.getAggressivity());
+    EXPECT_EQ(5, rc2.getRate());
+    EXPECT_FALSE(rc2.getDue().is_not_a_date_time());
+    EXPECT_FALSE(rc2.last_sent_.is_not_a_date_time());
+    EXPECT_FALSE(rc2.isLateSent());
+
+    // The 0 value of aggressivity < 1 is not acceptable.
+    EXPECT_THROW(RateControl(3, 0), isc::BadValue);
+}
+
+// Check the aggressivity accessor.
+TEST(RateControl, getAggressivity) {
+    RateControl rc;
+    ASSERT_EQ(1, rc.getAggressivity());
+    rc.setAggressivity(5);
+    ASSERT_EQ(5, rc.getAggressivity());
+    rc.setAggressivity(10);
+    EXPECT_EQ(10, rc.getAggressivity());
+}
+
+// Check the due time accessor.
+TEST(RateControl, getDue) {
+    NakedRateControl rc;
+    ASSERT_FALSE(rc.getDue().is_not_a_date_time());
+    rc.send_due_ = NakedRateControl::currentTime();
+    EXPECT_TRUE(NakedRateControl::currentTime() >= rc.getDue());
+    rc.send_due_ = NakedRateControl::currentTime() + boost::posix_time::seconds(10);
+    EXPECT_TRUE(NakedRateControl::currentTime() < rc.getDue());
+}
+
+// Check the rate accessor.
+TEST(RateControl, getRate) {
+    RateControl rc;
+    ASSERT_EQ(0, rc.getRate());
+    rc.setRate(5);
+    ASSERT_EQ(5, rc.getRate());
+    rc.setRate(10);
+    EXPECT_EQ(10, rc.getRate());
+}
+
+// Check if late send flag accessor.
+TEST(RateControl, isLateSent) {
+    NakedRateControl rc;
+    ASSERT_FALSE(rc.isLateSent());
+    rc.late_sent_ = true;
+    EXPECT_TRUE(rc.isLateSent());
+}
+
+// Check that the function returns the number of messages to be sent "now"
+// correctly.
+// @todo Possibly extend this test to cover more complex scenarios. Note that
+// it is quite hard to fully test this function as its behaviour strongly
+// depends on time.
+TEST(RateControl, getOutboundMessageCount) {
+    NakedRateControl rc1;
+    // Set the timestamp of the last sent message well to the past.
+    // The resulting due time will be in the past too.
+    rc1.last_sent_ =
+        NakedRateControl::currentTime() - boost::posix_time::seconds(5);
+    // The number of messages to be sent must be greater than 0.
+    uint64_t count;
+    ASSERT_NO_THROW(count = rc1.getOutboundMessageCount());
+    EXPECT_GT(count, 0);
+    // Now, don't specify the rate. In this case the aggressivity dictates
+    // how many messages to send.
+    NakedRateControl rc2(0, 3);
+    rc2.last_sent_ =
+        NakedRateControl::currentTime() - boost::posix_time::seconds(5);
+    ASSERT_NO_THROW(count = rc2.getOutboundMessageCount());
+    EXPECT_EQ(3, count);
+    // Specify the rate and set the timestamp of the last sent message well
+    // to the future. If the resulting due time is well in the future too,
+    // the number of messages to be sent must be 0.
+    NakedRateControl rc3(10, 3);
+    rc3.last_sent_ = NakedRateControl::currentTime() + boost::posix_time::seconds(5);
+    ASSERT_NO_THROW(count = rc3.getOutboundMessageCount());
+    EXPECT_EQ(0, count);
+
+}
+
+// Test the function which calculates the due time to send next set of
+// messages.
+TEST(RateControl, updateSendDue) {
+    NakedRateControl rc;
+    // Set the send due timestamp to the value which is well in the future.
+    // If we don't hit the due time, the function should not modify the
+    // due time.
+    rc.send_due_ =
+        NakedRateControl::currentTime() + boost::posix_time::seconds(10);
+    boost::posix_time::ptime last_send_due = rc.send_due_;
+    ASSERT_NO_THROW(rc.updateSendDue());
+    EXPECT_TRUE(rc.send_due_ == last_send_due);
+    // Set the due time to the value which is already behind.
+    rc.send_due_ =
+        NakedRateControl::currentTime() - boost::posix_time::seconds(10);
+    last_send_due = rc.send_due_;
+    ASSERT_NO_THROW(rc.updateSendDue());
+    // The value should be modified to the new value.
+    EXPECT_TRUE(rc.send_due_ != last_send_due);
+
+}
+
+// Test that the message send time is updated to the current time.
+TEST(RateControl, updateSendTime) {
+    NakedRateControl rc;
+    // Set the timestamp to the future.
+    rc.last_sent_ =
+        NakedRateControl::currentTime() + boost::posix_time::seconds(5);
+    rc.updateSendTime();
+    // Updated timestamp should be set to now or to the past.
+    EXPECT_TRUE(rc.last_sent_ <= NakedRateControl::currentTime());
+
+}

+ 13 - 47
tests/tools/perfdhcp/tests/test_control_unittest.cc

@@ -92,12 +92,9 @@ public:
     void setRelativeDueTimes(const int send_secs, const int renew_secs = 0,
                              const int release_secs = 0) {
         ptime now = microsec_clock::universal_time();
-        send_due_ = send_secs > 0 ?
-            now + seconds(abs(send_secs)) : now - seconds(abs(send_secs));
-        renew_due_ = renew_secs > 0 ?
-            now + seconds(abs(renew_secs)) : now - seconds(abs(renew_secs));
-        release_due_ = release_secs > 0 ?
-            now + seconds(abs(release_secs)) : now - seconds(abs(release_secs));
+        basic_rate_control_.setRelativeDue(send_secs);
+        renew_rate_control_.setRelativeDue(renew_secs);
+        release_rate_control_.setRelativeDue(release_secs);
 
     }
 
@@ -112,7 +109,6 @@ public:
     using TestControl::generateDuid;
     using TestControl::generateMacAddress;
     using TestControl::getCurrentTimeout;
-    using TestControl::getNextExchangesNum;
     using TestControl::getTemplateBuffer;
     using TestControl::initPacketTemplates;
     using TestControl::initializeStatsMgr;
@@ -128,13 +124,10 @@ public:
     using TestControl::sendSolicit6;
     using TestControl::setDefaults4;
     using TestControl::setDefaults6;
-    using TestControl::send_due_;
-    using TestControl::last_sent_;
+    using TestControl::basic_rate_control_;
+    using TestControl::renew_rate_control_;
+    using TestControl::release_rate_control_;
     using TestControl::last_report_;
-    using TestControl::renew_due_;
-    using TestControl::release_due_;
-    using TestControl::last_renew_;
-    using TestControl::last_release_;
     using TestControl::transid_gen_;
     using TestControl::macaddr_gen_;
     using TestControl::first_packet_serverid_;
@@ -913,16 +906,16 @@ public:
 
 // 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 -a 3 all"));
     NakedTestControl tc;
     tc.reset();
-    EXPECT_FALSE(tc.send_due_.is_not_a_date_time());
-    EXPECT_FALSE(tc.last_sent_.is_not_a_date_time());
+    EXPECT_EQ(3, tc.basic_rate_control_.getAggressivity());
+    EXPECT_EQ(3, tc.renew_rate_control_.getAggressivity());
+    EXPECT_EQ(3, tc.release_rate_control_.getAggressivity());
+    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.renew_due_.is_not_a_date_time());
-    EXPECT_FALSE(tc.release_due_.is_not_a_date_time());
-    EXPECT_FALSE(tc.last_renew_.is_not_a_date_time());
-    EXPECT_FALSE(tc.last_release_.is_not_a_date_time());
-    EXPECT_FALSE(tc.send_due_.is_not_a_date_time());
     EXPECT_FALSE(tc.transid_gen_);
     EXPECT_FALSE(tc.macaddr_gen_);
     EXPECT_TRUE(tc.first_packet_serverid_.empty());
@@ -1446,33 +1439,6 @@ TEST_F(TestControlTest, PacketTemplates) {
     EXPECT_THROW(tc.initPacketTemplates(), isc::BadValue);
 }
 
-TEST_F(TestControlTest, RateControl) {
-    // We don't specify the exchange rate here so the aggressivity
-    // value will determine how many packets are to be send each
-    // time we query the getNextExchangesNum.
-    ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all"));
-    CommandOptions& options = CommandOptions::instance();
-
-    NakedTestControl tc1;
-    uint64_t xchgs_num = tc1.getNextExchangesNum(microsec_clock::universal_time(),
-                                                 options.getRate());
-    EXPECT_EQ(options.getAggressivity(), xchgs_num);
-
-    // The exchange rate is now 1 per second. We don't know how many
-    // exchanges have to initiated exactly but for sure it has to be
-    // non-zero value. Also, since aggressivity is very high we expect
-    // that it will not be restricted by aggressivity.
-    ASSERT_NO_THROW(
-        processCmdLine("perfdhcp -l 127.0.0.1 -a 1000000 -r 1 all")
-    );
-    NakedTestControl tc2;
-    xchgs_num = tc2.getNextExchangesNum(microsec_clock::universal_time(),
-                                        options.getRate());
-    EXPECT_GT(xchgs_num, 0);
-    EXPECT_LT(xchgs_num, options.getAggressivity());
-    // @todo add more thorough checks for rate values.
-}
-
 TEST_F(TestControlTest, processRenew) {
     testSendRenewRelease(DHCPV6_RENEW);
 }