mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[#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
This commit is contained in:
@@ -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)
|
||||
|
137
src/hooks/dhcp/perfmon/alarm_store.cc
Normal file
137
src/hooks/dhcp/perfmon/alarm_store.cc
Normal file
@@ -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 <config.h>
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <alarm_store.h>
|
||||
#include <util/multi_threading_mgr.h>
|
||||
|
||||
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<AlarmPrimaryKeyTag>();
|
||||
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<AlarmPrimaryKeyTag>();
|
||||
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<AlarmPrimaryKeyTag>();
|
||||
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<AlarmPrimaryKeyTag>();
|
||||
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
|
||||
|
165
src/hooks/dhcp/perfmon/alarm_store.h
Normal file
165
src/hooks/dhcp/perfmon/alarm_store.h
Normal file
@@ -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 <exceptions/exceptions.h>
|
||||
#include <alarm.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 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
|
||||
/// <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.
|
||||
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<AlarmPrimaryKeyTag>,
|
||||
boost::multi_index::identity<DurationKey>
|
||||
>
|
||||
>
|
||||
> AlarmContainer;
|
||||
|
||||
/// @brief Type for a collection of AlarmPtrs.
|
||||
typedef std::vector<AlarmPtr> AlarmCollection;
|
||||
|
||||
/// @brief Type for a pointer to a collection of AlarmPtrs.
|
||||
typedef boost::shared_ptr<AlarmCollection> 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 <TBD>
|
||||
/// 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<std::mutex> mutex_;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<AlarmStore> AlarmStorePtr;
|
||||
|
||||
} // end of namespace perfmon
|
||||
} // end of namespace isc
|
||||
|
||||
#endif
|
@@ -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)));
|
||||
}
|
||||
|
||||
|
@@ -157,7 +157,7 @@ private:
|
||||
|
||||
typedef boost::shared_ptr<MonitoredDurationStore> MonitoredDurationStorePtr;
|
||||
|
||||
} // end of namespace ping_check
|
||||
} // end of namespace perfmon
|
||||
} // end of namespace isc
|
||||
|
||||
#endif
|
||||
|
@@ -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)
|
||||
|
||||
|
430
src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc
Normal file
430
src/hooks/dhcp/perfmon/tests/alarm_store_unittests.cc
Normal file
@@ -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 <config.h>
|
||||
#include <alarm_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 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<AlarmPtr> 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<DurationKeyPtr> 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
|
@@ -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
|
||||
|
Reference in New Issue
Block a user