]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3513] adapt unit tests to HA clock skew in status-get
authorAndrei Pavel <andrei@isc.org>
Wed, 21 Aug 2024 11:09:52 +0000 (14:09 +0300)
committerAndrei Pavel <andrei@isc.org>
Thu, 22 Aug 2024 14:22:45 +0000 (17:22 +0300)
src/hooks/dhcp/high_availability/tests/Makefile.am
src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc
src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc
src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc
src/hooks/dhcp/high_availability/tests/ha_test.cc
src/hooks/dhcp/high_availability/tests/ha_test.h

index 22d9da38024569c8befe09fddee95b9fd111171e..71f72374919ae73074716536f8f45edbb065f704 100644 (file)
@@ -62,6 +62,7 @@ ha_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
 ha_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
 ha_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
 ha_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
 ha_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
 ha_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
 ha_unittests_LDADD += $(LOG4CPLUS_LIBS)
index 149e5a0db921742a4d7db30951b5e8f2d743935d..a559bbb5588e22ff26c6738b0a14e7a8a3b49872 100644 (file)
@@ -15,6 +15,8 @@
 #include <dhcp/dhcp6.h>
 #include <exceptions/exceptions.h>
 #include <http/date_time.h>
+#include <testutils/gtest_utils.h>
+#include <testutils/test_to_element.h>
 #include <util/multi_threading_mgr.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
@@ -30,6 +32,7 @@ using namespace isc::dhcp;
 using namespace isc::ha;
 using namespace isc::ha::test;
 using namespace isc::http;
+using namespace isc::test;
 using namespace isc::util;
 
 using namespace boost::posix_time;
@@ -760,9 +763,14 @@ CommunicationStateTest::getReportTest() {
     ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, 1, 0, 15)));
 
     // Get the report.
-    auto report = state_.getReport();
+    ElementPtr report;
+    ASSERT_NO_THROW_LOG(report = state_.getReport());
     ASSERT_TRUE(report);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    checkThatTimeIsParsable(report);
+
     // Compare with the expected output.
     std::string expected = "{"
         "    \"age\": 100,"
@@ -773,17 +781,23 @@ CommunicationStateTest::getReportTest() {
         "    \"connecting-clients\": 2,"
         "    \"unacked-clients\": 1,"
         "    \"unacked-clients-left\": 10,"
-        "    \"analyzed-packets\": 2"
+        "    \"analyzed-packets\": 2,"
+        "    \"clock-skew\": 0"
         "}";
-    EXPECT_TRUE(isEquivalent(Element::fromJSON(expected), report));
+    expectEqWithDiff(Element::fromJSON(expected), report);
 }
 
 // Tests unusual values used to create the report.
 void
 CommunicationStateTest::getReportDefaultValuesTest() {
-    auto report = state_.getReport();
+    ElementPtr report;
+    ASSERT_NO_THROW_LOG(report = state_.getReport());
     ASSERT_TRUE(report);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    checkThatTimeIsParsable(report);
+
     // Compare with the expected output.
     std::string expected = "{"
         "    \"age\": 0,"
@@ -794,9 +808,10 @@ CommunicationStateTest::getReportDefaultValuesTest() {
         "    \"connecting-clients\": 0,"
         "    \"unacked-clients\": 0,"
         "    \"unacked-clients-left\": 0,"
-        "    \"analyzed-packets\": 0"
+        "    \"analyzed-packets\": 0,"
+        "    \"clock-skew\": 0"
         "}";
-    EXPECT_TRUE(isEquivalent(Element::fromJSON(expected), report));
+    expectEqWithDiff(Element::fromJSON(expected), report);
 }
 
 void
index ee272ba8d98d2a155269814ab9b332c2f78c900b..21eb07b71c71a58d325c149e40714ab472e46359 100644 (file)
 #include <hooks/hooks_manager.h>
 #include <stats/stats_mgr.h>
 #include <testutils/gtest_utils.h>
+#include <testutils/test_to_element.h>
+
 #include <boost/pointer_cast.hpp>
+
 #include <gtest/gtest.h>
+
 #include <string>
 
 using namespace isc::asiolink;
@@ -33,6 +37,7 @@ using namespace isc::ha;
 using namespace isc::ha::test;
 using namespace isc::hooks;
 using namespace isc::stats;
+using namespace isc::test;
 
 namespace {
 
@@ -1797,6 +1802,16 @@ TEST_F(HAImplTest, statusGet) {
     callout_handle->getArgument("response", got);
     ASSERT_TRUE(got);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    ConstElementPtr ha_servers(
+        got->get("arguments")->get("high-availability")->get(0)->get("ha-servers"));
+    EXPECT_TRUE(ha_servers);
+    ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+    ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
+    checkThatTimeIsParsable(local);
+    checkThatTimeIsParsable(remote);
+
     std::string expected =
         "{"
         "    \"arguments\": {"
@@ -1821,7 +1836,8 @@ TEST_F(HAImplTest, statusGet) {
         "                        \"connecting-clients\": 0,"
         "                        \"unacked-clients\": 0,"
         "                        \"unacked-clients-left\": 0,"
-        "                        \"analyzed-packets\": 0"
+        "                        \"analyzed-packets\": 0,"
+        "                        \"clock-skew\": 0"
         "                    }"
         "                }"
         "            }"
@@ -1830,7 +1846,7 @@ TEST_F(HAImplTest, statusGet) {
         "    },"
         "    \"result\": 0"
         "}";
-    EXPECT_TRUE(isEquivalent(got, Element::fromJSON(expected)));
+    expectEqWithDiff(Element::fromJSON(expected), got);
 }
 
 // Tests status-get command processed handler for backup server.
@@ -1860,6 +1876,14 @@ TEST_F(HAImplTest, statusGetBackupServer) {
     callout_handle->getArgument("response", got);
     ASSERT_TRUE(got);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    ConstElementPtr ha_servers(
+        got->get("arguments")->get("high-availability")->get(0)->get("ha-servers"));
+    EXPECT_TRUE(ha_servers);
+    ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+    checkThatTimeIsParsable(local);
+
     std::string expected =
         "{"
         "    \"arguments\": {"
@@ -1880,7 +1904,7 @@ TEST_F(HAImplTest, statusGetBackupServer) {
         "    },"
         "    \"result\": 0"
         "}";
-    EXPECT_TRUE(isEquivalent(got, Element::fromJSON(expected)));
+    expectEqWithDiff(Element::fromJSON(expected), got);
 }
 
 // Tests status-get command processed handler for primary server being in the
@@ -1910,6 +1934,14 @@ TEST_F(HAImplTest, statusGetPassiveBackup) {
     callout_handle->getArgument("response", got);
     ASSERT_TRUE(got);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    ConstElementPtr ha_servers(
+        got->get("arguments")->get("high-availability")->get(0)->get("ha-servers"));
+    EXPECT_TRUE(ha_servers);
+    ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+    checkThatTimeIsParsable(local);
+
     std::string expected =
         "{"
         "    \"arguments\": {"
@@ -1930,7 +1962,7 @@ TEST_F(HAImplTest, statusGetPassiveBackup) {
         "    },"
         "    \"result\": 0"
         "}";
-    EXPECT_TRUE(isEquivalent(got, Element::fromJSON(expected)));
+    expectEqWithDiff(Element::fromJSON(expected), got);
 }
 
 // Tests status-get command processed handler for standby server in the
@@ -1960,6 +1992,18 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
     callout_handle->getArgument("response", got);
     ASSERT_TRUE(got);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    for (int i = 0; i < 2; ++i) {
+        ConstElementPtr ha_servers(
+            got->get("arguments")->get("high-availability")->get(i)->get("ha-servers"));
+        EXPECT_TRUE(ha_servers);
+        ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+        ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
+        checkThatTimeIsParsable(local);
+        checkThatTimeIsParsable(remote);
+    }
+
     std::string expected =
         "{"
         "    \"arguments\": {"
@@ -1976,6 +2020,7 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
         "                    \"remote\": {"
         "                        \"age\": 0,"
         "                        \"analyzed-packets\": 0,"
+        "                        \"clock-skew\": 0,"
         "                        \"communication-interrupted\": false,"
         "                        \"connecting-clients\": 0,"
         "                        \"in-touch\": false,"
@@ -2000,6 +2045,7 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
         "                    \"remote\": {"
         "                        \"age\": 0,"
         "                        \"analyzed-packets\": 0,"
+        "                        \"clock-skew\": 0,"
         "                        \"communication-interrupted\": false,"
         "                        \"connecting-clients\": 0,"
         "                        \"in-touch\": false,"
@@ -2017,7 +2063,7 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
         "    },"
         "    \"result\": 0"
         "}";
-    EXPECT_TRUE(isEquivalent(got, Element::fromJSON(expected)));
+    expectEqWithDiff(Element::fromJSON(expected), got);
 }
 
 // Test ha-maintenance-notify command handler with server name.
index be05601265f7d7c25629649f88364184abeabc97..1a2a1c6b60156c23066a87d46b1ff86726e4f73a 100644 (file)
@@ -39,6 +39,7 @@
 #include <http/response_json.h>
 #include <util/multi_threading_mgr.h>
 #include <testutils/gtest_utils.h>
+#include <testutils/test_to_element.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/pointer_cast.hpp>
@@ -59,6 +60,7 @@ using namespace isc::ha;
 using namespace isc::ha::test;
 using namespace isc::hooks;
 using namespace isc::http;
+using namespace isc::test;
 using namespace isc::util;
 
 /// @file The tests herein were created prior to HA+MT but are very valuable
@@ -2632,6 +2634,14 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisPrimary) {
     // Check the reported info about servers.
     ConstElementPtr ha_servers = service.processStatusGet();
     ASSERT_TRUE(ha_servers);
+
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+    ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
+    checkThatTimeIsParsable(local);
+    checkThatTimeIsParsable(remote);
+
     std::string expected = "{"
         "    \"local\": {"
         "        \"role\": \"primary\","
@@ -2650,10 +2660,11 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisPrimary) {
         "        \"connecting-clients\": 0,"
         "        \"unacked-clients\": 0,"
         "        \"unacked-clients-left\": 0,"
-        "        \"analyzed-packets\": 0"
+        "        \"analyzed-packets\": 0,"
+        "        \"clock-skew\": 0"
         "    }"
         "}";
-    EXPECT_TRUE(isEquivalent(Element::fromJSON(expected), ha_servers));
+    expectEqWithDiff(Element::fromJSON(expected), ha_servers);
 
     // Set the test size - 65535 queries.
     const unsigned queries_num = 65535;
@@ -2683,6 +2694,13 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisStandby) {
     ConstElementPtr ha_servers = service.processStatusGet();
     ASSERT_TRUE(ha_servers);
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    ElementPtr local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+    ElementPtr remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
+    checkThatTimeIsParsable(local);
+    checkThatTimeIsParsable(remote);
+
     std::string expected = "{"
         "    \"local\": {"
         "        \"role\": \"standby\","
@@ -2701,10 +2719,11 @@ TEST_F(HAServiceTest, hotStandbyScopeSelectionThisStandby) {
         "        \"connecting-clients\": 0,"
         "        \"unacked-clients\": 0,"
         "        \"unacked-clients-left\": 0,"
-        "        \"analyzed-packets\": 0"
+        "        \"analyzed-packets\": 0,"
+        "        \"clock-skew\": 0"
         "    }"
         "}";
-    EXPECT_TRUE(isEquivalent(Element::fromJSON(expected), ha_servers));
+    expectEqWithDiff(Element::fromJSON(expected), ha_servers);
 
     // Set the test size - 65535 queries.
     const unsigned queries_num = 65535;
@@ -6563,6 +6582,13 @@ TEST_F(HAServiceStateMachineTest, waitingParterDownLoadBalancingPartnerDown) {
     std::ostringstream s;
     s << age_value;
 
+    // Check that system-time exists and that format is parsable by ptime.
+    // Do not check exact value because it can be time-sensitive.
+    ElementPtr mutable_local(boost::const_pointer_cast<Element>(ha_servers->get("local")));
+    ElementPtr mutable_remote(boost::const_pointer_cast<Element>(ha_servers->get("remote")));
+    checkThatTimeIsParsable(mutable_local);
+    checkThatTimeIsParsable(mutable_remote);
+
     std::string expected = "{"
         "    \"local\": {"
         "        \"role\": \"primary\","
@@ -6581,10 +6607,11 @@ TEST_F(HAServiceStateMachineTest, waitingParterDownLoadBalancingPartnerDown) {
         "        \"connecting-clients\": 0,"
         "        \"unacked-clients\": 0,"
         "        \"unacked-clients-left\": 0,"
-        "        \"analyzed-packets\": 0"
+        "        \"analyzed-packets\": 0,"
+        "        \"clock-skew\": 0"
         "    }"
         "}";
-    EXPECT_TRUE(isEquivalent(Element::fromJSON(expected), ha_servers));
+    expectEqWithDiff(Element::fromJSON(expected), ha_servers);
 
     // Crash the partner and see whether our server can return to the partner
     // down state.
index 350df09a7116fc180e9a16376e7fb233cf2b85ac..3494719bbc6d88e54c4296518646903810ede6a1 100644 (file)
@@ -22,7 +22,6 @@
 #include <hooks/hooks_manager.h>
 #include <util/range_utilities.h>
 #include <functional>
-#include <utility>
 #include <vector>
 
 using namespace isc::asiolink;
@@ -30,6 +29,8 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 
+using namespace std;
+
 namespace {
 
 /// @brief Structure that holds registered hook indexes.
@@ -146,6 +147,33 @@ HATest::signalServiceRunning(bool& running, std::mutex& mutex,
     condvar.notify_one();
 }
 
+
+void
+HATest::checkThatTimeIsParsable(ElementPtr node) {
+    ConstElementPtr system_time(node->get("system-time"));
+    EXPECT_TRUE(system_time);
+
+    // Is freed automatically by std::locale. See [localization.locales.locale#6] and
+    // [localization.locales.locale.facet#2] in the C++ standard.
+    boost::posix_time::time_input_facet* facet(
+        new boost::posix_time::time_input_facet("%Y-%m-%d %H:%M:%S"));
+
+    stringstream ss;
+    ss.imbue(std::locale(std::locale(), facet));
+    EXPECT_EQ(system_time->getType(), Element::string);
+    ss << system_time->stringValue();
+    boost::posix_time::ptime t;
+    ss >> t;
+
+    // Reset stringstream.
+    ss = stringstream();
+
+    ss << t;
+    EXPECT_NE(ss.str(), "not-a-date-time");
+
+    node->remove("system-time");
+}
+
 void
 HATest::stopIOServiceHandler(bool& stop_flag) {
     stop_flag = true;
index 911ff9cb876c9e87a6657ae6797a4437232bf87d..a12359cfb9abedc9cc2af6b21a106b3b24afa465 100644 (file)
@@ -129,6 +129,16 @@ protected:
     void signalServiceRunning(bool& running, std::mutex& mutex,
                               std::condition_variable& condvar);
 
+    /// @brief Check that a map element pointer representing the reported status
+    /// of an HA node contains  string element pointer indexed by the
+    /// "system-time" key that can be parsed in a ptime object.
+    ///
+    /// Also removes the "system-time" element for the purpose of holistically
+    /// comparing the node without worrying about time-sensitive information.
+    ///
+    /// @brief param the node element pointer
+    void checkThatTimeIsParsable(isc::data::ElementPtr node);
+
 public:
 
     /// @brief Handler for timeout during runIOService invocation.