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)
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,
/// @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_;
--- /dev/null
+// 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 <config.h>
+
+#include <exceptions/exceptions.h>
+#include <monitored_duration_store.h>
+#include <util/multi_threading_mgr.h>
+
+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<KeyTag>();
+ auto duration_iter = index.find(boost::make_tuple(key->getQueryType(),
+ key->getResponseType(),
+ key->getStartEventLabel(),
+ key->getEndEventLabel(),
+ key->getSubnetId()));
+#else
+ const auto& index = durations_.get<DurationKeyTag>();
+ 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<DurationKeyTag>();
+ 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<DurationKeyTag>();
+ 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<DurationKeyTag>();
+ 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
+
--- /dev/null
+// 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 <exceptions/exceptions.h>
+#include <monitored_duration.h>
+
+#include <boost/multi_index/indexed_by.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/composite_key.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <string>
+
+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
+/// <TBD>
+///
+/// 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<DurationKeyTag>,
+ boost::multi_index::identity<DurationKey>
+ >
+ /// @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<KeyTag>,
+ boost::multi_index::composite_key<
+ MonitoredDuration,
+ // The query packet type
+ boost::multi_index::const_mem_fun<DurationKey, uint8_t,
+ &DurationKey::getQueryType>,
+ // The response packet type
+ boost::multi_index::const_mem_fun<DurationKey, uint8_t,
+ &DurationKey::getResponseType>,
+ // The start event label
+ boost::multi_index::const_mem_fun<DurationKey, std::string,
+ &DurationKey::getStartEventLabel>,
+ // The end event label
+ boost::multi_index::const_mem_fun<DurationKey, std::string,
+ &DurationKey::getEndEventLabel>,
+ // The subnet id
+ boost::multi_index::const_mem_fun<DurationKey, dhcp::SubnetID,
+ &DurationKey::getSubnetId>
+ >
+ >
+#endif
+ >
+> MonitoredDurationContainer;
+
+/// @brief Type for a collection of MonitoredDurationPtrs.
+typedef std::vector<MonitoredDurationPtr> MonitoredDurationCollection;
+
+/// @brief Type for a pointer to a collection of MonitoredDurationPtrs.
+typedef boost::shared_ptr<MonitoredDurationCollection> 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 <TBD>
+/// 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<std::mutex> mutex_;
+};
+
+typedef boost::shared_ptr<MonitoredDurationStore> MonitoredDurationStorePtr;
+
+} // end of namespace ping_check
+} // end of namespace isc
+
+#endif
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)
--- /dev/null
+// 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 <config.h>
+#include <monitored_duration_store.h>
+#include <dhcp/dhcp6.h>
+#include <testutils/gtest_utils.h>
+#include <testutils/multi_threading_utils.h>
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+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<DurationKeyPtr> 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
}
}
+/// @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;