From: Thomas Markwalder Date: Tue, 27 Feb 2024 20:30:55 +0000 (-0500) Subject: [#3253] Added AlarmStore classes X-Git-Tag: Kea-2.5.7~68 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ea714013b034e5895fa5d7f1cb0e394ea3ca11e8;p=thirdparty%2Fkea.git [#3253] Added AlarmStore classes src/hooks/dhcp/perfmon/alarm_store.h src/hooks/dhcp/perfmon/alarm_store.cc src/hooks/dhcp/perfmon/testsalarm_store_unittests.cc new files src/hooks/dhcp/perfmon/Makefile.am Added alarm_store.cc and alarm_store.h --- diff --git a/src/hooks/dhcp/perfmon/Makefile.am b/src/hooks/dhcp/perfmon/Makefile.am index f981893c69..36302b8cc2 100644 --- a/src/hooks/dhcp/perfmon/Makefile.am +++ b/src/hooks/dhcp/perfmon/Makefile.am @@ -20,6 +20,7 @@ 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 += alarm_store.cc alarm_store.h libperfmon_la_SOURCES += version.cc libperfmon_la_CXXFLAGS = $(AM_CXXFLAGS) diff --git a/src/hooks/dhcp/perfmon/alarm_store.cc b/src/hooks/dhcp/perfmon/alarm_store.cc new file mode 100644 index 0000000000..582daf8b01 --- /dev/null +++ b/src/hooks/dhcp/perfmon/alarm_store.cc @@ -0,0 +1,137 @@ +// 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 { + +AlarmStore::AlarmStore(uint16_t family) + : family_(family), + alarms_(), + mutex_(new std::mutex) { + if (family_ != AF_INET && family_ != AF_INET6) { + isc_throw(BadValue, "AlarmStore - invalid family " + << family_ << ", must be AF_INET or AF_INET6"); + } +} + +void +AlarmStore::validateKey(const std::string& label, DurationKeyPtr key) const { + if (!key) { + isc_throw(BadValue, "AlarmStore::" << label << " - key is empty"); + } + + if (key->getFamily() != family_) { + isc_throw(BadValue, "AlarmStore::" << label + << " - family mismatch, key is " << (family_ == AF_INET ? + "v6, store is v4" : "v4, store is v6")); + } +} + +AlarmPtr +AlarmStore::addAlarm(AlarmPtr alarm) { + { + MultiThreadingLock lock(*mutex_); + auto ret = alarms_.insert(alarm); + if (ret.second == false) { + isc_throw(DuplicateAlarm, + "AlarmStore::addAlarm: alarm already exists for: " + << alarm->getLabel()); + } + } + + // Return a copy of what we inserted. + return (AlarmPtr(new Alarm(*alarm))); +} + +AlarmPtr +AlarmStore::addAlarm(DurationKeyPtr key, const Duration& low_water, + const Duration& high_water, bool enabled /* = true */) { + validateKey("addAlarm", key); + + // Create the alarm instance. + AlarmPtr alarm; + try { + alarm.reset(new Alarm(*key, low_water, high_water, enabled)); + } catch (const std::exception& ex) { + isc_throw(BadValue, "AlarmStore::addAlarm failed: " << ex.what()); + } + + return(addAlarm(alarm)); +} + +AlarmPtr +AlarmStore::getAlarm(DurationKeyPtr key) { + validateKey("getAlarm", key); + + MultiThreadingLock lock(*mutex_); + const auto& index = alarms_.get(); + auto alarm_iter = index.find(*key); + return (alarm_iter == index.end() ? AlarmPtr() + : AlarmPtr(new Alarm(**alarm_iter))); +} + +void +AlarmStore::updateAlarm(AlarmPtr& alarm) { + validateKey("updateAlarm", alarm); + + MultiThreadingLock lock(*mutex_); + auto& index = alarms_.get(); + auto alarm_iter = index.find(*alarm); + if (alarm_iter == index.end()) { + isc_throw(InvalidOperation, "AlarmStore::updateAlarm alarm not found: " + << alarm->getLabel()); + } + + // Use replace() which only re-indexes if keys change. + index.replace(alarm_iter, AlarmPtr(new Alarm(*alarm))); +} + +void +AlarmStore::deleteAlarm(DurationKeyPtr key) { + validateKey("deleteAlarm", key); + + MultiThreadingLock lock(*mutex_); + auto& index = alarms_.get(); + auto alarm_iter = index.find(*key); + if (alarm_iter == index.end()) { + // Not there, just return. + return; + } + + // Remove the alarm from the store. + alarms_.erase(alarm_iter); +} + +AlarmCollectionPtr +AlarmStore::getAll() { + MultiThreadingLock lock(*mutex_); + const auto& index = alarms_.get(); + AlarmCollectionPtr collection(new AlarmCollection()); + for (auto alarm_iter = index.begin(); alarm_iter != index.end(); ++alarm_iter) { + collection->push_back(AlarmPtr(new Alarm(**alarm_iter))); + } + + return (collection); +} + +void +AlarmStore::clear() { + MultiThreadingLock lock(*mutex_); + alarms_.clear(); +} + +} // end of namespace perfmon +} // end of namespace isc + diff --git a/src/hooks/dhcp/perfmon/alarm_store.h b/src/hooks/dhcp/perfmon/alarm_store.h new file mode 100644 index 0000000000..35a6a3ef61 --- /dev/null +++ b/src/hooks/dhcp/perfmon/alarm_store.h @@ -0,0 +1,165 @@ +// 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 ALARM_STORE_H +#define ALARM_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 DuplicateAlarm : public Exception { +public: + DuplicateAlarm(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Tag for index by primary key (DurationKey). +struct AlarmPrimaryKeyTag { }; + +/// @brief A multi index container holding pointers to Alarms. +/// +/// 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. + AlarmPtr, + 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 + > + > +> AlarmContainer; + +/// @brief Type for a collection of AlarmPtrs. +typedef std::vector AlarmCollection; + +/// @brief Type for a pointer to a collection of AlarmPtrs. +typedef boost::shared_ptr AlarmCollectionPtr; + +/// @brief Maintains an in-memory store of Alarms +/// +/// Provides essential CRUD functions for managing a collection of +/// Alarms. 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 AlarmStore { +public: + /// @brief Constructor + /// + /// @param family protocol family AF_INET or AF_INET6 + explicit AlarmStore(uint16_t family); + + /// @brief Destructor + ~AlarmStore() = default; + + /// @brief Creates a new Alarm and adds it to the store + /// + /// @param key key value of the Alarm to create. + /// @param low_water threshold below which the average duration must fall to clear the alarm + /// @brief high_water threshold above which the average duration must rise to trigger the alarm. + /// @brief enabled true sets state to CLEAR, otherwise DISABLED, defaults to true. + /// + /// @return pointer to the newly created Alarm. + /// @throw DuplicateAlarm if a duration for the given key already exists in + /// the store. + AlarmPtr addAlarm(DurationKeyPtr key, const Duration& low_water, + const Duration& high_water, bool enabled = true); + + /// @brief Adds an Alarm to the store. + /// + /// @return pointer to a copy of the Alarm added. + AlarmPtr addAlarm(AlarmPtr alarm); + + /// @brief Fetches a duration from the store for a given key. + /// + /// @param key key value of the alarm to fetch. + /// + /// @return Pointer the desired alarm or an empty pointer. + AlarmPtr getAlarm(DurationKeyPtr key); + + /// @brief Updates an alarm in the store. + /// + /// The alarm is assumed to already exist in the store. + /// + /// @param alarm alarm to update. + /// + /// @throw InvalidOperation if the alarm does not exist in the store. + void updateAlarm(AlarmPtr& alarm); + + /// @brief Removes the alarm from the store. + /// + /// If the alarm does not exist in the store, it simply returns. + /// + /// @param key key value of the alarm to delete. + void deleteAlarm(DurationKeyPtr key); + + /// @brief Fetches all of the alarms (in order by target) + /// + /// @return a collection of all alarms in the store. + AlarmCollectionPtr getAll(); + + /// @brief Removes all alarms 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 Convenience method to verify a key is valid for an operation. + /// + /// @param label description of where the check is being made, appears in exception text. + /// @param key key to validate + /// + /// @throw BadValue if the key is either empty or its family does not + /// match the store. + void validateKey(const std::string& label, DurationKeyPtr key) const; + + /// @brief Protocol family AF_INET or AF_INET6. + uint16_t family_; + + /// @brief Container instance. + AlarmContainer alarms_; + + /// @brief The mutex used to protect internal state. + const boost::scoped_ptr mutex_; +}; + +typedef boost::shared_ptr AlarmStorePtr; + +} // end of namespace perfmon +} // end of namespace isc + +#endif diff --git a/src/hooks/dhcp/perfmon/monitored_duration_store.cc b/src/hooks/dhcp/perfmon/monitored_duration_store.cc index 5d51f8be73..7e20708b02 100644 --- a/src/hooks/dhcp/perfmon/monitored_duration_store.cc +++ b/src/hooks/dhcp/perfmon/monitored_duration_store.cc @@ -22,6 +22,11 @@ MonitoredDurationStore::MonitoredDurationStore(uint16_t family, interval_duration_(interval_duration), durations_(), mutex_(new std::mutex) { + if (family != AF_INET && family_ != AF_INET6) { + isc_throw(BadValue, "MonitoredDurationStore - invalid family " + << family_ << ", must be AF_INET or AF_INET6"); + } + if (interval_duration_ <= DurationDataInterval::ZERO_DURATION()) { isc_throw(BadValue, "MonitoredDurationStore - invalid interval_duration " << interval_duration_ << ", must be greater than zero"); @@ -96,7 +101,7 @@ MonitoredDurationStore::updateDuration(MonitoredDurationPtr& duration) { << duration->getLabel()); } - // Use replace() to re-index durations. + // Use replace() which only re-indexes if keys change. index.replace(duration_iter, MonitoredDurationPtr(new MonitoredDuration(*duration))); } diff --git a/src/hooks/dhcp/perfmon/monitored_duration_store.h b/src/hooks/dhcp/perfmon/monitored_duration_store.h index ea9a7768c3..b5d9f9a912 100644 --- a/src/hooks/dhcp/perfmon/monitored_duration_store.h +++ b/src/hooks/dhcp/perfmon/monitored_duration_store.h @@ -157,7 +157,7 @@ private: typedef boost::shared_ptr MonitoredDurationStorePtr; -} // end of namespace ping_check +} // end of namespace perfmon } // end of namespace isc #endif diff --git a/src/hooks/dhcp/perfmon/tests/Makefile.am b/src/hooks/dhcp/perfmon/tests/Makefile.am index 75dc950b67..e74c1d8c33 100644 --- a/src/hooks/dhcp/perfmon/tests/Makefile.am +++ b/src/hooks/dhcp/perfmon/tests/Makefile.am @@ -30,6 +30,7 @@ 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_SOURCES += alarm_store_unittests.cc perfmon_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES) diff --git a/src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc b/src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc new file mode 100644 index 0000000000..7d22486db3 --- /dev/null +++ b/src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc @@ -0,0 +1,430 @@ +// 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 AlarmStore 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 AlarmStore valid construction. +TEST(AlarmStore, validConstructors) { + AlarmStorePtr store; + + // Construct and verify v4 store. + EXPECT_NO_THROW_LOG(store.reset(new AlarmStore(AF_INET))); + ASSERT_TRUE(store); + EXPECT_EQ(store->getFamily(), AF_INET); + + AlarmCollectionPtr alarms; + ASSERT_NO_THROW_LOG(alarms = store->getAll()); + ASSERT_TRUE(alarms); + EXPECT_TRUE(alarms->empty()); + + // Construct and verify v6 store. + EXPECT_NO_THROW_LOG(store.reset(new AlarmStore(AF_INET6))); + ASSERT_TRUE(store); + EXPECT_EQ(store->getFamily(), AF_INET6); + + ASSERT_NO_THROW_LOG(alarms = store->getAll()); + ASSERT_TRUE(alarms); + EXPECT_TRUE(alarms->empty()); +} + +// Verifies AlarmStore invalid construction. +TEST(AlarmStore, invalidConstructors) { + AlarmStorePtr store; + + // Invalid family should throw. + EXPECT_THROW_MSG(AlarmStore(777), + BadValue, + "AlarmStore - invalid family 777, must be AF_INET or AF_INET6"); +} + +/// @brief Text fixture class for @c AlarmStore +/// +/// 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 AlarmStoreTest : public ::testing::Test { +public: + + /// @brief Constructor + AlarmStoreTest() = default; + + /// @brief Destructor + virtual ~AlarmStoreTest() = default; + + /// @brief Creates a protocol-specific DurationKey for a given subnet + /// + /// The message-pair and socket-event pairs are fixed. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + /// @param subnet SubnetID of the duration + DurationKeyPtr makeKey(uint16_t family, SubnetID subnet = 1) { + DurationKeyPtr key; + if (family == AF_INET) { + return (DurationKeyPtr(new DurationKey(AF_INET, DHCPDISCOVER, DHCPOFFER, + "socket_received", "buffer_read", subnet))); + } + + return (DurationKeyPtr(new DurationKey(AF_INET6, DHCPV6_SOLICIT, DHCPV6_REPLY, + "socket_received", "buffer_read", subnet))); + } + + /// @brief Verifies that alarms can be added to the store and fetched + /// by DurationKey. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addAlarmTest(uint16_t family) { + Duration low_water(milliseconds(10)); + Duration high_water(milliseconds(250)); + AlarmStore store(family); + + // Add four alarms with decreaing subnet ids. + std::vector orig_alarms; + for (int subnet = 4; subnet > 0; --subnet) { + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm = store.addAlarm(makeKey(family, subnet), + low_water, high_water)); + ASSERT_TRUE(alarm); + orig_alarms.push_back(alarm); + } + + // Get all should retrieve all four in ascending order. + AlarmCollectionPtr alarms = store.getAll(); + ASSERT_EQ(alarms->size(), orig_alarms.size()); + + int idx = orig_alarms.size() - 1; + for (auto const& d : *alarms) { + EXPECT_EQ(*d, *orig_alarms[idx]) << "failed on pass :" << idx; + --idx; + } + + // Make sure we can fetch them all individually. + for (auto const& alarm : orig_alarms) { + AlarmPtr found; + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + ASSERT_TRUE(found); + EXPECT_EQ(*alarm, *found); + } + + // Verify that clear() discards store contents. + store.clear(); + alarms = store.getAll(); + ASSERT_TRUE(alarms->empty()); + } + /// @brief Verifies that duplicate alarms cannot be added to the store. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void addAlarmDuplicateTest(uint16_t family) { + AlarmStore store(family); + + // Add a duration. + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm = store.addAlarm(makeKey(family), milliseconds(10), + milliseconds(250))); + ASSERT_TRUE(alarm); + + // Attempting to add it again should evoke a duplicate key exception. + ASSERT_THROW(store.addAlarm(alarm), DuplicateAlarm); + } + + /// @brief Verifies that duration key must be valid to add a duration to the store. + /// + /// Tests both v4 and v6. + void addAlarmInvalidTest() { + // Create a v4 store. + AlarmStorePtr store(new AlarmStore(AF_INET)); + + // Attempting to add with an empty key should throw. + ASSERT_THROW_MSG(store->addAlarm(DurationKeyPtr(), + milliseconds(10), milliseconds(250)), + BadValue, + "AlarmStore::addAlarm - key is empty"); + + // Attempting to a v6 key should fail. + ASSERT_THROW_MSG(store->addAlarm(makeKey(AF_INET6), + milliseconds(10), milliseconds(250)), + BadValue, + "AlarmStore::addAlarm" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new AlarmStore(AF_INET6)); + + // Attempting to add a v4 key should fail. + ASSERT_THROW_MSG(store->addAlarm(makeKey(AF_INET), + milliseconds(10), milliseconds(250)), + BadValue, + "AlarmStore::addAlarm" + " - family mismatch, key is v4, store is v6"); + } + + /// @brief Verify that alarms can be deleted from the store. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void deleteAlarmTest(uint16_t family) { + AlarmStore store(family); + + std::vector keys; + for (int subnet = 0; subnet < 3; ++subnet) { + AlarmPtr alarm; + DurationKeyPtr key = makeKey(family, subnet); + ASSERT_NO_THROW_LOG(alarm = store.addAlarm(key, milliseconds(10), milliseconds(250))); + ASSERT_TRUE(alarm); + keys.push_back(key); + } + + // Verify we added three of them. + auto alarms = store.getAll(); + ASSERT_EQ(alarms->size(), 3); + + // Fetch the second duration. + AlarmPtr alarm; + ASSERT_NO_THROW_LOG(alarm = store.getAlarm(keys[1])); + ASSERT_TRUE(alarm); + EXPECT_EQ(*alarm, *(keys[1])); + + // Delete it. + ASSERT_NO_THROW_LOG(store.deleteAlarm(alarm)); + + // Try to fetch it, shouldn't find it. + AlarmPtr alarm2; + ASSERT_NO_THROW_LOG(alarm2 = store.getAlarm(alarm)); + ASSERT_FALSE(alarm2); + + // Deleting it again should do no harm. + ASSERT_NO_THROW_LOG(store.deleteAlarm(alarm)); + + // Verify there are two left. + alarms = store.getAll(); + ASSERT_EQ(alarms->size(), 2); + } + + /// @brief Verify an invalid duration key on delete is detected. + /// + /// Tests both v4 and v6. + void deleteAlarmInvalidTest() { + // Create a v4 store. + AlarmStorePtr store(new AlarmStore(AF_INET)); + + // Attempting to delete an empty key should throw. + DurationKeyPtr key; + ASSERT_THROW_MSG(store->deleteAlarm(key), + BadValue, + "AlarmStore::deleteAlarm - key is empty"); + + // Attempting to delete a v6 key should fail. + ASSERT_THROW_MSG(store->deleteAlarm(makeKey(AF_INET6)), + BadValue, + "AlarmStore::deleteAlarm" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new AlarmStore(AF_INET6)); + + // Attempting to delete a v4 key should fail. + ASSERT_THROW_MSG(store->deleteAlarm(makeKey(AF_INET)), + BadValue, + "AlarmStore::deleteAlarm" + " - family mismatch, key is v4, store is v6"); + } + + + /// @brief Verify that alarms in the store can be updated. + /// + /// @param family protocol family to test, AF_INET or AF_INET6 + void updateAlarmTest(uint16_t family) { + AlarmStore store(family); + + // Add the duration to the store. + AlarmPtr alarm; + ASSERT_NO_THROW(alarm.reset(new Alarm(*makeKey(family), milliseconds(10), + milliseconds(250)))); + ASSERT_NO_THROW(store.addAlarm(alarm)); + + // Fetch it. + AlarmPtr found; + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + ASSERT_TRUE(found); + + // Verify the fetched object is a copy. + ASSERT_NE(found, alarm); + ASSERT_EQ(*found, *alarm); + + // Now change the thresholds and update it. + alarm->setLowWater(milliseconds(125)); + alarm->setHighWater(milliseconds(500)); + ASSERT_NO_THROW(store.updateAlarm(alarm)); + + // Fetch it again. + ASSERT_NO_THROW_LOG(found = store.getAlarm(alarm)); + + // Verify it has the expected thresholds. + EXPECT_EQ(found->getLowWater(), milliseconds(125)); + EXPECT_EQ(found->getHighWater(), milliseconds(500)); + } + + /// @brief Verify an invalid duration key on update is detected. + /// + /// Tests both v4 and v6. + void updateAlarmInvalidTest() { + AlarmPtr alarm; + + // Create a v4 store. + AlarmStorePtr store(new AlarmStore(AF_INET)); + + // Attempting to update an empty key should throw. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + BadValue, + "AlarmStore::updateAlarm - key is empty"); + + // Create a v6 alarm. + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*makeKey(AF_INET6), milliseconds(10), + milliseconds(250)))); + + // Attempting to update v6 alarm to a v4 store should fail. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + BadValue, + "AlarmStore::updateAlarm" + " - family mismatch, key is v6, store is v4"); + + // Create a v6 store. + store.reset(new AlarmStore(AF_INET6)); + + // Updating a non-existent alarm should fail. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + InvalidOperation, + "AlarmStore::updateAlarm alarm not found:" + " SOLICIT-REPLY.socket_received-buffer_read.1"); + + // Create a v4 alarm. + ASSERT_NO_THROW_LOG(alarm.reset(new Alarm(*makeKey(AF_INET), milliseconds(10), + milliseconds(250)))); + + // Attempting to update v4 duration to a v6 store fail. + ASSERT_THROW_MSG(store->updateAlarm(alarm), + BadValue, + "AlarmStore::updateAlarm" + " - family mismatch, key is v4, store is v6"); + } +}; + +TEST_F(AlarmStoreTest, addAlarm) { + addAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarmMultiThreading) { + MultiThreadingTest mt; + addAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarm6) { + addAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarm6MultiThreading) { + MultiThreadingTest mt; + addAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarmDuplicate) { + addAlarmDuplicateTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarmDuplicateMultiThreading) { + MultiThreadingTest mt; + addAlarmDuplicateTest(AF_INET); +} + +TEST_F(AlarmStoreTest, addAlarm6Duplicate) { + addAlarmDuplicateTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarm6DuplicateMultiThreading) { + MultiThreadingTest mt; + addAlarmDuplicateTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, addAlarmInvalid) { + addAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, addAlarmInvalidMultiThreading) { + MultiThreadingTest mt; + addAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, deleteAlarm) { + deleteAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, deleteAlarmMultiThreading) { + MultiThreadingTest mt; + deleteAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, deleteAlarm6) { + deleteAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, deleteAlarm6MultiThreading) { + MultiThreadingTest mt; + deleteAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, deleteAlarmInvalid) { + deleteAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, deleteAlarmInvalidMultiThreading) { + MultiThreadingTest mt; + deleteAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, updateAlarm) { + updateAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, updateAlarmMultiThreading) { + MultiThreadingTest mt; + updateAlarmTest(AF_INET); +} + +TEST_F(AlarmStoreTest, updateAlarm6) { + updateAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, updateAlarm6MultiThreading) { + MultiThreadingTest mt; + updateAlarmTest(AF_INET6); +} + +TEST_F(AlarmStoreTest, updateAlarmInvalid) { + updateAlarmInvalidTest(); +} + +TEST_F(AlarmStoreTest, updateAlarmInvalidMultiThreading) { + MultiThreadingTest mt; + updateAlarmInvalidTest(); +} + + +} // end of anonymous namespace diff --git a/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc b/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc index 6a19c9a7e1..5b94d04d3f 100644 --- a/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc +++ b/src/hooks/dhcp/perfmon/tests/monitored_duration_store_unittests.cc @@ -40,6 +40,10 @@ TEST(MonitoredDurationStore, validConstructors) { TEST(MonitoredDurationStore, invalidConstructors) { MonitoredDurationStorePtr store; + EXPECT_THROW_MSG(MonitoredDurationStore(777, seconds(60)), + BadValue, + "MonitoredDurationStore - invalid family 777, must be AF_INET or AF_INET6"); + EXPECT_THROW_MSG(MonitoredDurationStore(AF_INET, milliseconds(0)), BadValue, "MonitoredDurationStore - invalid interval_duration" @@ -82,7 +86,7 @@ public: "socket_received", "buffer_read", subnet))); } - /// @brief Verifies that durations be added to the store and fetched + /// @brief Verifies that durations can be added to the store and fetched /// by DurationKey. /// /// @param family protocol family to test, AF_INET or AF_INET6 @@ -288,12 +292,12 @@ public: MonitoredDurationPtr mond; // Create a v4 store. - MonitoredDurationStorePtr store(new MonitoredDurationStore(AF_INET6, interval_duration)); + MonitoredDurationStorePtr store(new MonitoredDurationStore(AF_INET, interval_duration)); // Attempting to update an empty key should throw. ASSERT_THROW_MSG(store->updateDuration(mond), BadValue, - "MonitoredDurationStore::deleteDuration - key is empty"); + "MonitoredDurationStore::updateDuration - key is empty"); // Create a v6 duration. ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(*makeKey(AF_INET6), interval_duration))); @@ -309,9 +313,9 @@ public: // Updating a non-existent duration should fail. ASSERT_THROW_MSG(store->updateDuration(mond), - BadValue, + InvalidOperation, "MonitoredDurationStore::updateDuration duration not found:" - " SOLICIT-ADVERTISE.mt_queued-process_started.77"); + " SOLICIT-REPLY.socket_received-buffer_read.1"); // Create a v4 duration. ASSERT_NO_THROW_LOG(mond.reset(new MonitoredDuration(*makeKey(AF_INET), interval_duration))); @@ -414,4 +418,13 @@ TEST_F(MonitoredDurationStoreTest, updateDuration6MultiThreading) { updateDurationTest(AF_INET6); } +TEST_F(MonitoredDurationStoreTest, updateDurationInvalid) { + updateDurationInvalidTest(); +} + +TEST_F(MonitoredDurationStoreTest, updateDurationInvalidMultiThreading) { + MultiThreadingTest mt; + updateDurationInvalidTest(); +} + } // end of anonymous namespace