From: Thomas Markwalder Date: Fri, 23 Feb 2024 21:00:31 +0000 (-0500) Subject: [#3253] Initial commit of MontioredDurationStore X-Git-Tag: Kea-2.5.7~72 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=179e10ef452b481308925dbef3d2d22db2cdd892;p=thirdparty%2Fkea.git [#3253] Initial commit of MontioredDurationStore Initial implemention of MonitoredDurationStore and UTs src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc src/hooks/dhcp/perfmon/monitored_duration_store.cc src/hooks/dhcp/perfmon/monitored_duration_store.h new files src/hooks/dhcp/perfmon/Makefile.am added monitored_duration_store.cc monitored_duration_store.h src/hooks/dhcp/perfmon/monitored_duration.* Added ==, !=, < operators src/hooks/dhcp/perfmon/tests/Makefile.am added monitored_duration_store_unittests.cc src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc TEST(DurationKey, equalityOperators) - new test --- diff --git a/src/hooks/dhcp/perfmon/Makefile.am b/src/hooks/dhcp/perfmon/Makefile.am index 3d96fff9ce..f981893c69 100644 --- a/src/hooks/dhcp/perfmon/Makefile.am +++ b/src/hooks/dhcp/perfmon/Makefile.am @@ -19,6 +19,7 @@ libperfmon_la_SOURCES += perfmon_log.cc perfmon_log.h libperfmon_la_SOURCES += perfmon_messages.cc perfmon_messages.h libperfmon_la_SOURCES += monitored_duration.cc monitored_duration.h libperfmon_la_SOURCES += alarm.cc alarm.h +libperfmon_la_SOURCES += monitored_duration_store.cc monitored_duration_store.h libperfmon_la_SOURCES += version.cc libperfmon_la_CXXFLAGS = $(AM_CXXFLAGS) diff --git a/src/hooks/dhcp/perfmon/monitored_duration.cc b/src/hooks/dhcp/perfmon/monitored_duration.cc index d6ddd172fb..0da1853377 100644 --- a/src/hooks/dhcp/perfmon/monitored_duration.cc +++ b/src/hooks/dhcp/perfmon/monitored_duration.cc @@ -164,6 +164,36 @@ DurationKey::getLabel() const { return (oss.str()); }; +bool +DurationKey::operator==(const DurationKey& other) const { + return ( + (family_ == other.family_) && + (query_type_ == other.query_type_) && + (response_type_ == other.response_type_) && + (start_event_label_ == other.start_event_label_) && + (end_event_label_ == other.end_event_label_) && + (subnet_id_ == other.subnet_id_) + ); +} + +bool +DurationKey::operator!=(const DurationKey& other) const { + return (!(*this == other)); +} + +bool +DurationKey::operator<(const DurationKey& other) const { + return ( + (family_ < other.family_) || + (query_type_ < other.query_type_) || + (response_type_ < other.response_type_) || + (start_event_label_ < other.start_event_label_) || + (end_event_label_ < other.end_event_label_) || + (subnet_id_ < other.subnet_id_) + ); +} + + // MonitoredDuration methods MonitoredDuration::MonitoredDuration(uint16_t family, diff --git a/src/hooks/dhcp/perfmon/monitored_duration.h b/src/hooks/dhcp/perfmon/monitored_duration.h index 535a7882fe..7dc91b7831 100644 --- a/src/hooks/dhcp/perfmon/monitored_duration.h +++ b/src/hooks/dhcp/perfmon/monitored_duration.h @@ -210,6 +210,27 @@ public: /// @throw BadValue is the pairing does not make sense. static void validateMessagePair(uint16_t family, uint8_t query_type, uint8_t response_type); + /// @brief Equality operator. + /// + /// equality operator to compare two DurationKey objects. + /// @param other DurationKey to be compared against. + /// @return True the keys are equal + bool operator==(const DurationKey& other) const; + + /// @brief Inequality operator. + /// + /// Inequality operator to compare two DurationKey objects. + /// @param other DurationKey to be compared against. + /// @return True the keys are not equal + bool operator!=(const DurationKey& other) const; + + /// @brief Less than operator. + /// + /// less than operator to compare two DurationKey objects. + /// @param other DurationKey to be compared against. + /// @return True other is less than this key + bool operator<(const DurationKey& other) const; + protected: /// @brief Protocol family AF_INET or AF_INET6. uint16_t family_; diff --git a/src/hooks/dhcp/perfmon/monitored_duration_store.cc b/src/hooks/dhcp/perfmon/monitored_duration_store.cc new file mode 100644 index 0000000000..7ee473d95b --- /dev/null +++ b/src/hooks/dhcp/perfmon/monitored_duration_store.cc @@ -0,0 +1,144 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include + +using namespace isc; +using namespace isc::util; + +namespace isc { +namespace perfmon { + +MonitoredDurationStore::MonitoredDurationStore(uint16_t family, const Duration& interval_duration) + : family_(family), interval_duration_(interval_duration), durations_(), mutex_(new std::mutex) { + if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) { + isc_throw(BadValue, "MonitoredDurationStore - invalid interval_duration " + << interval_duration_ << ", must be greater than zero"); + } +} + +MonitoredDurationPtr +MonitoredDurationStore::addDuration(DurationKeyPtr key, + const Duration& sample /* = ZERO_DURATION()*/) { + if (!key) { + isc_throw(BadValue, "MonitoredDurationStore::addDuration - key is empty"); + } + + if (key->getFamily() != family_) { + isc_throw(BadValue, "MonitoredDurationStore::addDuration - cannot add " + << (family_ == AF_INET ? "v6 key to v4" : "v4 key to v6") + << " store"); + } + + // Create the duration instance. + MonitoredDurationPtr mond; + try { + mond.reset(new MonitoredDuration(*key, interval_duration_)); + // Add the first sample if provided. + if (sample > DurationDataInterval::ZERO_DURATION()) { + mond->addSample(sample); + } + } catch (const std::exception& ex) { + isc_throw(BadValue, "MonitoredDurationStore::addDuration failed: " << ex.what()); + } + + // Now lock and insert the new duration. + { + MultiThreadingLock lock(*mutex_); + auto ret = durations_.insert(mond); + if (ret.second == false) { + isc_throw(DuplicateDurationKey, + "MonitoredDurationStore::addDuration: duration already exists for: " + << key->getLabel()); + } + } + + // Return a copy of what we inserted. + return (MonitoredDurationPtr(new MonitoredDuration(*mond))); +} + +MonitoredDurationPtr +MonitoredDurationStore::getDuration(DurationKeyPtr key) { + if (!key) { + isc_throw(BadValue, "MonitoredDurationStore::getDuration - key is empty"); + } + + MultiThreadingLock lock(*mutex_); +#if 0 + const auto& index = durations_.get(); + auto duration_iter = index.find(boost::make_tuple(key->getQueryType(), + key->getResponseType(), + key->getStartEventLabel(), + key->getEndEventLabel(), + key->getSubnetId())); +#else + const auto& index = durations_.get(); + auto duration_iter = index.find(*key); +#endif + return (duration_iter == index.end() ? MonitoredDurationPtr() + : MonitoredDurationPtr(new MonitoredDuration(**duration_iter))); +} + +void +MonitoredDurationStore::updateDuration(MonitoredDurationPtr& duration) { + if (!duration) { + isc_throw(BadValue, "MonitoredDurationStore::updateDuration - duration is empty"); + } + + MultiThreadingLock lock(*mutex_); + auto& index = durations_.get(); + auto duration_iter = index.find(*duration); + if (duration_iter == index.end()) { + isc_throw(InvalidOperation, "MonitoredDurationStore::updateDuration duration not found: " + << duration->getLabel()); + } + + // Use replace() to re-index durations. + index.replace(duration_iter, MonitoredDurationPtr(new MonitoredDuration(*duration))); +} + +void +MonitoredDurationStore::deleteDuration(DurationKeyPtr key) { + if (!key) { + isc_throw(BadValue, "MonitoredDurationStore::deleteDuration - key is empty"); + } + + MultiThreadingLock lock(*mutex_); + auto& index = durations_.get(); + auto duration_iter = index.find(*key); + if (duration_iter == index.end()) { + // Not there, just return. + return; + } + + // Remove the context from the store. + durations_.erase(duration_iter); +} + +MonitoredDurationCollectionPtr +MonitoredDurationStore::getAll() { + MultiThreadingLock lock(*mutex_); + const auto& index = durations_.get(); + MonitoredDurationCollectionPtr collection(new MonitoredDurationCollection()); + for (auto duration_iter = index.begin(); duration_iter != index.end(); ++duration_iter) { + collection->push_back(MonitoredDurationPtr(new MonitoredDuration(**duration_iter))); + } + + return (collection); +} + +void +MonitoredDurationStore::clear() { + isc_throw(NotImplemented, __FUNCTION__); +} + +} // end of namespace perfmon +} // end of namespace isc + diff --git a/src/hooks/dhcp/perfmon/monitored_duration_store.h b/src/hooks/dhcp/perfmon/monitored_duration_store.h new file mode 100644 index 0000000000..1f6555437e --- /dev/null +++ b/src/hooks/dhcp/perfmon/monitored_duration_store.h @@ -0,0 +1,181 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef MONITORED_DURATION_STORE_H +#define MONITORED_DURATION_STORE_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace isc { +namespace perfmon { + +/// @brief Exception thrown when an attempt was made to add a duplicate key +/// to either the duration or alarm stores. +class DuplicateDurationKey : public Exception { +public: + DuplicateDurationKey(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Tag for index by primary key (DurationKey). +struct DurationKeyTag { }; + +/// @brief A multi index container holding pointers to MonitoredDurations. +/// +/// The durations in the container may be accessed using different indexes: +/// - using the full key index +/// +/// +/// Indexes can be accessed using the index number (from 0 to n) or a +/// name tag. It is recommended to use the tags to access indexes as +/// they do not depend on the order of indexes in the container. +typedef boost::multi_index_container< + // It holds pointers to Lease6 objects. + MonitoredDurationPtr, + boost::multi_index::indexed_by< + // Specification of the first index starts here. + // This index sorts using DurationKey::operators + boost::multi_index::ordered_unique< + boost::multi_index::tag, + boost::multi_index::identity + > + /// @todo more indexes start here... +#if 0 + /// @todo toss this ... did this before I figured out how to use + /// DurationKey::operator< + , + boost::multi_index::ordered_unique< + boost::multi_index::tag, + boost::multi_index::composite_key< + MonitoredDuration, + // The query packet type + boost::multi_index::const_mem_fun, + // The response packet type + boost::multi_index::const_mem_fun, + // The start event label + boost::multi_index::const_mem_fun, + // The end event label + boost::multi_index::const_mem_fun, + // The subnet id + boost::multi_index::const_mem_fun + > + > +#endif + > +> MonitoredDurationContainer; + +/// @brief Type for a collection of MonitoredDurationPtrs. +typedef std::vector MonitoredDurationCollection; + +/// @brief Type for a pointer to a collection of MonitoredDurationPtrs. +typedef boost::shared_ptr MonitoredDurationCollectionPtr; + +/// @brief Maintains an in-memory store of MonitoredDurations +/// +/// Provides essential CRUD functions for managing a collection of +/// MonitoredDurations. Additionally there are finders that can return +/// durations by DurationKey +/// All finders return copies of the durations found, rather than the +/// stored duration itself. +class MonitoredDurationStore { +public: + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + /// @param interval_duration the interval duration + explicit MonitoredDurationStore(uint16_t family, const Duration& interval_duration); + + /// @brief Destructor + ~MonitoredDurationStore() = default; + + /// @brief Creates a new MonitoredDuration and adds it to the store + /// + /// @param key key value of the duration to create. + /// @param sample An initial sample to add to the duration if not zero. + /// + /// @return pointer to the newly created duration. + /// @throw DuplicateDuration if a duration for the given key already exists in + /// the store. + MonitoredDurationPtr addDuration(DurationKeyPtr key, const Duration& sample + = DurationDataInterval::ZERO_DURATION()); + + /// @brief Fetches a duration from the store for a given key. + /// + /// @param key key value of the duration to fetch. + /// + /// @return Pointer the desired duration or an empty pointer. + MonitoredDurationPtr getDuration(DurationKeyPtr key); + + /// @brief Updates a duration in the store. + /// + /// The duration is assumed to already exist in the store. + /// + /// @param duration duration to update. + /// + /// @throw InvalidOperation if MonitoredDuration does not exist in the store. + void updateDuration(MonitoredDurationPtr& duration); + + /// @brief Removes the duration from the store. + /// + /// If the duration does not exist in the store, it simply returns. + /// + /// @param key key value of the duration to delete. + void deleteDuration(DurationKeyPtr key); + + /// @brief Fetches all of the durations (in order by target) + /// + /// @return a collection of all durations in the store. + MonitoredDurationCollectionPtr getAll(); + + /// @brief Removes all durations from the store. + void clear(); + + /// @brief Get protocol family + /// + /// @return uint16_t containing the family (AF_INET or AF_INET6) + uint16_t getFamily() { + return (family_); + } + +private: + /// @brief Protocol family AF_INET or AF_INET6. + uint16_t family_; + + /// @brief The length of time over data for a single MonitoredDuration is + /// accumulated before reporting. + Duration interval_duration_; + + /// @brief Container instance. + MonitoredDurationContainer durations_; + + /// @brief The mutex used to protect internal state. + const boost::scoped_ptr mutex_; +}; + +typedef boost::shared_ptr MonitoredDurationStorePtr; + +} // end of namespace ping_check +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/perfmon/tests/Makefile.am b/src/hooks/dhcp/perfmon/tests/Makefile.am index b091c961c4..75dc950b67 100644 --- a/src/hooks/dhcp/perfmon/tests/Makefile.am +++ b/src/hooks/dhcp/perfmon/tests/Makefile.am @@ -29,6 +29,7 @@ TESTS += perfmon_unittests perfmon_unittests_SOURCES = run_unittests.cc perfmon_unittests_SOURCES += monitored_duration_unittests.cc perfmon_unittests_SOURCES += alarm_unittests.cc +perfmon_unittests_SOURCES += monitored_duration_store_unittests.cc perfmon_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) diff --git a/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc b/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc new file mode 100644 index 0000000000..d18b3b97fd --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc @@ -0,0 +1,347 @@ +// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// @file This file contains tests which exercise the MonitoredDurationStore class. +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfmon; +using namespace isc::test; +using namespace boost::posix_time; + +namespace { + +// Verifies MonitoredDurationStore valid construction. +TEST(MonitoredDurationStore, validConstructors) { + MonitoredDurationStorePtr store; + + EXPECT_NO_THROW_LOG(store.reset(new MonitoredDurationStore(AF_INET, milliseconds(5)))); + ASSERT_TRUE(store); + + MonitoredDurationCollectionPtr durations; + ASSERT_NO_THROW_LOG(durations = store->getAll()); + ASSERT_TRUE(durations); + EXPECT_TRUE(durations->empty()); +} + +// Verifies MonitoredDurationStore invalid construction. +TEST(MonitoredDurationStore, invalidConstructors) { + MonitoredDurationStorePtr store; + + EXPECT_THROW_MSG(MonitoredDurationStore(AF_INET, milliseconds(0)), + BadValue, + "MonitoredDurationStore - invalid interval_duration" + " 00:00:00, must be greater than zero"); + + EXPECT_THROW_MSG(MonitoredDurationStore(AF_INET, milliseconds(-5)), + BadValue, + "MonitoredDurationStore - invalid interval_duration" + " -00:00:00.005000, must be greater than zero"); +} + +/// @brief Text fixture class for @c MonitoredDurationStore +/// +/// In order to facilitate single and multi threaded testing, +/// individual tests are implemented as methods that are called +/// from within TEST_F bodies rather than in TEST_F bodies. +class MonitoredDurationStoreTest : public ::testing::Test { +public: + + /// @brief Constructor + MonitoredDurationStoreTest() { + } + + /// @brief Destructor + virtual ~MonitoredDurationStoreTest() = default; + + /// @brief Verifies that durations be added to the store and fetched + /// by DurationKey. + void addDurationTest() { + Duration interval_duration(milliseconds(10)); + MonitoredDurationStore store(AF_INET6, interval_duration); + + // Create a key. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + // Add a duration using the key. + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.addDuration(key, interval_duration)); + ASSERT_TRUE(mond); + + // Verify we can fetch duration by key. + MonitoredDurationPtr found; + ASSERT_NO_THROW_LOG(found = store.getDuration(key)); + ASSERT_TRUE(found); + + // Verify we have different objects but equal keys. Ensures we retrieved + // a copy, not what is stored. + EXPECT_NE(found, mond); + EXPECT_EQ(*found, *mond); + + // Create a second key and duration. + DurationKeyPtr key2; + ASSERT_NO_THROW_LOG(key2.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_REPLY, + "mt_queued", "process_started", 77))); + MonitoredDurationPtr mond2; + ASSERT_NO_THROW_LOG(mond2 = store.addDuration(key2, interval_duration)); + ASSERT_TRUE(mond2); + + // Verify we can fetch duration by key. + MonitoredDurationPtr found2; + ASSERT_NO_THROW_LOG(found2 = store.getDuration(key2)); + ASSERT_TRUE(found2); + + // Fetch all durations, should return them both. + MonitoredDurationCollectionPtr durations; + ASSERT_NO_THROW_LOG(durations = store.getAll()); + ASSERT_TRUE(durations); + ASSERT_EQ(durations->size(), 2); + + // They should be in order by key. + EXPECT_EQ(*(*durations)[0], *mond); + EXPECT_EQ(*(*durations)[1], *mond2); + } + + /// @brief Verifies that duplicate durations cannot be added to the store. + void addDurationDuplicateTest() { + Duration interval_duration(milliseconds(10)); + MonitoredDurationStore store(AF_INET6, interval_duration); + + // Create a key. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + // Add a duration using the key. + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.addDuration(key, interval_duration)); + ASSERT_TRUE(mond); + + // Attempting to add it again should evoke a duplicate key exception. + ASSERT_THROW_MSG(store.addDuration(key, interval_duration), + DuplicateDurationKey, + "MonitoredDurationStore::addDuration: duration already exists for:" + " SOLICIT-ADVERTISE.mt_queued-process_started.77"); + } + + /// @brief Verifies that duration and store families must match on add. + void addDurationInvalidTest() { + Duration interval_duration(milliseconds(10)); + MonitoredDurationStorePtr store(new MonitoredDurationStore(AF_INET, interval_duration)); + + // Create a key. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + + // Attempting to add it the key should fail. + ASSERT_THROW_MSG(store->addDuration(key, interval_duration), + BadValue, + "MonitoredDurationStore::addDuration - cannot add v6 key to v4 store"); + + store.reset(new MonitoredDurationStore(AF_INET6, interval_duration)); + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "mt_queued", "process_started", 77))); + // Attempting to add it the key should fail. + ASSERT_THROW_MSG(store->addDuration(key, interval_duration), + BadValue, + "MonitoredDurationStore::addDuration - cannot add v4 key to v6 store"); + } + + /// @brief Verify that durations can be deleted from the store. + void deleteDurationTest() { + MonitoredDurationStore store(AF_INET, milliseconds(5)); + + std::vector keys; + for (int subnet = 0; subnet < 3; ++subnet) { + MonitoredDurationPtr mond; + DurationKeyPtr key(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "socket_received", "buffer_read", subnet)); + ASSERT_NO_THROW_LOG(mond = store.addDuration(key)); + ASSERT_TRUE(mond); + keys.push_back(key); + } + + // Verify we added three of them. + auto durations = store.getAll(); + ASSERT_EQ(durations->size(), 3); + + // Fetch the second duration. + MonitoredDurationPtr mond; + ASSERT_NO_THROW_LOG(mond = store.getDuration(keys[1])); + ASSERT_TRUE(mond); + EXPECT_EQ(*mond, *(keys[1])); + + // Delete it. + ASSERT_NO_THROW_LOG(store.deleteDuration(mond)); + + // Try to fetch it, shouldn't find it. + MonitoredDurationPtr mond2; + ASSERT_NO_THROW_LOG(mond2 = store.getDuration(mond)); + ASSERT_FALSE(mond2); + + // Deleting it again should do no harm. + ASSERT_NO_THROW_LOG(store.deleteDuration(mond)); + + // Verify there are two left. + durations = store.getAll(); + ASSERT_EQ(durations->size(), 2); + } + + /// @brief Verify that durations in the store can be updated. + void updateDurationTest() { + Duration interval_duration(seconds(60)); + MonitoredDurationStore store(AF_INET6, interval_duration); + MonitoredDurationPtr mond; + + // Passing in an empty duration should throw. + ASSERT_THROW_MSG(store.updateDuration(mond), BadValue, + "MonitoredDurationStore::updateDuration - duration is empty"); + + // Create a key and then a duration. + DurationKeyPtr key; + ASSERT_NO_THROW_LOG(key.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_ADVERTISE, + "mt_queued", "process_started", 77))); + ASSERT_NO_THROW(mond.reset(new MonitoredDuration(*key, interval_duration))); + + ASSERT_THROW_MSG(store.updateDuration(mond), InvalidOperation, + "MonitoredDurationStore::updateDuration duration not found:" + " SOLICIT-ADVERTISE.mt_queued-process_started.77"); + + // Now add the duration to the store. + ASSERT_NO_THROW(store.addDuration(mond)); + + // Fetch it. + MonitoredDurationPtr found; + ASSERT_NO_THROW_LOG(found = store.getDuration(key)); + ASSERT_TRUE(found); + + // Verify the fetched object is a copy. + ASSERT_NE(found, mond); + ASSERT_EQ(*found, *mond); + + // Verify that it has no intervals. + ASSERT_FALSE(found->getPreviousInterval()); + ASSERT_FALSE(found->getCurrentInterval()); + + // Now add a sample to the duration and update it. + mond->addSample(milliseconds(75)); + ASSERT_NO_THROW(store.updateDuration(mond)); + + // Fetch it again and verify there is now a current interval. + ASSERT_NO_THROW_LOG(found = store.getDuration(key)); + ASSERT_FALSE(found->getPreviousInterval()); + + DurationDataIntervalPtr current; + ASSERT_TRUE(current = found->getCurrentInterval()); + EXPECT_EQ(current->getOccurrences(), 1); + EXPECT_EQ(current->getTotalDuration(), milliseconds(75)); + } + +YOU ARE HERE +#if 0 + void getAllAndClearTest() { + MonitoredDurationStore store; + + // Add contexts to store. + for (int i = 0; i < leases_.size(); ++i) { + MonitoredDurationPtr context; + ASSERT_NO_THROW_LOG(context = store.addDuration(leases_[i], queries_[i], 1, 100)); + ASSERT_TRUE(context); + EXPECT_EQ(leases_[i], context->getLease()); + EXPECT_EQ(queries_[i], context->getQuery()); + } + + // Fetch them all. + MonitoredDurationCollectionPtr contexts; + ASSERT_NO_THROW_LOG(contexts = store.getAll()); + ASSERT_EQ(leases_.size(), contexts->size()); + + // Verify we got them all in order. + int i = 0; + for (const auto& context : *contexts) { + EXPECT_EQ(leases_[i], context->getLease()); + EXPECT_EQ(queries_[i], context->getQuery()); + ++i; + } + + // Now clear the store. Verify it's empty. + ASSERT_NO_THROW_LOG(store.clear()); + ASSERT_NO_THROW_LOG(contexts = store.getAll()); + ASSERT_EQ(0, contexts->size()); + + // Verify clearing an empty store does no harm. + ASSERT_NO_THROW_LOG(store.clear()); + } +#endif +}; + +TEST_F(MonitoredDurationStoreTest, addDuration) { + addDurationTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationMultiThreading) { + MultiThreadingTest mt; + addDurationTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationDuplicate) { + addDurationDuplicateTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationDuplicateMultiThreading) { + MultiThreadingTest mt; + addDurationDuplicateTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationInvalid) { + addDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, addDurationInvalidMultiThreading) { + MultiThreadingTest mt; + addDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, deleteDuration) { + deleteDurationTest(); +} + +TEST_F(MonitoredDurationStoreTest, deleteDurationMultiThreading) { + MultiThreadingTest mt; + deleteDurationTest(); +} + +TEST_F(MonitoredDurationStoreTest, updateDuration) { + updateDurationTest(); +} + +TEST_F(MonitoredDurationStoreTest, updateDurationMultiThreading) { + MultiThreadingTest mt; + updateDurationTest(); +} + +#if 0 +TEST_F(MonitoredDurationStoreTest, getAllAndClear) { + getAllAndClearTest(); +} + +TEST_F(MonitoredDurationStoreTest, getAllAndClearMultiThreading) { + MultiThreadingTest mt; + getAllAndClearTest(); +} +#endif + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc b/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc index 7b295d3d87..e9223472ac 100644 --- a/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc +++ b/src/hooks/dhcp/perfmon/tests/monitored_duration_unittests.cc @@ -232,6 +232,23 @@ TEST(DurationKey, validateMessagePairs6) { } } +/// @brief Verify DurationKey equality operator +TEST(DurationKey, equalityOperators) { + DurationKeyPtr refkey; + DurationKeyPtr compkey; + + ASSERT_NO_THROW_LOG(refkey.reset(new DurationKey(AF_INET6, DHCPV6_REQUEST, DHCPV6_REPLY, + "event_2", "event_3", 100))); + + ASSERT_NO_THROW_LOG(compkey.reset(new DurationKey(AF_INET6, DHCPV6_REQUEST, DHCPV6_REPLY, + "event_2", "event_3", 100))); + EXPECT_EQ(*compkey, *refkey); + + ASSERT_NO_THROW_LOG(compkey.reset(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_REPLY, + "event_2", "event_3", 100))); + EXPECT_NE(*compkey, *refkey); +} + // Verifies MonitoredDuration valid construction. TEST(MonitoredDuration, validConstructors) { MonitoredDurationPtr mond;