Skip to content

Commit 8c80464

Browse files
committed
[#3513] address review
- fix documentation - show null on system-time and clock-skew when uninitialized - add UT CommunicationStateTest.getReportWithClockSkewTest
1 parent 756a737 commit 8c80464

File tree

9 files changed

+111
-57
lines changed

9 files changed

+111
-57
lines changed

doc/sphinx/arm/hooks-ha.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,10 +2170,14 @@ server may start monitoring the DHCP traffic directed to the partner to see if
21702170
the partner is responding to this traffic. More about the failover procedure can
21712171
be found in :ref:`ha-load-balancing-config`.
21722172

2173-
The ``system-time`` parameters hold the UTC time in ``%Y-%m-%d %H:%M:%S`` format
2173+
The ``system-time`` parameter holds the UTC time when skew between local and
2174+
partner node was last calculated. It is displayed in ``%Y-%m-%d %H:%M:%S`` format
21742175
for each active node: local, and remote, respectively. The ``clock-skew``
21752176
parameter is available in the ``remote`` map and holds the difference in seconds
2176-
between the two times.
2177+
between the two times. Local time is subtracted from the partner's time.
2178+
A positive value means that the partner is ahead, while a negative value means
2179+
that the partner is behind. Both ``system-time`` and ``clock-skew`` parameters
2180+
can be null if the clock skew was not calculated yet.
21772181

21782182
The ``connecting-clients``, ``unacked-clients``, ``unacked-clients-left``, and
21792183
``analyzed-packets`` parameters were introduced along with the

src/hooks/dhcp/high_availability/communication_state.cc

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,13 @@ CommunicationState::getReport() const {
587587
}
588588
report->set("unacked-clients-left", Element::create(unacked_clients_left));
589589
report->set("analyzed-packets", Element::create(static_cast<long long>(getAnalyzedMessagesCount())));
590-
report->set("system-time", Element::create(ptimeToText(getPartnerTimeAtSkew(), 0)));
591-
report->set("clock-skew", Element::create(clock_skew_.total_seconds()));
590+
if (partner_time_at_skew_.is_not_a_date_time()) {
591+
report->set("system-time", Element::create());
592+
report->set("clock-skew", Element::create());
593+
} else {
594+
report->set("system-time", Element::create(ptimeToText(partner_time_at_skew_, 0)));
595+
report->set("clock-skew", Element::create(clock_skew_.total_seconds()));
596+
}
592597

593598
return (report);
594599
}
@@ -658,19 +663,11 @@ CommunicationState::setPartnerUnsentUpdateCountInternal(uint64_t unsent_update_c
658663

659664
boost::posix_time::ptime
660665
CommunicationState::getMyTimeAtSkew() const {
661-
if (my_time_at_skew_.is_not_a_date_time()) {
662-
// Return current time.
663-
return boost::posix_time::microsec_clock::universal_time();
664-
}
665666
return my_time_at_skew_;
666667
}
667668

668669
boost::posix_time::ptime
669670
CommunicationState::getPartnerTimeAtSkew() const {
670-
if (partner_time_at_skew_.is_not_a_date_time()) {
671-
// Return current time.
672-
return boost::posix_time::microsec_clock::universal_time();
673-
}
674671
return partner_time_at_skew_;
675672
}
676673

src/hooks/dhcp/high_availability/communication_state.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include <boost/shared_ptr.hpp>
2626

2727
#include <functional>
28-
#include <map>
2928
#include <mutex>
3029
#include <set>
3130
#include <string>
@@ -701,17 +700,11 @@ class CommunicationState {
701700
public:
702701
/// @brief Retrieves the time of the local node when skew was last calculated.
703702
///
704-
/// Used in reporting to the user, which is why being lenient with corner cases is important.
705-
/// That is why if the time was not initialized yet, it is approximated to the current time.
706-
///
707703
/// @return my time at skew
708704
boost::posix_time::ptime getMyTimeAtSkew() const;
709705

710706
/// @brief Retrieves the time of the partner node when skew was last calculated.
711707
///
712-
/// Used in reporting to the user, which is why being lenient with corner cases is important.
713-
/// That is why if the time was not initialized yet, it is approximated to the current time.
714-
///
715708
/// @return partner's time at skew
716709
boost::posix_time::ptime getPartnerTimeAtSkew() const;
717710

src/hooks/dhcp/high_availability/ha_service.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,12 @@ HAService::processStatusGet() const {
16941694
}
16951695
local->set("scopes", list);
16961696
local->set("server-name", Element::create(config_->getThisServerName()));
1697-
local->set("system-time", Element::create(ptimeToText(communication_state_->getMyTimeAtSkew(), 0)));
1697+
auto const my_time(communication_state_->getMyTimeAtSkew());
1698+
if (my_time.is_not_a_date_time()) {
1699+
local->set("system-time", Element::create());
1700+
} else {
1701+
local->set("system-time", Element::create(ptimeToText(my_time, 0)));
1702+
}
16981703
ha_servers->set("local", local);
16991704

17001705
// Do not include remote server information if this is a backup server or

src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ using namespace isc::util;
3838
using namespace boost::posix_time;
3939
using namespace boost::gregorian;
4040

41+
using namespace std;
42+
4143

4244
namespace {
4345

@@ -129,6 +131,9 @@ class CommunicationStateTest : public HATest {
129131
/// @brief Tests unusual values used to create the report.
130132
void getReportDefaultValuesTest();
131133

134+
/// @brief Tests the report when clock is skewed.
135+
void getReportWithClockSkewTest();
136+
132137
/// @brief Tests that unsent updates count can be incremented and fetched.
133138
void getUnsentUpdateCountTest();
134139

@@ -769,7 +774,7 @@ CommunicationStateTest::getReportTest() {
769774

770775
// Check that system-time exists and that format is parsable by ptime.
771776
// Do not check exact value because it can be time-sensitive.
772-
checkThatTimeIsParsable(report);
777+
checkThatTimeIsParsable(report, /* null_expected = */ true);
773778

774779
// Compare with the expected output.
775780
std::string expected = "{"
@@ -782,7 +787,7 @@ CommunicationStateTest::getReportTest() {
782787
" \"unacked-clients\": 1,"
783788
" \"unacked-clients-left\": 10,"
784789
" \"analyzed-packets\": 2,"
785-
" \"clock-skew\": 0"
790+
" \"clock-skew\": null"
786791
"}";
787792
expectEqWithDiff(Element::fromJSON(expected), report);
788793
}
@@ -796,7 +801,7 @@ CommunicationStateTest::getReportDefaultValuesTest() {
796801

797802
// Check that system-time exists and that format is parsable by ptime.
798803
// Do not check exact value because it can be time-sensitive.
799-
checkThatTimeIsParsable(report);
804+
checkThatTimeIsParsable(report, /* null_expected = */ true);
800805

801806
// Compare with the expected output.
802807
std::string expected = "{"
@@ -809,11 +814,47 @@ CommunicationStateTest::getReportDefaultValuesTest() {
809814
" \"unacked-clients\": 0,"
810815
" \"unacked-clients-left\": 0,"
811816
" \"analyzed-packets\": 0,"
812-
" \"clock-skew\": 0"
817+
" \"clock-skew\": null"
813818
"}";
814819
expectEqWithDiff(Element::fromJSON(expected), report);
815820
}
816821

822+
// Tests that the communication state report is correct when clock is skewed.
823+
void
824+
CommunicationStateTest::getReportWithClockSkewTest() {
825+
auto const now(microsec_clock::universal_time());
826+
// RFC 1123 format
827+
// Is freed automatically by std::locale. See [localization.locales.locale#6] and
828+
// [localization.locales.locale.facet#2] in the C++ standard.
829+
time_facet* facet(new time_facet("%a, %d %b %Y %H:%M:%S GMT"));
830+
stringstream ss;
831+
ss.imbue(std::locale(std::locale(), facet));
832+
ss << now + seconds(2);
833+
state_.setPartnerTime(ss.str());
834+
ElementPtr report;
835+
ASSERT_NO_THROW_LOG(report = state_.getReport());
836+
ASSERT_TRUE(report);
837+
838+
// Check that system-time exists and that format is parsable by ptime.
839+
// Do not check exact value because it can be time-sensitive.
840+
checkThatTimeIsParsable(report, /* null_expected = */ false);
841+
842+
// Compare with the expected output.
843+
std::string expected = R"({
844+
"age": 0,
845+
"in-touch": false,
846+
"last-scopes": [ ],
847+
"last-state": "",
848+
"communication-interrupted": false,
849+
"connecting-clients": 0,
850+
"unacked-clients": 0,
851+
"unacked-clients-left": 0,
852+
"analyzed-packets": 0,
853+
"clock-skew": 2
854+
})";
855+
expectEqWithDiff(Element::fromJSON(expected), report);
856+
}
857+
817858
void
818859
CommunicationStateTest::getUnsentUpdateCountTest() {
819860
// Initially the count should be 0.
@@ -1221,6 +1262,15 @@ TEST_F(CommunicationStateTest, getReportDefaultValuesTestMultiThreading) {
12211262
getReportDefaultValuesTest();
12221263
}
12231264

1265+
TEST_F(CommunicationStateTest, getReportWithClockSkewTest) {
1266+
getReportWithClockSkewTest();
1267+
}
1268+
1269+
TEST_F(CommunicationStateTest, getReportWithClockSkewTestMultiThreading) {
1270+
MultiThreadingMgr::instance().setMode(true);
1271+
getReportWithClockSkewTest();
1272+
}
1273+
12241274
TEST_F(CommunicationStateTest, getUnsentUpdateCountTest) {
12251275
getUnsentUpdateCountTest();
12261276
}

src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,8 +1809,8 @@ TEST_F(HAImplTest, statusGet) {
18091809
EXPECT_TRUE(ha_servers);
18101810
ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
18111811
ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
1812-
checkThatTimeIsParsable(local);
1813-
checkThatTimeIsParsable(remote);
1812+
checkThatTimeIsParsable(local, /* null_expected = */ true);
1813+
checkThatTimeIsParsable(remote, /* null_expected = */ true);
18141814

18151815
std::string expected =
18161816
"{"
@@ -1837,7 +1837,7 @@ TEST_F(HAImplTest, statusGet) {
18371837
" \"unacked-clients\": 0,"
18381838
" \"unacked-clients-left\": 0,"
18391839
" \"analyzed-packets\": 0,"
1840-
" \"clock-skew\": 0"
1840+
" \"clock-skew\": null"
18411841
" }"
18421842
" }"
18431843
" }"
@@ -1882,7 +1882,7 @@ TEST_F(HAImplTest, statusGetBackupServer) {
18821882
got->get("arguments")->get("high-availability")->get(0)->get("ha-servers"));
18831883
EXPECT_TRUE(ha_servers);
18841884
ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
1885-
checkThatTimeIsParsable(local);
1885+
checkThatTimeIsParsable(local, /* null_expected = */ true);
18861886

18871887
std::string expected =
18881888
"{"
@@ -1940,7 +1940,7 @@ TEST_F(HAImplTest, statusGetPassiveBackup) {
19401940
got->get("arguments")->get("high-availability")->get(0)->get("ha-servers"));
19411941
EXPECT_TRUE(ha_servers);
19421942
ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
1943-
checkThatTimeIsParsable(local);
1943+
checkThatTimeIsParsable(local, /* null_expected = */ true);
19441944

19451945
std::string expected =
19461946
"{"
@@ -2000,8 +2000,8 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
20002000
EXPECT_TRUE(ha_servers);
20012001
ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
20022002
ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
2003-
checkThatTimeIsParsable(local);
2004-
checkThatTimeIsParsable(remote);
2003+
checkThatTimeIsParsable(local, /* null_expected = */ true);
2004+
checkThatTimeIsParsable(remote, /* null_expected = */ true);
20052005
}
20062006

20072007
std::string expected =
@@ -2020,7 +2020,7 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
20202020
" \"remote\": {"
20212021
" \"age\": 0,"
20222022
" \"analyzed-packets\": 0,"
2023-
" \"clock-skew\": 0,"
2023+
" \"clock-skew\": null,"
20242024
" \"communication-interrupted\": false,"
20252025
" \"connecting-clients\": 0,"
20262026
" \"in-touch\": false,"
@@ -2045,7 +2045,7 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
20452045
" \"remote\": {"
20462046
" \"age\": 0,"
20472047
" \"analyzed-packets\": 0,"
2048-
" \"clock-skew\": 0,"
2048+
" \"clock-skew\": null,"
20492049
" \"communication-interrupted\": false,"
20502050
" \"connecting-clients\": 0,"
20512051
" \"in-touch\": false,"

src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2639,8 +2639,8 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisPrimary) {
26392639
// Do not check exact value because it can be time-sensitive.
26402640
ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
26412641
ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
2642-
checkThatTimeIsParsable(local);
2643-
checkThatTimeIsParsable(remote);
2642+
checkThatTimeIsParsable(local, /* null_expected = */ true);
2643+
checkThatTimeIsParsable(remote, /* null_expected = */ true);
26442644

26452645
std::string expected = "{"
26462646
" \"local\": {"
@@ -2661,7 +2661,7 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisPrimary) {
26612661
" \"unacked-clients\": 0,"
26622662
" \"unacked-clients-left\": 0,"
26632663
" \"analyzed-packets\": 0,"
2664-
" \"clock-skew\": 0"
2664+
" \"clock-skew\": null"
26652665
" }"
26662666
"}";
26672667
expectEqWithDiff(Element::fromJSON(expected), ha_servers);
@@ -2698,8 +2698,8 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisStandby) {
26982698
// Do not check exact value because it can be time-sensitive.
26992699
ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
27002700
ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
2701-
checkThatTimeIsParsable(local);
2702-
checkThatTimeIsParsable(remote);
2701+
checkThatTimeIsParsable(local, /* null_expected = */ true);
2702+
checkThatTimeIsParsable(remote, /* null_expected = */ true);
27032703

27042704
std::string expected = "{"
27052705
" \"local\": {"
@@ -2720,7 +2720,7 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisStandby) {
27202720
" \"unacked-clients\": 0,"
27212721
" \"unacked-clients-left\": 0,"
27222722
" \"analyzed-packets\": 0,"
2723-
" \"clock-skew\": 0"
2723+
" \"clock-skew\": null"
27242724
" }"
27252725
"}";
27262726
expectEqWithDiff(Element::fromJSON(expected), ha_servers);
@@ -6500,7 +6500,7 @@ class HAServiceStateMachineTest : public HAServiceTest {
65006500
// is available and it is doing load balancing.
65016501
// 10. I stay in the partner-down state to force the partner to transition
65026502
// to the waiting state and synchronize its database.
6503-
TEST_F(HAServiceStateMachineTest, waitingParterDownLoadBalancingPartnerDown) {
6503+
TEST_F(HAServiceStateMachineTest, waitingPartnerDownLoadBalancingPartnerDown) {
65046504
HAConfigPtr config_storage = createValidConfiguration();
65056505
// Disable syncing leases to avoid transitions via the syncing state.
65066506
// In this state it is necessary to perform synchronous tasks.
@@ -6586,8 +6586,8 @@ TEST_F(HAServiceStateMachineTest, waitingParterDownLoadBalancingPartnerDown) {
65866586
// Do not check exact value because it can be time-sensitive.
65876587
ElementPtr mutable_local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
65886588
ElementPtr mutable_remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
6589-
checkThatTimeIsParsable(mutable_local);
6590-
checkThatTimeIsParsable(mutable_remote);
6589+
checkThatTimeIsParsable(mutable_local, /* null_expected = */ false);
6590+
checkThatTimeIsParsable(mutable_remote, /* null_expected = */ false);
65916591

65926592
std::string expected = "{"
65936593
" \"local\": {"
@@ -6685,7 +6685,7 @@ TEST_F(HAServiceStateMachineTest, waitingParterDownLoadBalancingPartnerDown) {
66856685
// 10. The partner unexpectedly shows up in the hot-standby mode. I stay in
66866686
// the partner-down state to force the partner to transition to the waiting
66876687
// state and synchronize its database.
6688-
TEST_F(HAServiceStateMachineTest, waitingParterDownHotStandbyPartnerDown) {
6688+
TEST_F(HAServiceStateMachineTest, waitingPartnerDownHotStandbyPartnerDown) {
66896689
HAConfigPtr valid_config = createValidConfiguration(HAConfig::HOT_STANDBY);
66906690

66916691
// Turn it into hot-standby configuration.

src/hooks/dhcp/high_availability/tests/ha_test.cc

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ HATest::signalServiceRunning(bool& running, std::mutex& mutex,
149149

150150

151151
void
152-
HATest::checkThatTimeIsParsable(ElementPtr node) {
152+
HATest::checkThatTimeIsParsable(ElementPtr const& node, bool const null_expected) {
153153
ConstElementPtr system_time(node->get("system-time"));
154154
EXPECT_TRUE(system_time);
155155

@@ -160,16 +160,20 @@ HATest::checkThatTimeIsParsable(ElementPtr node) {
160160

161161
stringstream ss;
162162
ss.imbue(std::locale(std::locale(), facet));
163-
EXPECT_EQ(system_time->getType(), Element::string);
164-
ss << system_time->stringValue();
165-
boost::posix_time::ptime t;
166-
ss >> t;
167-
168-
// Reset stringstream.
169-
ss = stringstream();
170-
171-
ss << t;
172-
EXPECT_NE(ss.str(), "not-a-date-time");
163+
if (null_expected) {
164+
EXPECT_EQ(system_time->getType(), Element::null);
165+
} else {
166+
EXPECT_EQ(system_time->getType(), Element::string);
167+
ss << system_time->stringValue();
168+
boost::posix_time::ptime t;
169+
ss >> t;
170+
171+
// Reset stringstream.
172+
ss = stringstream();
173+
174+
ss << t;
175+
EXPECT_NE(ss.str(), "not-a-date-time");
176+
}
173177

174178
node->remove("system-time");
175179
}

src/hooks/dhcp/high_availability/tests/ha_test.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,15 @@ class HATest : public ::testing::Test {
130130
std::condition_variable& condvar);
131131

132132
/// @brief Check that a map element pointer representing the reported status
133-
/// of an HA node contains string element pointer indexed by the
133+
/// of an HA node contains a string element pointer indexed by the
134134
/// "system-time" key that can be parsed in a ptime object.
135135
///
136136
/// Also removes the "system-time" element for the purpose of holistically
137137
/// comparing the node without worrying about time-sensitive information.
138138
///
139-
/// @brief param the node element pointer
140-
void checkThatTimeIsParsable(isc::data::ElementPtr node);
139+
/// @param node the node element pointer
140+
/// @param null_expected whether null is expected as the system-time value
141+
void checkThatTimeIsParsable(isc::data::ElementPtr const& node, bool const null_expected);
141142

142143
public:
143144

0 commit comments

Comments
 (0)