diff options
author | Thomas Markwalder <tmark@isc.org> | 2024-06-13 20:56:52 +0200 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2024-06-15 09:17:39 +0200 |
commit | 0e5b367beabf4dc8ff4268cff917a3c597e3e759 (patch) | |
tree | 137023ff24740ebb0208d85a71280f6ba81f1c01 | |
parent | [#3328] Doc updates (diff) | |
download | kea-0e5b367beabf4dc8ff4268cff917a3c597e3e759.tar.xz kea-0e5b367beabf4dc8ff4268cff917a3c597e3e759.zip |
[#3328] New Unit tests
/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc
TEST(DurationKey, toElement)
TEST(MonitoredDuration, toElement)
TEST(MonitoredDuration, toValueRow)
/src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc
TEST_F(PerfMonCmdTest4, invalidPerfMonGetAllDurations)
TEST_F(PerfMonCmdTest6, invalidPerfMonGetAllDurations)
TEST_F(PerfMonCmdTest4, perfMonGetAllDurationsResultSetFalse)
TEST_F(PerfMonCmdTest4, perfMonGetAllDurationsResultSetTrue)
TEST_F(PerfMonCmdTest6, perfMonGetAllDurationsResultSetFalse)
TEST_F(PerfMonCmdTest6, perfMonGetAllDurationsResultSetTrue)
-rw-r--r-- | src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc | 164 | ||||
-rw-r--r-- | src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc | 217 |
2 files changed, 359 insertions, 22 deletions
diff --git a/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc b/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc index 842902ce3a..b64d857c80 100644 --- a/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc +++ b/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc @@ -6,7 +6,9 @@ #include <config.h> #include <monitored_duration.h> +#include <cc/data.h> #include <dhcp/dhcp6.h> +#include <util/boost_time_utils.h> #include <testutils/gtest_utils.h> #include <gtest/gtest.h> @@ -14,8 +16,10 @@ #include <unordered_set> using namespace isc; +using namespace isc::data; using namespace isc::dhcp; using namespace isc::perfmon; +using namespace isc::util; using namespace boost::posix_time; namespace { @@ -255,6 +259,42 @@ TEST(DurationKey, equalityOperators) { EXPECT_NE(*compkey, *refkey); } +// Verifies the DurationKey::toElement() +TEST(DurationKey, toElement) { + DurationKeyPtr key; + + // Create valid v4 key, verify contents and label. + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL))); + ASSERT_TRUE(key); + + ElementPtr ref_key_elem = Element::createMap(); + ref_key_elem->set("query-type", Element::create("DHCPDISCOVER")); + ref_key_elem->set("response-type", Element::create("DHCPOFFER")); + ref_key_elem->set("start-event", Element::create("process_started")); + ref_key_elem->set("stop-event", Element::create("process_completed")); + ref_key_elem->set("subnet-id", Element::create(SUBNET_ID_GLOBAL)); + + auto key_elem = key->toElement(); + EXPECT_EQ(*ref_key_elem, *key_elem); + + // Create valid v6 key, verify contents and label. + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + ASSERT_TRUE(key); + + ref_key_elem = Element::createMap(); + ref_key_elem->set("query-type", Element::create("SOLICIT")); + ref_key_elem->set("response-type", Element::create("ADVERTISE")); + ref_key_elem->set("start-event", Element::create("mt_queued")); + ref_key_elem->set("stop-event", Element::create("process_started")); + ref_key_elem->set("subnet-id", Element::create(77)); + + key_elem = key->toElement(); + EXPECT_EQ(*ref_key_elem, *key_elem); +} + // Verifies MonitoredDuration valid construction. TEST(MonitoredDuration, validConstructors) { MonitoredDurationPtr mond; @@ -525,4 +565,128 @@ TEST(MonitoredDuration, expireInterval) { EXPECT_EQ(mond->getCurrentIntervalStart(), PktEvent::MIN_TIME()); } +// Verifies the MonitoredDuration::toElement(). We do not bother with +// a v6 version of this test as family only influences DurationKey content +// and that is tested elsewhere. +TEST(MonitoredDuration, toElement) { + MonitoredDurationPtr duration; + Duration interval_duration(milliseconds(50)); + + // Create valid v4 duration. + ASSERT_NO_THROW_LOG(duration.reset(new MonitoredDuration(AF_INET, DHCPDISCOVER, DHCPOFFER, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration))); + ASSERT_TRUE(duration); + duration->addSample(microseconds(5)); + duration->addSample(microseconds(2)); + duration->addSample(microseconds(7)); + + ElementPtr ref_duration_elem = Element::createMap(); + // Add the key. + ElementPtr ref_key_elem = Element::createMap(); + ref_key_elem->set("query-type", Element::create("DHCPDISCOVER")); + ref_key_elem->set("response-type", Element::create("DHCPOFFER")); + ref_key_elem->set("start-event", Element::create("process_started")); + ref_key_elem->set("stop-event", Element::create("process_completed")); + ref_key_elem->set("subnet-id", Element::create(SUBNET_ID_GLOBAL)); + ref_duration_elem->set("duration-key", ref_key_elem); + + // Add the data. Should have empty values as we do not have a previous interval. + ref_duration_elem->set("ave-duration-usecs", Element::create(0)); + ref_duration_elem->set("max-duration-usecs", Element::create(0)); + ref_duration_elem->set("min-duration-usecs", Element::create(0)); + ref_duration_elem->set("occurrences", Element::create(0)); + ref_duration_elem->set("start-time", Element::create("<none>")); + ref_duration_elem->set("total-duration-usecs", Element::create(0)); + + // Generate the valueRow Element and compare it to the reference. + auto duration_elem = duration->toElement(); + ASSERT_TRUE(duration_elem); + EXPECT_EQ(*ref_duration_elem, *duration_elem); + + // Now expire the current interval so we'll have a previous interval. + duration->expireCurrentInterval(); + auto previous_interval = duration->getPreviousInterval(); + ASSERT_TRUE(previous_interval); + + // Replace the data values with those from the new previous interval. + ref_duration_elem->set("ave-duration-usecs", Element::create(4)); + ref_duration_elem->set("max-duration-usecs", Element::create(7)); + ref_duration_elem->set("min-duration-usecs", Element::create(2)); + ref_duration_elem->set("occurrences", Element::create(3)); + ref_duration_elem->set("start-time", + Element::create(ptimeToText(previous_interval->getStartTime()))); + ref_duration_elem->set("total-duration-usecs", Element::create(14)); + + // Generate the valueRow Element and compare it to the reference. + duration_elem = duration->toElement(); + ASSERT_TRUE(duration_elem); + EXPECT_EQ(*ref_duration_elem, *duration_elem); +} + +// Verifies the MonitoredDuration::toElement(). We do not bother with +// a v4 version of this test as family only influences DurationKey content +// and that is tested elsewhere. +TEST(MonitoredDuration, toValueRow) { + MonitoredDurationPtr duration; + Duration interval_duration(milliseconds(50)); + auto ten_ms = milliseconds(10); + + // Create valid v4 duration. + ASSERT_NO_THROW_LOG(duration.reset(new MonitoredDuration(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "process_started", "process_completed", + SUBNET_ID_GLOBAL, interval_duration))); + ASSERT_TRUE(duration); + duration->addSample(microseconds(5)); + duration->addSample(microseconds(2)); + duration->addSample(microseconds(7)); + + ElementPtr ref_row_elem = Element::createList(); + // Add key values first. + ref_row_elem->add(Element::create("SOLICIT")); // query-type + ref_row_elem->add(Element::create("ADVERTISE")); // response-type + ref_row_elem->add(Element::create("process_started")); // start-event + ref_row_elem->add(Element::create("process_completed")); // stop-event + ref_row_elem->add(Element::create(SUBNET_ID_GLOBAL)); // subnet-id + + // Remember where the data values begin. + auto data_start = ref_row_elem->size(); + + // Add the data values. Should have empty values as we do not have a previous interval. + ref_row_elem->add(Element::create("<none>")); // start-time + ref_row_elem->add(Element::create(0)); // occurrences + ref_row_elem->add(Element::create(0)); // min-duration-usecs + ref_row_elem->add(Element::create(0)); // max-duration-usecs + ref_row_elem->add(Element::create(0)); // total-duration-usecs + ref_row_elem->add(Element::create(0)); // ave-duration-usecs + + // Generate the valueRow Element and compare it to the reference. + auto row_elem = duration->toValueRow(); + ASSERT_TRUE(row_elem); + EXPECT_EQ(*ref_row_elem, *row_elem); + + // Now expire the current interval so we'll have a previous interval. + duration->expireCurrentInterval(); + auto previous_interval = duration->getPreviousInterval(); + ASSERT_TRUE(previous_interval); + + // Remove the old reference data values. + while (ref_row_elem->size() > data_start) { + ref_row_elem->remove(data_start); + } + + // Add the new reference data values. + ref_row_elem->add(Element::create(ptimeToText(previous_interval->getStartTime()))); + ref_row_elem->add(Element::create(3)); // occurrences + ref_row_elem->add(Element::create(2)); // min-duration-usecs + ref_row_elem->add(Element::create(7)); // max-duration-usecs + ref_row_elem->add(Element::create(14)); // total-duration-usecs + ref_row_elem->add(Element::create(4)); // ave-duration-usecs + + // Generate the valueRow Element and compare it to the reference. + row_elem = duration->toValueRow(); + ASSERT_TRUE(row_elem); + EXPECT_EQ(*ref_row_elem, *row_elem); +} + } // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc b/src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc index 02bce8512f..ee0c538a74 100644 --- a/src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc +++ b/src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc @@ -16,6 +16,7 @@ #include <testutils/log_utils.h> #include <testutils/gtest_utils.h> #include <testutils/multi_threading_utils.h> +#include <util/boost_time_utils.h> #include <gtest/gtest.h> #include <list> @@ -31,6 +32,7 @@ using namespace isc::hooks; using namespace isc::perfmon; using namespace isc::stats; using namespace isc::test; +using namespace isc::util; using namespace isc::dhcp::test; using namespace boost::posix_time; @@ -91,28 +93,22 @@ public: mgr_->configure(json_elements); } - /// @brief Make a valid family-specific query. + /// @brief Adds durations to the store. /// - /// @return if family is AF_INET return a pointer to a DHCPDISCOVER - /// otherwise a pointer to a DHCPV6_SOLICIT. - PktPtr makeFamilyQuery() { - if (family_ == AF_INET) { - return (PktPtr(new Pkt4(DHCPDISCOVER, 7788))); + /// @param family protocol family to test, AF_INET or AF_INET6. + void addDurations(uint16_t family) { + // Create two keys where the stop event for the first key is the start + // event for the second key. + DurationKeyPtr key1(new DurationKey(family, 0, 0, "socket_received", "buffer_read", 1)); + DurationKeyPtr key2(new DurationKey(family, 0, 0, "buffer_read", "process_started", 1)); + + // Make multiple calls to addDurationSample() for each key, starting with key1. + auto store = mgr_->getDurationStore(); + ASSERT_TRUE(store); + for (int i = 0; i < 4; ++i) { + ASSERT_NO_THROW_LOG(store->addDurationSample(key1, milliseconds(1))); + ASSERT_NO_THROW_LOG(store->addDurationSample(key2, milliseconds(2))); } - - return (PktPtr(new Pkt6(DHCPV6_SOLICIT, 7788))); - } - - /// @brief Make a valid family-specific response. - /// - /// @return if family is AF_INET return a pointer to a DHCPOFFER - /// otherwise a pointer to a DHCPV6_ADVERTISE. - PktPtr makeFamilyResponse() { - if (family_ == AF_INET) { - return (PktPtr(new Pkt4(DHCPOFFER, 7788))); - } - - return (PktPtr(new Pkt6(DHCPV6_ADVERTISE, 7788))); } /// @brief Tests specified command and verifies response. @@ -178,6 +174,8 @@ public: // Run the command handler appropriate for the given command name. if (command_name == "perfmon-control") { static_cast<void>(mgr_->perfmonControlHandler(*callout_handle)); + } else if (command_name == "perfmon-get-all-durations") { + static_cast<void>(mgr_->perfmonGetAllDurationsHandler(*callout_handle)); } else { ADD_FAILURE() << "unrecognized command '" << command_name << "'"; } @@ -239,7 +237,7 @@ public: } } - // Verify that invalid perfmon-control commands are caught. + /// @brief Verify that invalid perfmon-control commands are caught. void testInvalidPerfMonControl() { struct Scenario { int line_; // Scenario line number @@ -283,7 +281,7 @@ public: } } - // Verify that valid perfmon-control are processed correctly. + /// @brief Verify that valid perfmon-control are processed correctly. void testValidPerfMonControl() { struct Scenario { int line_; // Scenario line number @@ -387,6 +385,158 @@ public: } } + /// @brief Verify that invalid perfmon-get-all-durations commands are caught. + void testInvalidPerfMonGetAllDurations() { + struct Scenario { + int line_; // Scenario line number + std::string cmd_; // JSON command text + int exp_result_; // Expected result code + std::string exp_text_; // Expected result text + }; + + std::list<Scenario> scenarios = { + { + __LINE__, + R"({ + "command": "perfmon-get-all-durations", + "arguments": { + "result-set-format": "bogus" + } + })", + CONTROL_RESULT_ERROR, + "'result-set-format' parameter is not a boolean" + }, + { + __LINE__, + R"({ + "command": "perfmon-get-all-durations", + "arguments": { + "bogus": 23 + } + })", + CONTROL_RESULT_ERROR, + "spurious 'bogus' parameter" + } + }; + + for (const auto& scenario : scenarios) { + stringstream oss; + oss << "scenario at line: " << scenario.line_; + SCOPED_TRACE(oss.str()); + ConstElementPtr answer = testCommand(scenario.cmd_, + scenario.exp_result_, + scenario.exp_text_); + } + } + + /// @brief Veriies that a valid perfmon-get-all-durations command with + /// result-set-format set false, returns all durations correctly. + void testPerfMonGetAllDurationsResultSetFalse() { + std::string now_str = ptimeToText(PktEvent::now()); + std::string cmd = + R"({ + "command": "perfmon-get-all-durations", + "arguments": { + "result-set-format": false + } + })"; + + addDurations(family_); + + auto ref_durations = mgr_->getDurationStore()->getAll(); + auto ref_time = PktEvent::now(); + std::ostringstream oss; + oss << "perfmon-get-all-durations: " << ref_durations->size() << " found"; + ConstElementPtr answer = testCommand(cmd, CONTROL_RESULT_SUCCESS, oss.str()); + + checkAnswerAgainstDurations(ref_durations, answer, ref_time, false); + } + + /// @brief Veriies that a valid perfmon-get-all-durations with result-set-format + /// set true, returns all durations correctly. + void testPerfMonGetAllDurationsResultSetTrue() { + std::string now_str = ptimeToText(PktEvent::now()); + std::string cmd = + R"({ + "command": "perfmon-get-all-durations", + "arguments": { + "result-set-format": true + } + })"; + + addDurations(family_); + auto ref_durations = mgr_->getDurationStore()->getAll(); + ASSERT_TRUE(ref_durations); + + auto ref_time = PktEvent::now(); + std::ostringstream oss; + oss << "perfmon-get-all-durations: " << ref_durations->size() << " found"; + ConstElementPtr answer = testCommand(cmd, CONTROL_RESULT_SUCCESS, oss.str()); + + checkAnswerAgainstDurations(ref_durations, answer, ref_time, true); + } + + /// @brief Verifies that the command response content against a list of + /// MonitoredDurations and the expected format. + /// + /// @param ref_durations list of expected MonitoredDurations in the order they + /// should appear in the results. + /// @param anwswer complete command answer to check + /// @param ref_time timestamp used to compare againt the "timestamp" in the answer. + /// @param result_set_format expected format style of the answer + void checkAnswerAgainstDurations(const MonitoredDurationCollectionPtr ref_durations, + ConstElementPtr answer, + const Timestamp& ref_time, + bool result_set_format) { + // Sanity check. + ASSERT_TRUE(ref_durations); + auto ref_count = ref_durations->size(); + ASSERT_TRUE(answer); + + // Verify content as either list elements or result-set. + if (!result_set_format) { + auto durations_list = answer->find("arguments/durations"); + ASSERT_TRUE(durations_list); + EXPECT_EQ(ref_count, durations_list->size()); + + int i = 0; + for (const auto& ref_duration : *ref_durations) { + auto duration_elem = durations_list->get(i); + ASSERT_TRUE(duration_elem); + EXPECT_EQ(*(duration_elem), *(ref_duration->toElement())); + ++i; + } + } else { + auto elem = answer->find("arguments/result-set-format"); + ASSERT_TRUE(elem); + ASSERT_TRUE(elem->boolValue()); + + auto result_set = answer->find("arguments/durations-result-set"); + ASSERT_TRUE(result_set); + auto columns = result_set->find("columns"); + ASSERT_TRUE(columns); + EXPECT_EQ(*columns, *MonitoredDuration::valueRowColumns()); + + auto rows = result_set->find("rows"); + ASSERT_TRUE(rows); + + int i = 0; + for (const auto& ref_duration : *ref_durations) { + auto row = rows->get(i); + ASSERT_TRUE(row); + EXPECT_EQ(*row, *(ref_duration->toValueRow())); + ++i; + } + } + + auto elem = answer->find("arguments/interval-width-secs"); + ASSERT_TRUE(elem); + EXPECT_EQ(mgr_->getIntervalWidthSecs(), elem->intValue()); + + elem = answer->find("arguments/timestamp"); + ASSERT_TRUE(elem); + EXPECT_GE(elem->stringValue(), ptimeToText(ref_time)); + } /// @brief Protocol family AF_INET or AF_INET6 uint16_t family_; @@ -437,5 +587,28 @@ TEST_F(PerfMonCmdTest6, validPerfMonControl) { testValidPerfMonControl(); } +TEST_F(PerfMonCmdTest4, invalidPerfMonGetAllDurations) { + testInvalidPerfMonGetAllDurations(); +} + +TEST_F(PerfMonCmdTest6, invalidPerfMonGetAllDurations) { + testInvalidPerfMonGetAllDurations(); +} + +TEST_F(PerfMonCmdTest4, perfMonGetAllDurationsResultSetFalse) { + testPerfMonGetAllDurationsResultSetFalse(); +} + +TEST_F(PerfMonCmdTest4, perfMonGetAllDurationsResultSetTrue) { + testPerfMonGetAllDurationsResultSetTrue(); +} + +TEST_F(PerfMonCmdTest6, perfMonGetAllDurationsResultSetFalse) { + testPerfMonGetAllDurationsResultSetFalse(); +} + +TEST_F(PerfMonCmdTest6, perfMonGetAllDurationsResultSetTrue) { + testPerfMonGetAllDurationsResultSetTrue(); +} } // end of anonymous namespace |