From: Thomas Markwalder Date: Wed, 21 Apr 2021 16:50:58 +0000 (-0400) Subject: [#1736] Added MT unit tests for CommunicationState X-Git-Tag: Kea-1.9.7~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cfa4c84c3eca036a602052074638efca90ed3af6;p=thirdparty%2Fkea.git [#1736] Added MT unit tests for CommunicationState modified: src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc --- diff --git a/src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc b/src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc index 60dd29ca0a..b114673c05 100644 --- a/src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc +++ b/src/hooks/dhcp/high_availability/tests/communication_state_unittest.cc @@ -55,6 +55,54 @@ public: io_service_->poll(); } + /// @brief Verifies that the partner state is set and retrieved correctly. + void partnerStateTest(); + + /// @brief Verifies that the partner's scopes are set and retrieved correctly. + void partnerScopesTest(); + + /// @brief Verifies that the object is poked right after construction. + void initialDurationTest(); + + /// @brief Verifies that poking the state updates the returned duration. + void pokeTest(); + + /// @brief Test that heartbeat function is triggered. + void heartbeatTest(); + + /// @brief Test that invalid values provided to startHeartbeat are rejected. + void startHeartbeatInvalidValuesTest(); + + /// @brief Test that failure detection works properly for DHCPv4 case. + void detectFailureV4Test(); + + /// @brief This test verifies that it is possible to disable analysis of the DHCPv4 + /// packets in which case the partner's failure is assumed when there is + /// no connection over the control channel. + void failureDetectionDisabled4Test(); + + /// @brief Test that failure detection works properly for DHCPv6 case. + void detectFailureV6Test(); + + /// @brief This test verifies that it is possible to disable analysis of the DHCPv6 + /// packets in which case the partner's failure is assumed when there is + /// no connection over the control channel. + void failureDetectionDisabled6Test(); + + /// @brief This test verifies that the clock skew is checked properly by the + /// clockSkewShouldWarn and clockSkewShouldTerminate functions. + void clockSkewTest(); + + /// @brief This test verifies that the clock skew value is formatted correctly + /// for logging. + void logFormatClockSkewTest(); + + /// @brief Tests that the communication state report is correct. + void getReportTest(); + + /// @brief Tests unusual values used to create the report. + void getReportDefaultValuesTest(); + /// @brief Returns test heartbeat implementation. /// /// @return Pointer to heartbeat implementation function under test. @@ -79,7 +127,8 @@ public: }; // Verifies that the partner state is set and retrieved correctly. -TEST_F(CommunicationStateTest, partnerState) { +void +CommunicationStateTest::partnerStateTest() { // Initially the state is unknown. EXPECT_LT(state_.getPartnerState(), 0); @@ -112,7 +161,8 @@ TEST_F(CommunicationStateTest, partnerState) { } // Verifies that the partner's scopes are set and retrieved correctly. -TEST_F(CommunicationStateTest, partnerScopes) { +void +CommunicationStateTest::partnerScopesTest() { // Initially, the scopes should be empty. ASSERT_TRUE(state_.getPartnerScopes().empty()); @@ -148,23 +198,14 @@ TEST_F(CommunicationStateTest, partnerScopes) { } // Verifies that the object is poked right after construction. -TEST_F(CommunicationStateTest, initialDuration) { +void +CommunicationStateTest::initialDurationTest() { EXPECT_TRUE(state_.isPoked()); } // Verifies that poking the state updates the returned duration. -TEST_F(CommunicationStateTest, poke) { - state_.modifyPokeTime(-30); - ASSERT_GE(state_.getDurationInMillisecs(), 30000); - ASSERT_TRUE(state_.isCommunicationInterrupted()); - ASSERT_NO_THROW(state_.poke()); - EXPECT_TRUE(state_.isPoked()); - EXPECT_FALSE(state_.isCommunicationInterrupted()); -} - -// Verifies that poking the state updates the returned duration. -TEST_F(CommunicationStateTest, pokeMultiThreading) { - MultiThreadingMgr::instance().setMode(true); +void +CommunicationStateTest::pokeTest() { state_.modifyPokeTime(-30); ASSERT_GE(state_.getDurationInMillisecs(), 30000); ASSERT_TRUE(state_.isCommunicationInterrupted()); @@ -174,7 +215,8 @@ TEST_F(CommunicationStateTest, pokeMultiThreading) { } // Test that heartbeat function is triggered. -TEST_F(CommunicationStateTest, heartbeat) { +void +CommunicationStateTest::heartbeatTest() { // Set poke time to the past and expect that the object is considered // not poked. state_.modifyPokeTime(-30); @@ -196,134 +238,16 @@ TEST_F(CommunicationStateTest, heartbeat) { } // Test that invalid values provided to startHeartbeat are rejected. -TEST_F(CommunicationStateTest, startHeartbeatInvalidValues) { +void +CommunicationStateTest::startHeartbeatInvalidValuesTest() { EXPECT_THROW(state_.startHeartbeat(-1, getHeartbeatImpl()), BadValue); EXPECT_THROW(state_.startHeartbeat(0, getHeartbeatImpl()), BadValue); EXPECT_THROW(state_.startHeartbeat(1, 0), BadValue); } // Test that failure detection works properly for DHCPv4 case. -TEST_F(CommunicationStateTest, detectFailureV4) { - // Initially, there should be no unacked clients recorded. - ASSERT_FALSE(state_.failureDetected()); - EXPECT_EQ(0, state_.getUnackedClientsCount()); - EXPECT_EQ(0, state_.getConnectingClientsCount()); - EXPECT_EQ(0, state_.getAnalyzedMessagesCount()); - - // The maximum number of unacked clients is 10. Let's provide 10 - // DHCPDISCOVER messages with the "secs" value of 15 which exceeds - // the threshold of 10. All these clients should be recorded as - // unacked. - for (uint8_t i = 0; i < 10; ++i) { - // Some of the requests have no client identifier to test that - // we don't fall over if the client identifier is null. - const uint8_t client_id_seed = (i < 5 ? i : 0); - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, i, - client_id_seed, - 15))); - // We don't exceed the maximum of number of unacked clients so the - // partner failure shouldn't be reported. - ASSERT_FALSE(state_.failureDetected()) - << "failure detected for the request number " - << static_cast(i); - } - EXPECT_EQ(10, state_.getUnackedClientsCount()); - EXPECT_EQ(10, state_.getConnectingClientsCount()); - EXPECT_EQ(10, state_.getAnalyzedMessagesCount()); - - // Let's provide similar set of requests but this time the "secs" field is - // below the threshold. They should not be counted as failures. Also, - // all of these requests have client identifier. - for (uint8_t i = 0; i < 10; ++i) { - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, i, i, - 9))); - ASSERT_FALSE(state_.failureDetected()) - << "failure detected for the request number " - << static_cast(i); - } - EXPECT_EQ(10, state_.getUnackedClientsCount()); - EXPECT_EQ(15, state_.getConnectingClientsCount()); - EXPECT_EQ(20, state_.getAnalyzedMessagesCount()); - - // Let's create a message from a new (not recorded yet) client with the - // "secs" field value below the threshold. It should not be counted as failure. - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, 10, 10, 6))); - - // Still no failure. - ASSERT_FALSE(state_.failureDetected()); - EXPECT_EQ(10, state_.getUnackedClientsCount()); - EXPECT_EQ(16, state_.getConnectingClientsCount()); - EXPECT_EQ(21, state_.getAnalyzedMessagesCount()); - - // Let's repeat one of the requests which already have been recorded as - // unacked but with a greater value of "secs" field. This should not - // be counted because only new clients count. - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, 3, 3, 20))); - ASSERT_FALSE(state_.failureDetected()); - EXPECT_EQ(10, state_.getUnackedClientsCount()); - EXPECT_EQ(16, state_.getConnectingClientsCount()); - EXPECT_EQ(22, state_.getAnalyzedMessagesCount()); - - // This time let's simulate a client with a MAC address already recorded but - // with a client identifier. This should be counted as a new unacked request. - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, 7, 7, 15))); - ASSERT_TRUE(state_.failureDetected()); - EXPECT_EQ(11, state_.getUnackedClientsCount()); - EXPECT_EQ(16, state_.getConnectingClientsCount()); - EXPECT_EQ(23, state_.getAnalyzedMessagesCount()); - - // Poking should cause all counters to reset as it is an indication that the - // control connection has been re-established. - ASSERT_NO_THROW(state_.poke()); - - // We're back to no failure state. - EXPECT_FALSE(state_.failureDetected()); - EXPECT_EQ(0, state_.getUnackedClientsCount()); - EXPECT_EQ(0, state_.getConnectingClientsCount()); - EXPECT_EQ(0, state_.getAnalyzedMessagesCount()); - - // Send 11 DHCPDISCOVER messages with the "secs" field bytes swapped. Swapping - // bytes was reported for some misbehaving Windows clients. The server should - // detect bytes swapping when second byte is 0 and the first byte is non-zero. - // However, the first byte is equal to 5 which is below our threshold so none - // of the requests below should count as unacked. - for (uint8_t i = 0; i < 11; ++i) { - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, i, i, - 0x0500))); - ASSERT_FALSE(state_.failureDetected()) - << "failure detected for the request number " - << static_cast(i) - << " when testing swapped secs field bytes"; - } - EXPECT_EQ(0, state_.getUnackedClientsCount()); - EXPECT_EQ(11, state_.getConnectingClientsCount()); - EXPECT_EQ(11, state_.getAnalyzedMessagesCount()); - - // Repeat the same test, but this time either the first byte exceeds the - // secs threshold or the second byte is non-zero. All should be counted - // as unacked. - for (uint8_t i = 0; i < 10; ++i) { - uint16_t secs = (i % 2 == 0 ? 0x0F00 : 0x0501); - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, i, i, - secs))); - ASSERT_FALSE(state_.failureDetected()) - << "failure detected for the request number " - << static_cast(i) - << " when testing swapped secs field bytes"; - } - - // This last message should cause the failure state. - ASSERT_NO_THROW(state_.analyzeMessage(createMessage4(DHCPDISCOVER, 11, 11, - 0x30))); - EXPECT_TRUE(state_.failureDetected()); - EXPECT_EQ(11, state_.getUnackedClientsCount()); - EXPECT_EQ(12, state_.getConnectingClientsCount()); - EXPECT_EQ(22, state_.getAnalyzedMessagesCount()); -} - -// Test that failure detection works properly for DHCPv4 case. -TEST_F(CommunicationStateTest, detectFailureV4MultiThreading) { - MultiThreadingMgr::instance().setMode(true); +void +CommunicationStateTest::detectFailureV4Test() { // Initially, there should be no unacked clients recorded. ASSERT_FALSE(state_.failureDetected()); EXPECT_EQ(0, state_.getUnackedClientsCount()); @@ -444,100 +368,15 @@ TEST_F(CommunicationStateTest, detectFailureV4MultiThreading) { // This test verifies that it is possible to disable analysis of the DHCPv4 // packets in which case the partner's failure is assumed when there is // no connection over the control channel. -TEST_F(CommunicationStateTest, failureDetectionDisabled4) { +void +CommunicationStateTest::failureDetectionDisabled4Test() { state_.config_->setMaxUnackedClients(0); EXPECT_TRUE(state_.failureDetected()); } -// This test verifies that it is possible to disable analysis of the DHCPv4 -// packets in which case the partner's failure is assumed when there is -// no connection over the control channel. -TEST_F(CommunicationStateTest, failureDetectionDisabled4MultiThreading) { - MultiThreadingMgr::instance().setMode(true); - state_.config_->setMaxUnackedClients(0); - EXPECT_TRUE(state_.failureDetected()); -} - -// Test that failure detection works properly for DHCPv6 case. -TEST_F(CommunicationStateTest, detectFailureV6) { - // Initially, there should be no unacked clients recorded. - ASSERT_FALSE(state6_.failureDetected()); - EXPECT_EQ(0, state6_.getUnackedClientsCount()); - EXPECT_EQ(0, state6_.getConnectingClientsCount()); - EXPECT_EQ(0, state6_.getAnalyzedMessagesCount()); - - // The maximum number of unacked clients is 10. Let's provide 10 - // Solicit messages with the "elapsed time" value of 1500 which exceeds - // the threshold of 10000ms. Note that the elapsed time value is provided - // in 1/100s of 1 second. All these clients should be recorded as - // unacked. - for (uint8_t i = 0; i < 10; ++i) { - ASSERT_NO_THROW(state6_.analyzeMessage(createMessage6(DHCPV6_SOLICIT, i, - 1500))); - // We don't exceed the maximum number of unacked clients so the - // partner failure shouldn't be reported. - ASSERT_FALSE(state6_.failureDetected()) - << "failure detected for the request number " - << static_cast(i); - } - EXPECT_EQ(10, state6_.getUnackedClientsCount()); - EXPECT_EQ(10, state6_.getConnectingClientsCount()); - EXPECT_EQ(10, state6_.getAnalyzedMessagesCount()); - - // Let's provide similar set of requests but this time the "elapsed time" is - // below the threshold. This should not reduce the number of unacked or new - // clients. - for (uint8_t i = 0; i < 10; ++i) { - ASSERT_NO_THROW(state6_.analyzeMessage(createMessage6(DHCPV6_SOLICIT, i, - 900))); - ASSERT_FALSE(state6_.failureDetected()) - << "failure detected for the request number " - << static_cast(i); - } - EXPECT_EQ(10, state6_.getUnackedClientsCount()); - EXPECT_EQ(10, state6_.getConnectingClientsCount()); - EXPECT_EQ(20, state6_.getAnalyzedMessagesCount()); - - // Let's create a message from a new (not recorded yet) client with the - // "elapsed time" value below the threshold. It should not count as failure. - ASSERT_NO_THROW(state6_.analyzeMessage(createMessage6(DHCPV6_SOLICIT, 10, 600))); - - // Still no failure. - ASSERT_FALSE(state6_.failureDetected()); - EXPECT_EQ(10, state6_.getUnackedClientsCount()); - EXPECT_EQ(11, state6_.getConnectingClientsCount()); - EXPECT_EQ(21, state6_.getAnalyzedMessagesCount()); - - // Let's repeat one of the requests which already have been recorded as - // unacked but with a greater value of "elapsed time". This should not - // be counted because only new clients count. - ASSERT_NO_THROW(state6_.analyzeMessage(createMessage6(DHCPV6_SOLICIT, 3, 2000))); - ASSERT_FALSE(state6_.failureDetected()); - EXPECT_EQ(10, state6_.getUnackedClientsCount()); - EXPECT_EQ(11, state6_.getConnectingClientsCount()); - EXPECT_EQ(22, state6_.getAnalyzedMessagesCount()); - - // New unacked client should cause failure to be detected. - ASSERT_NO_THROW(state6_.analyzeMessage(createMessage6(DHCPV6_SOLICIT, 11, 1500))); - ASSERT_TRUE(state6_.failureDetected()); - EXPECT_EQ(11, state6_.getUnackedClientsCount()); - EXPECT_EQ(12, state6_.getConnectingClientsCount()); - EXPECT_EQ(23, state6_.getAnalyzedMessagesCount()); - - // Poking should cause all counters to reset as it is an indication that the - // control connection has been re-established. - ASSERT_NO_THROW(state6_.poke()); - - // We're back to no failure state. - EXPECT_FALSE(state6_.failureDetected()); - EXPECT_EQ(0, state6_.getUnackedClientsCount()); - EXPECT_EQ(0, state6_.getConnectingClientsCount()); - EXPECT_EQ(0, state6_.getAnalyzedMessagesCount()); -} - // Test that failure detection works properly for DHCPv6 case. -TEST_F(CommunicationStateTest, detectFailureV6MultiThreading) { - MultiThreadingMgr::instance().setMode(true); +void +CommunicationStateTest::detectFailureV6Test() { // Initially, there should be no unacked clients recorded. ASSERT_FALSE(state6_.failureDetected()); EXPECT_EQ(0, state6_.getUnackedClientsCount()); @@ -616,23 +455,16 @@ TEST_F(CommunicationStateTest, detectFailureV6MultiThreading) { // This test verifies that it is possible to disable analysis of the DHCPv6 // packets in which case the partner's failure is assumed when there is // no connection over the control channel. -TEST_F(CommunicationStateTest, failureDetectionDisabled6) { - state6_.config_->setMaxUnackedClients(0); - EXPECT_TRUE(state6_.failureDetected()); -} - -// This test verifies that it is possible to disable analysis of the DHCPv6 -// packets in which case the partner's failure is assumed when there is -// no connection over the control channel. -TEST_F(CommunicationStateTest, failureDetectionDisabled6MultiThreading) { - MultiThreadingMgr::instance().setMode(true); +void +CommunicationStateTest::failureDetectionDisabled6Test() { state6_.config_->setMaxUnackedClients(0); EXPECT_TRUE(state6_.failureDetected()); } // This test verifies that the clock skew is checked properly by the // clockSkewShouldWarn and clockSkewShouldTerminate functions. -TEST_F(CommunicationStateTest, clockSkew) { +void +CommunicationStateTest::clockSkewTest() { // Default clock skew is 0. EXPECT_FALSE(state_.clockSkewShouldWarn()); EXPECT_FALSE(state_.clockSkewShouldTerminate()); @@ -687,7 +519,8 @@ TEST_F(CommunicationStateTest, clockSkew) { // This test verifies that the clock skew value is formatted correctly // for logging. -TEST_F(CommunicationStateTest, logFormatClockSkew) { +void +CommunicationStateTest::logFormatClockSkewTest() { // Make sure logFormatClockSkew() does not throw if called prior // the first call to setPartnerTime(). std::string log; @@ -745,7 +578,8 @@ TEST_F(CommunicationStateTest, logFormatClockSkew) { } // Tests that the communication state report is correct. -TEST_F(CommunicationStateTest, getReport) { +void +CommunicationStateTest::getReportTest() { state_.setPartnerState("waiting"); auto scopes = Element::createList(); @@ -782,7 +616,8 @@ TEST_F(CommunicationStateTest, getReport) { } // Tests unusual values used to create the report. -TEST_F(CommunicationStateTest, getReportDefaultValues) { +void +CommunicationStateTest::getReportDefaultValuesTest() { auto report = state_.getReport(); ASSERT_TRUE(report); @@ -801,4 +636,130 @@ TEST_F(CommunicationStateTest, getReportDefaultValues) { EXPECT_TRUE(isEquivalent(Element::fromJSON(expected), report)); } +TEST_F(CommunicationStateTest, partnerStateTest) { + partnerStateTest(); +} + +TEST_F(CommunicationStateTest, partnerStateTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + partnerStateTest(); +} + +TEST_F(CommunicationStateTest, partnerScopesTest) { + partnerScopesTest(); +} + +TEST_F(CommunicationStateTest, partnerScopesTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + partnerScopesTest(); +} + +TEST_F(CommunicationStateTest, initialDurationTest) { + initialDurationTest(); +} + +TEST_F(CommunicationStateTest, initialDurationTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + initialDurationTest(); +} + +TEST_F(CommunicationStateTest, pokeTest) { + pokeTest(); +} + +TEST_F(CommunicationStateTest, pokeTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + pokeTest(); +} + +TEST_F(CommunicationStateTest, heartbeatTest) { + heartbeatTest(); +} + +TEST_F(CommunicationStateTest, heartbeatTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + heartbeatTest(); +} + +TEST_F(CommunicationStateTest, startHeartbeatInvalidValuesTest) { + startHeartbeatInvalidValuesTest(); +} + +TEST_F(CommunicationStateTest, startHeartbeatInvalidValuesTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + startHeartbeatInvalidValuesTest(); +} + +TEST_F(CommunicationStateTest, detectFailureV4Test) { + detectFailureV4Test(); +} + +TEST_F(CommunicationStateTest, detectFailureV4TestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + detectFailureV4Test(); +} + +TEST_F(CommunicationStateTest, failureDetectionDisabled4Test) { + failureDetectionDisabled4Test(); +} + +TEST_F(CommunicationStateTest, failureDetectionDisabled4TestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + failureDetectionDisabled4Test(); +} + +TEST_F(CommunicationStateTest, detectFailureV6Test) { + detectFailureV6Test(); +} + +TEST_F(CommunicationStateTest, detectFailureV6TestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + detectFailureV6Test(); +} + +TEST_F(CommunicationStateTest, failureDetectionDisabled6Test) { + failureDetectionDisabled6Test(); +} + +TEST_F(CommunicationStateTest, failureDetectionDisabled6TestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + failureDetectionDisabled6Test(); +} + +TEST_F(CommunicationStateTest, clockSkewTest) { + clockSkewTest(); +} + +TEST_F(CommunicationStateTest, clockSkewTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + clockSkewTest(); +} + +TEST_F(CommunicationStateTest, logFormatClockSkewTest) { + logFormatClockSkewTest(); +} + +TEST_F(CommunicationStateTest, logFormatClockSkewTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + logFormatClockSkewTest(); +} + +TEST_F(CommunicationStateTest, getReportTest) { + getReportTest(); +} + +TEST_F(CommunicationStateTest, getReportTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + getReportTest(); +} + +TEST_F(CommunicationStateTest, getReportDefaultValuesTest) { + getReportDefaultValuesTest(); +} + +TEST_F(CommunicationStateTest, getReportDefaultValuesTestMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + getReportDefaultValuesTest(); +} + }