Commit af2ab70a authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[3181] Send Release messages if -F<release-rate> is specified.

parent ae4c0644
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-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
......@@ -124,7 +124,8 @@ public:
XCHG_RA, ///< DHCPv4 REQUEST-ACK
XCHG_SA, ///< DHCPv6 SOLICIT-ADVERTISE
XCHG_RR, ///< DHCPv6 REQUEST-REPLY
XCHG_RN ///< DHCPv6 RENEW-REPLY
XCHG_RN, ///< DHCPv6 RENEW-REPLY
XCHG_RL ///< DHCPv6 RELEASE-REPLY
};
/// \brief Exchange Statistics.
......@@ -871,6 +872,20 @@ public:
boot_time_));
}
/// \brief Check if the exchange type has been specified.
///
/// This method checks if the \ref ExchangeStats object of a particular type
/// exists (has been added using \ref addExchangeStats function).
///
/// \param xchg_type A type of the exchange being repersented by the
/// \ref ExchangeStats object.
///
/// \return true if the \ref ExchangeStats object has been added for a
/// specified exchange type.
bool hasExchangeStats(const ExchangeType xchg_type) const {
return (exchanges_.find(xchg_type) != exchanges_.end());
}
/// \brief Add named custom uint64 counter.
///
/// Method creates new named counter and stores in counter's map under
......
......@@ -505,19 +505,25 @@ TestControl::getCurrentTimeout() const {
// 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.getRenewRate() != 0 && now >= renew_due_) ||
(options.getReleaseRate() != 0 && now >= release_due_)) {
return (0);
}
// If Renews are being sent, we have to adjust the timeout to the nearest
// Solicit or Renew, depending on what happens sooner.
if (options.getRenewRate() != 0) {
ptime due = send_due_ > renew_due_ ? renew_due_ : send_due_;
return (time_period(now, due).length().total_microseconds());
// Let's assume that the due time for Solicit is the soonest.
ptime due = send_due_;
// 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_;
}
// We are not sending Renews, let's adjust the timeout to the nearest
// Solicit.
return (time_period(now, send_due_).length().total_microseconds());
// 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_;
}
// Return the timeout in microseconds.
return (time_period(now, due).length().total_microseconds());
}
int
......@@ -714,6 +720,9 @@ TestControl::initializeStatsMgr() {
if (options.getRenewRate() != 0) {
stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RN);
}
if (options.getReleaseRate() != 0) {
stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RL);
}
}
if (testDiags('i')) {
if (options.getIpVersion() == 4) {
......@@ -868,14 +877,15 @@ TestControl::sendPackets(const TestControlSocket& socket,
}
uint64_t
TestControl::sendRenewPackets(const TestControlSocket& socket,
const uint64_t packets_num) {
for (uint64_t i = 0; i < packets_num; ++i) {
if (!sendRenew(socket)) {
TestControl::sendMultipleMessages6(const TestControlSocket& socket,
const uint32_t msg_type,
const uint64_t msg_num) {
for (uint64_t i = 0; i < msg_num; ++i) {
if (!sendMessageFromReply(msg_type, socket)) {
return (i);
}
}
return (packets_num);
return (msg_num);
}
void
......@@ -1133,14 +1143,15 @@ TestControl::processReceivedPacket6(const TestControlSocket& socket,
}
}
} else if (packet_type == DHCPV6_REPLY) {
Pkt6Ptr sent_packet = stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR,
pkt6);
if (sent_packet) {
if (CommandOptions::instance().getRenewRate() != 0) {
if (stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6)) {
if (stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RN) ||
stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RL)) {
reply_storage_.append(pkt6);
}
} else {
stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RN, pkt6);
} else if (!(stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RN) &&
stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RN, pkt6)) &&
stats_mgr6_->hasExchangeStats(StatsMgr6::XCHG_RL)) {
stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RL, pkt6);
}
}
}
......@@ -1273,6 +1284,7 @@ TestControl::reset() {
last_sent_ = send_due_;
last_report_ = send_due_;
renew_due_ = send_due_;
release_due_ = send_due_;
last_renew_ = send_due_;
transid_gen_.reset();
// Actual generators will have to be set later on because we need to
......@@ -1373,8 +1385,19 @@ TestControl::run() {
updateSendDue(last_renew_, options.getRenewRate(), renew_due_);
uint64_t renew_packets_due =
getNextExchangesNum(renew_due_, options.getRenewRate());
// Send renew packets.
sendRenewPackets(socket, renew_packets_due);
// Send Renew messages.
sendMultipleMessages6(socket, 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)) {
updateSendDue(last_release_, options.getReleaseRate(),
release_due_);
uint64_t release_packets_due =
getNextExchangesNum(release_due_, options.getReleaseRate());
// Send Release messages.
sendMultipleMessages6(socket, DHCPV6_RELEASE, release_packets_due);
}
// Report delay means that user requested printing number
......@@ -1566,21 +1589,35 @@ TestControl::sendDiscover4(const TestControlSocket& socket,
}
bool
TestControl::sendRenew(const TestControlSocket& socket) {
last_renew_ = microsec_clock::universal_time();
TestControl::sendMessageFromReply(const uint16_t msg_type,
const TestControlSocket& socket) {
// We only permit Release or Renew messages to be sent using this function.
if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
isc_throw(isc::BadValue, "invalid message type " << msg_type
<< " to be sent, expected DHCPV6_RENEW or DHCPV6_RELEASE");
}
// We track the timestamp of last Release and Renew in different variables.
if (msg_type == DHCPV6_RENEW) {
last_renew_ = microsec_clock::universal_time();
} else {
last_release_ = microsec_clock::universal_time();
}
Pkt6Ptr reply = reply_storage_.getRandom();
if (!reply) {
return (false);
}
Pkt6Ptr renew = createMessageFromReply(DHCPV6_RENEW, reply);
setDefaults6(socket, renew);
renew->pack();
IfaceMgr::instance().send(renew);
// Prepare the message of the specified type.
Pkt6Ptr msg = createMessageFromReply(msg_type, reply);
setDefaults6(socket, msg);
msg->pack();
// And send it.
IfaceMgr::instance().send(msg);
if (!stats_mgr6_) {
isc_throw(Unexpected, "Statistics Manager for DHCPv6 "
"hasn't been initialized");
}
stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RN, renew);
stats_mgr6_->passSentPacket((msg_type == DHCPV6_RENEW ? StatsMgr6::XCHG_RN
: StatsMgr6::XCHG_RL), msg);
return (true);
}
......
......@@ -748,25 +748,32 @@ protected:
const uint64_t packets_num,
const bool preload = false);
/// \brief Send number of DHCPv6 Renew packets to the server.
/// \brief Send number of DHCPv6 Renew or Release messages to the server.
///
/// \param socket An object representing socket to be used to send packets.
/// \param packets_num A number of Renew packets to be send.
/// \param msg_type A type of the messages to be sent (DHCPV6_RENEW or
/// DHCPV6_RELEASE).
/// \param msg_num A number of messages to be sent.
///
/// \return A number of packets actually sent.
uint64_t sendRenewPackets(const TestControlSocket& socket,
const uint64_t packets_num);
/// \return A number of messages actually sent.
uint64_t sendMultipleMessages6(const TestControlSocket& socket,
const uint32_t msg_type,
const uint64_t msg_num);
/// \brief Send a renew message using provided socket.
/// \brief Send DHCPv6 Renew or Release message using specified socket.
///
/// This method will select an existing lease from the Reply packet cache
/// If there is no lease that can be renewed this method will return false.
/// If there is no lease that can be renewed or released this method will
/// return false.
///
/// \param msg_type A type of the message to be sent (DHCPV6_RENEW or
/// DHCPV6_RELEASE).
/// \param socket An object encapsulating socket to be used to send
/// a packet.
///
/// \return true if packet has been sent, false otherwise.
bool sendRenew(const TestControlSocket& socket);
/// \return true if the message has been sent, false otherwise.
bool sendMessageFromReply(const uint16_t msg_type,
const TestControlSocket& socket);
/// \brief Send DHCPv4 REQUEST message.
///
......@@ -1074,8 +1081,12 @@ protected:
///< 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.
private:
boost::posix_time::ptime last_report_; ///< Last intermediate report time.
......
......@@ -187,6 +187,8 @@ TEST_F(StatsMgrTest, Exchange) {
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));
EXPECT_THROW(
stats_mgr->passSentPacket(StatsMgr4::XCHG_DO, sent_packet),
BadValue
......@@ -196,8 +198,11 @@ TEST_F(StatsMgrTest, Exchange) {
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));
// The following two attempts are expected to throw because
// invalid exchange types are passed (XCHG_RA instead of XCHG_DO)
EXPECT_THROW(
......
......@@ -74,6 +74,33 @@ public:
uint32_t transid_; ///< Last generated transaction id.
};
/// \brief Sets the due times for sedning Solicit, Renew and Release.
///
/// There are three class members that hold the due time for sending DHCP
/// messages:
/// - send_due_ - due time to send Solicit,
/// - renew_due_ - due time to send Renew,
/// - release_due_ - due time to send Release.
/// Some tests in this test suite need to modify these values relative to
/// the current time. This function modifies this values using time
/// offset values (positive or negative) specified as a difference in
/// seconds between current time and the due time.
///
/// \param send_secs An offset of the due time for Solicit.
/// \param renew_secs An offset of the due time for Renew.
/// \param release_secs An offset of the due time for Release.
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));
}
using TestControl::checkExitConditions;
using TestControl::createMessageFromReply;
using TestControl::factoryElapsedTime6;
......@@ -95,7 +122,7 @@ public:
using TestControl::registerOptionFactories;
using TestControl::sendDiscover4;
using TestControl::sendPackets;
using TestControl::sendRenewPackets;
using TestControl::sendMultipleMessages6;
using TestControl::sendRequest6;
using TestControl::sendSolicit6;
using TestControl::setDefaults4;
......@@ -103,7 +130,9 @@ public:
using TestControl::send_due_;
using TestControl::last_sent_;
using TestControl::renew_due_;
using TestControl::release_due_;
using TestControl::last_renew_;
using TestControl::last_release_;
NakedTestControl() : TestControl() {
uint32_t clients_num = CommandOptions::instance().getClientsNum() == 0 ?
......@@ -698,6 +727,100 @@ public:
}
/// \brief Test sending DHCPv6 Releases or Renews.
///
/// This function simulates acquiring 10 leases from the server. Returned
/// Reply messages are cached and used to send Renew or Release messages.
/// The maxmimal number of Renew or Release messages which can be sent is
/// equal to the number of leases acquired (10). This function also checks
/// that an attempt to send more Renew or Release messages than the number
/// of leases acquired will fail.
///
/// \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.
std::ostringstream s;
s << "perfdhcp -6 -l " << loopback_iface << " -r 10 ";
s << (msg_type == DHCPV6_RENEW ? "-f" : "-F");
s << " 10 -R 10 -L 10547 -n 10 ::1";
ASSERT_NO_THROW(processCmdLine(s.str()));
// Create a test controller class.
NakedTestControl tc;
tc.initializeStatsMgr();
// 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());
TestControl::TestControlSocket 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);
// 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 (int i = generator->getNext() - 10; i < generator->getNext(); ++i) {
Pkt6Ptr advertise(createAdvertisePkt6(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));
}
// Requests have been sent, so now let's simulate responses from the
// server. Generate corresponding Reply messages with the transaction
// ids from the range from 11 to 20.
for (int i = generator->getNext() - 10; i < generator->getNext(); ++i) {
Pkt6Ptr reply(createReplyPkt6(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));
}
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)
);
// 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)
);
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)
);
// Make sure that no message has been sent.
EXPECT_EQ(0, msg_num);
}
/// \brief Parse command line string with CommandOptions.
///
/// \param cmdline command line string to be parsed.
......@@ -1326,76 +1449,11 @@ TEST_F(TestControlTest, RateControl) {
}
TEST_F(TestControlTest, processRenew) {
std::string loopback_iface(getLocalLoopback());
if (loopback_iface.empty()) {
std::cout << "Skipping the test because loopback interface could"
" not be detected" << std::endl;
return;
}
// This command line specifies that the Renew messages should be sent
// with the same rate as the Solicit messages.
ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface +
" -r 10 -f 10 -R 10 -L 10547 -n 10 ::1"));
// Create a test controller class.
NakedTestControl tc;
tc.initializeStatsMgr();
// 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());
TestControl::TestControlSocket 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);
// 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 (int i = generator->getNext() - 10; i < generator->getNext(); ++i) {
Pkt6Ptr advertise(createAdvertisePkt6(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));
}
// Requests have been sent, so now let's simulate responses from the server.
// Generate corresponding Reply messages with the transaction ids from the
// range from 11 to 20.
for (int i = generator->getNext() - 10; i < generator->getNext(); ++i) {
Pkt6Ptr reply(createReplyPkt6(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));
}
testSendRenewRelease(DHCPV6_RENEW);
}
uint64_t renew_num;
// Try to send 5 Renew packets. It should be successful because
// 10 Reply messages has been received. For each of them we should
// be able to send Renew.
ASSERT_NO_THROW(renew_num = tc.sendRenewPackets(sock, 5));
// Make sure that we have sent 5 packets.
EXPECT_EQ(5, renew_num);
// Try to do it again. We should still have 5 Reply packets for
// which Renews haven't been sent yet.
ASSERT_NO_THROW(renew_num = tc.sendRenewPackets(sock, 5));
EXPECT_EQ(5, renew_num);
// We used all the Reply packets (we sent Renew for each of them
// already). Therefore, no further Renew packets should be sent before
// We acquire new leases.
ASSERT_NO_THROW(renew_num = tc.sendRenewPackets(sock, 5));
// Make sure that no Renew has been sent.
EXPECT_EQ(0, renew_num);
TEST_F(TestControlTest, processRelease) {
testSendRenewRelease(DHCPV6_RELEASE);
}
// This test verifies that the DHCPV6 Renew message is created correctly
......@@ -1423,8 +1481,7 @@ TEST_F(TestControlTest, getCurrentTimeout) {
ASSERT_EQ(0, CommandOptions::instance().getRenewRate());
// Simulate the case when we are already behind the due time for
// the next Discover to be sent.
tc.send_due_ = microsec_clock::universal_time() -
boost::posix_time::seconds(3);
tc.setRelativeDueTimes(-3);
// Expected timeout value is 0, which means that perfdhcp should
// not wait for server's response but rather send the next
// message to a server immediately.
......@@ -1434,8 +1491,7 @@ TEST_F(TestControlTest, getCurrentTimeout) {
// future. The value of ten seconds ahead should be safe and guarantee
// that the returned timeout value is non-zero, even though there is a
// delay between setting the send_due_ value and invoking the function.
tc.send_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(10);
tc.setRelativeDueTimes(10);
uint32_t timeout = tc.getCurrentTimeout();
EXPECT_GT(timeout, 0);
EXPECT_LE(timeout, 10000000);
......@@ -1454,39 +1510,103 @@ TEST_F(TestControlTest, getCurrentTimeoutRenew) {
// Make sure, that the Renew rate has been set to 5.
ASSERT_EQ(5, CommandOptions::instance().getRenewRate());
// The send_due_ is in the past.
tc.send_due_ = microsec_clock::universal_time() -
boost::posix_time::seconds(3);
// The renew_due_ is in the future.
tc.renew_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(3);
// The timeout should be adjusted to the send_due_ as it indicates that
// Solicit should be sent immediately.
// The send_due_ is in the past, the renew_due_ is in the future.
tc.setRelativeDueTimes(-3, 3);
EXPECT_EQ(0, tc.getCurrentTimeout());
// Swap the due times from the previous check. The effect should be the
// same.
tc.send_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(3);
tc.renew_due_ = microsec_clock::universal_time() -
boost::posix_time::seconds(3);
tc.setRelativeDueTimes(3, -3);
EXPECT_EQ(0, tc.getCurrentTimeout());
// Set both due times to the future. The renew due time is to occur
// sooner. The timeout should be a value between now and the
// renew due time.
tc.send_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(10);
tc.renew_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(5);
tc.setRelativeDueTimes(10, 5);
EXPECT_GT(tc.getCurrentTimeout(), 0);
EXPECT_LE(tc.getCurrentTimeout(), 5000000);
// Repeat the same check, but swap the due times.
tc.setRelativeDueTimes(5, 10);
EXPECT_GT(tc.getCurrentTimeout(), 0);
EXPECT_LE(tc.getCurrentTimeout(), 5000000);
}
// This test verifies that the current timeout value for waiting for the
// server's responses is valid. In this case, we are simulating that perfdhcp
// sends Release requests to the server, apart from the regular 4-way exchanges.
TEST_F(TestControlTest, getCurrentTimeoutRelease) {
// Set the Solicit rate to 10 and the Release rate 5.
ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l lo -r 10 -F 5 ::1"));
NakedTestControl tc;
// Make sure, that the Release rate has been set to 5.
ASSERT_EQ(5, CommandOptions::instance().getReleaseRate());
// The send_due_ is in the past, the renew_due_ is in the future.
tc.setRelativeDueTimes(-3, 0, 3);
EXPECT_EQ(0, tc.getCurrentTimeout());
// Swap the due times from the previous check. The effect should be the
// same.
tc.setRelativeDueTimes(3, 0, -3);
EXPECT_EQ(0, tc.getCurrentTimeout());
// Set both due times to the future. The renew due time is to occur
// sooner. The timeout should be a value between now and the
// release due time.
tc.setRelativeDueTimes(10, 0, 5);
EXPECT_GT(tc.getCurrentTimeout(), 0);
EXPECT_LE(tc.getCurrentTimeout(), 5000000);
// Repeat the same check, but swap the due times.
tc.send_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(5);
tc.renew_due_ = microsec_clock::universal_time() +
boost::posix_time::seconds(10);
tc.setRelativeDueTimes(5, 0, 10);
EXPECT_GT(tc.getCurrentTimeout(), 0);
EXPECT_LE(tc.getCurrentTimeout(), 5000000);
}