mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[#3463] Added BindingVariable classes to lease cmds
/src/hooks/dhcp/lease_cmds/Makefile.am added new files /src/hooks/dhcp/lease_cmds/binding_variables.cc /src/hooks/dhcp/lease_cmds/binding_variables.h new files /src/hooks/dhcp/lease_cmds/tests/Makefile.am added new file /src/hooks/dhcp/lease_cmds/tests/binding_variables_unittest.cc new file
This commit is contained in:
@@ -20,6 +20,7 @@ liblease_cmds_la_SOURCES += lease_cmds_exceptions.h
|
||||
liblease_cmds_la_SOURCES += lease_parser.h lease_parser.cc
|
||||
liblease_cmds_la_SOURCES += lease_cmds_log.cc lease_cmds_log.h
|
||||
liblease_cmds_la_SOURCES += lease_cmds_messages.cc lease_cmds_messages.h
|
||||
liblease_cmds_la_SOURCES += binding_variables.h binding_variables.cc
|
||||
liblease_cmds_la_SOURCES += version.cc
|
||||
|
||||
liblease_cmds_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
|
154
src/hooks/dhcp/lease_cmds/binding_variables.cc
Normal file
154
src/hooks/dhcp/lease_cmds/binding_variables.cc
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Kea Hooks Basic
|
||||
// Commercial End User License Agreement v2.0. See COPYING file in the premium/
|
||||
// directory.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <binding_variables.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <cc/data.h>
|
||||
#include <eval/eval_context.h>
|
||||
#include <util/multi_threading_mgr.h>
|
||||
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::data;
|
||||
|
||||
namespace isc {
|
||||
namespace lease_cmds {
|
||||
|
||||
BindingVariable::BindingVariable(const std::string& name,
|
||||
const std::string& expression_str,
|
||||
const Source& source,
|
||||
uint32_t family)
|
||||
: name_(name), expression_str_(expression_str), source_(source),
|
||||
family_(family) {
|
||||
if (name_.empty()) {
|
||||
isc_throw(BadValue, "BindingVariable - name cannot be empty");
|
||||
}
|
||||
|
||||
/// @todo If we add socpes we may wish to allow higher order
|
||||
/// scopes to override lower scopes with empty expressions.
|
||||
if (expression_str_.empty()) {
|
||||
isc_throw(BadValue, "BindingVariable - '" << name_
|
||||
<< "' expression_str cannot be empty");
|
||||
}
|
||||
|
||||
if (family_ != AF_INET && family_ != AF_INET6) {
|
||||
isc_throw(BadValue, "BindingVariable - '" << name_
|
||||
<< "', invalid family: " << family_);
|
||||
}
|
||||
|
||||
try {
|
||||
EvalContext eval_ctx(family_ == AF_INET ? Option::V4 : Option::V6);
|
||||
eval_ctx.parseString(expression_str_, EvalContext::PARSER_STRING);
|
||||
expression_.reset(new Expression(eval_ctx.expression_));
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(BadValue, "BindingVariable - '" << name_ << "', error parsing expression: '"
|
||||
<< expression_str_ << "' : " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
BindingVariable::evaluate(PktPtr packet) const {
|
||||
try {
|
||||
return (evaluateString(*expression_, *packet));
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(BadValue, "BindingVariable - " << name_ << ", error evaluating expression: ["
|
||||
<< expression_str_ << "] : " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
/// @todo Not sure we need CfgElement derivation
|
||||
ElementPtr
|
||||
BindingVariable::toElement() const {
|
||||
ElementPtr map = Element::createMap();
|
||||
map->set("name", Element::create(name_));
|
||||
map->set("expression_str", Element::create(expression_str_));
|
||||
map->set("source", Element::create((source_ == QUERY ? "query" : "response")));
|
||||
// family_ is contextual
|
||||
return (map);
|
||||
}
|
||||
|
||||
BindingVariableCache::BindingVariableCache()
|
||||
: variables_(), mutex_(new std::mutex) {
|
||||
}
|
||||
|
||||
void
|
||||
BindingVariableCache::cacheVariable(BindingVariablePtr variable) {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
variables_.push_back(variable);
|
||||
}
|
||||
|
||||
void
|
||||
BindingVariableCache::clear() {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
// Discard contents.
|
||||
// We use modification time to remember the last time we flushed.
|
||||
variables_.clear();
|
||||
updateModificationTime();
|
||||
}
|
||||
|
||||
size_t
|
||||
BindingVariableCache::size() {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
return (variables_.size());
|
||||
}
|
||||
|
||||
boost::posix_time::ptime
|
||||
BindingVariableCache::getLastFlushTime() {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
return (BaseStampedElement::getModificationTime());
|
||||
}
|
||||
|
||||
/// @brief Tag for the name index.
|
||||
//struct VariableNameTag { };
|
||||
|
||||
/// @brief Tag for the source index.
|
||||
//struct VariableSourceTag { };
|
||||
|
||||
|
||||
BindingVariableListPtr
|
||||
BindingVariableCache::getAll() {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
|
||||
BindingVariableListPtr var_list(new BindingVariableList());
|
||||
const auto& index = variables_.get<VariableSequenceTag>();
|
||||
for (auto const& variable : index) {
|
||||
/// For now we'll return the pointer, w/o making a copy
|
||||
/// of the varaiable itself. We never updates variables
|
||||
/// so we should be OK.
|
||||
var_list->push_back(variable);
|
||||
}
|
||||
|
||||
return (var_list);
|
||||
}
|
||||
|
||||
BindingVariablePtr
|
||||
BindingVariableCache::getByName(const std::string& name) {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
|
||||
const auto& index = variables_.get<VariableNameTag>();
|
||||
auto var_iter = index.find(name);
|
||||
return (var_iter == index.end() ? BindingVariablePtr() : *var_iter);
|
||||
}
|
||||
|
||||
BindingVariableListPtr
|
||||
BindingVariableCache::getBySource(const BindingVariable::Source& source) {
|
||||
util::MultiThreadingLock lock(*mutex_);
|
||||
|
||||
BindingVariableListPtr var_list(new BindingVariableList());
|
||||
const auto& index = variables_.get<VariableSourceTag>();
|
||||
auto lower_limit = index.lower_bound(source);
|
||||
auto upper_limit = index.upper_bound(source);
|
||||
for (auto var_iter = lower_limit; var_iter != upper_limit; ++var_iter) {
|
||||
var_list->push_back(*var_iter);
|
||||
}
|
||||
|
||||
return (var_list);
|
||||
}
|
||||
|
||||
} // end of namespace lease_cmds
|
||||
} // end of namespace isc
|
231
src/hooks/dhcp/lease_cmds/binding_variables.h
Normal file
231
src/hooks/dhcp/lease_cmds/binding_variables.h
Normal file
@@ -0,0 +1,231 @@
|
||||
// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Kea Hooks Basic
|
||||
// Commercial End User License Agreement v2.0. See COPYING file in the premium/
|
||||
// directory.
|
||||
|
||||
#ifndef BINDING_VARIABLES_H
|
||||
#define BINDING_VARIABLES_H
|
||||
|
||||
#include <cc/base_stamped_element.h>
|
||||
#include <cc/cfg_to_element.h>
|
||||
#include <cc/data.h>
|
||||
#include <eval/evaluate.h>
|
||||
#include <eval/token.h>
|
||||
#include <dhcp/pkt.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
|
||||
namespace isc {
|
||||
namespace lease_cmds {
|
||||
|
||||
/// @brief Embodies a named expression, whose output when
|
||||
/// evaluated can be stored in a lease's user-context.
|
||||
class BindingVariable : public isc::data::CfgToElement {
|
||||
public:
|
||||
/// @brief Specifies the packet that the expression should be
|
||||
/// evaluated against.
|
||||
enum Source {
|
||||
QUERY,
|
||||
RESPONSE
|
||||
};
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param name name of the variable, must be unique. Used
|
||||
/// both as the key and as the label for the value in the output.
|
||||
/// @param expression_str Evaluation expression text.
|
||||
/// @param source Source packet the expression should be
|
||||
/// evaluated against, either QUERY or RESPONSE.
|
||||
/// @param family Protocol family of the expression, either
|
||||
/// AF_INET or AF_INET6.
|
||||
///
|
||||
/// During construction the expression string is parsed for the
|
||||
/// protocol family.
|
||||
/// @throw BadValue if name if empty, or expression string fails
|
||||
/// to parse.
|
||||
explicit BindingVariable(const std::string& name,
|
||||
const std::string& expression_str,
|
||||
const Source& source,
|
||||
uint32_t family);
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~BindingVariable() = default;
|
||||
|
||||
/// @brief Evaluate the variable against the given packet.
|
||||
///
|
||||
/// @param packet Pointer to the target packet.
|
||||
/// @return string result of the evaluation.
|
||||
/// @throw BadValue if an evaluation error occurs.
|
||||
std::string evaluate(dhcp::PktPtr packet) const;
|
||||
|
||||
/// @brief Fetches the variable's name.
|
||||
///
|
||||
/// @return string containing the name.
|
||||
std::string getName() const {
|
||||
return (name_);
|
||||
}
|
||||
|
||||
/// @brief Fetches the variable's pre-parsed expression string.
|
||||
///
|
||||
/// @return string containing the expression.
|
||||
std::string getExpressionStr() const {
|
||||
return (expression_str_);
|
||||
}
|
||||
|
||||
/// @brief Fetches the variable's parsed expression.
|
||||
///
|
||||
/// @return pointer to the expression.
|
||||
dhcp::ExpressionPtr getExpression() const {
|
||||
return (expression_);
|
||||
}
|
||||
|
||||
/// @brief Fetches the variable's packet source.
|
||||
///
|
||||
/// @return Source of the packet.
|
||||
Source getSource() const {
|
||||
return (source_);
|
||||
}
|
||||
|
||||
/// @brief Fetches the variable's protocol family.
|
||||
///
|
||||
/// @return Family of the packet i.e AF_INET or AF_INET6.
|
||||
uint32_t getFamily() const {
|
||||
return (family_);
|
||||
}
|
||||
|
||||
/// @todo Not sure we need CfgElement derivation
|
||||
virtual data::ElementPtr toElement() const;
|
||||
|
||||
private:
|
||||
/// @param source Source packet the expression should be
|
||||
/// evaluated against, either QUERY or RESPONSE.
|
||||
/// @param family Protocol family of the expression, either
|
||||
|
||||
/// @brief name of the variable.
|
||||
std::string name_;
|
||||
|
||||
/// @brief Evaluation expression text.
|
||||
std::string expression_str_;
|
||||
|
||||
/// @brief Source packet the expression should be evaluated against.
|
||||
Source source_;
|
||||
|
||||
/// @brief Protocol family AF_INET or AF_INET6.
|
||||
uint32_t family_;
|
||||
|
||||
/// @brief Parsed evaluation expression.
|
||||
dhcp::ExpressionPtr expression_;
|
||||
};
|
||||
|
||||
/// @brief Defines a shared pointer to a BindingVariable.
|
||||
typedef boost::shared_ptr<BindingVariable> BindingVariablePtr;
|
||||
|
||||
/// @brief Defines a list of BindingVariablePtr instances.
|
||||
typedef std::list<BindingVariablePtr> BindingVariableList;
|
||||
|
||||
/// @brief Defines a pointer to a list of BindingVariablePtrs.
|
||||
typedef boost::shared_ptr<BindingVariableList> BindingVariableListPtr;
|
||||
|
||||
/// @brief Tag for the sequence index.
|
||||
struct VariableSequenceTag { };
|
||||
|
||||
/// @brief Tag for the name index.
|
||||
struct VariableNameTag { };
|
||||
|
||||
/// @brief Tag for the source index.
|
||||
struct VariableSourceTag { };
|
||||
|
||||
/// @brief the client class multi-index.
|
||||
typedef boost::multi_index_container<
|
||||
BindingVariablePtr,
|
||||
boost::multi_index::indexed_by<
|
||||
// First index is by sequence. -- Do we need this one?
|
||||
boost::multi_index::sequenced<
|
||||
boost::multi_index::tag<VariableSequenceTag>
|
||||
>,
|
||||
// Second index is by name.
|
||||
boost::multi_index::hashed_unique<
|
||||
boost::multi_index::tag<VariableNameTag>,
|
||||
boost::multi_index::const_mem_fun<BindingVariable,
|
||||
std::string,
|
||||
&BindingVariable::getName>
|
||||
>,
|
||||
|
||||
// Third index is by source.
|
||||
boost::multi_index::ordered_non_unique<
|
||||
boost::multi_index::tag<VariableSourceTag>,
|
||||
boost::multi_index::const_mem_fun<BindingVariable,
|
||||
BindingVariable::Source,
|
||||
&BindingVariable::getSource>
|
||||
>
|
||||
>
|
||||
> BindingVariableContainer;
|
||||
|
||||
/// @brief BindingVariableCache stores binding variables.
|
||||
///
|
||||
/// Wrapper around the variable container that provides
|
||||
/// thread-safe access and time-stamped management. The
|
||||
/// later is available if/when supported scopes beyond
|
||||
/// global are added.
|
||||
class BindingVariableCache : public data::BaseStampedElement {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
BindingVariableCache();
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~BindingVariableCache() = default;
|
||||
|
||||
/// @brief Adds (or replaces) the variable in the cache.
|
||||
///
|
||||
/// @param variable pointer to the variable to store.
|
||||
void cacheVariable(BindingVariablePtr variable);
|
||||
|
||||
/// @brief Delete all the entries in the cache.
|
||||
void clear();
|
||||
|
||||
/// @brief Returns number of entries in the cache.
|
||||
size_t size();
|
||||
|
||||
/// @brief Returns the last time the cache was flushed (or
|
||||
/// the time it was created if it has never been flushed).
|
||||
boost::posix_time::ptime getLastFlushTime();
|
||||
|
||||
/// @brief Fetches all of the binding variables in the order
|
||||
/// they were added to the cache.
|
||||
///
|
||||
/// @return Pointer to a list of the BindingVariables.
|
||||
BindingVariableListPtr getAll();
|
||||
|
||||
/// @brief Fetches a binding variable by name
|
||||
///
|
||||
/// @return A pointer to the variable or an empty pointer
|
||||
/// if no match is found.
|
||||
BindingVariablePtr getByName(const std::string& name);
|
||||
|
||||
/// @brief Fetches all of the binding variables in the order
|
||||
/// they were added to the cache that use a specific source.
|
||||
///
|
||||
/// @return Pointer to a list of the BindingVariables.
|
||||
BindingVariableListPtr getBySource(const BindingVariable::Source& source);
|
||||
|
||||
private:
|
||||
/// @brief Variable storage container.
|
||||
BindingVariableContainer variables_;
|
||||
|
||||
/// @brief The mutex used to protect internal state.
|
||||
const boost::scoped_ptr<std::mutex> mutex_;
|
||||
|
||||
};
|
||||
|
||||
/// @brief Defines a shared pointer to a BindingVariableCache.
|
||||
typedef boost::shared_ptr<BindingVariableCache> BindingVariableCachePtr;
|
||||
|
||||
} // end of namespace lease_cmds
|
||||
} // end of namespace isc
|
||||
#endif
|
@@ -30,6 +30,7 @@ lease_cmds_unittests_SOURCES = run_unittests.cc
|
||||
lease_cmds_unittests_SOURCES += lease_cmds_unittest.h lease_cmds_unittest.cc
|
||||
lease_cmds_unittests_SOURCES += lease_cmds4_unittest.cc
|
||||
lease_cmds_unittests_SOURCES += lease_cmds6_unittest.cc
|
||||
lease_cmds_unittests_SOURCES += binding_variables_unittest.cc
|
||||
|
||||
lease_cmds_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
|
||||
|
||||
@@ -37,7 +38,8 @@ lease_cmds_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
|
||||
lease_cmds_unittests_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
|
||||
lease_cmds_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
|
||||
lease_cmds_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/lease_cmds/liblease_cmds.la
|
||||
lease_cmds_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
|
||||
lease_cmds_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
|
||||
lease_cmds_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
|
||||
lease_cmds_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
|
||||
|
234
src/hooks/dhcp/lease_cmds/tests/binding_variables_unittest.cc
Normal file
234
src/hooks/dhcp/lease_cmds/tests/binding_variables_unittest.cc
Normal file
@@ -0,0 +1,234 @@
|
||||
// Copyright (C) 2025 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 <binding_variables.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <cc/data.h>
|
||||
#include <testutils/gtest_utils.h>
|
||||
#include <testutils/user_context_utils.h>
|
||||
#include <testutils/multi_threading_utils.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::data;
|
||||
using namespace isc::test;
|
||||
|
||||
using namespace isc::lease_cmds;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Test BindingVariable valid construction scenarios.
|
||||
TEST(BindingVariableTest, validConstructor) {
|
||||
BindingVariablePtr bv;
|
||||
|
||||
struct Scenario {
|
||||
uint32_t line_;
|
||||
std::string name_;
|
||||
std::string expression_str_;
|
||||
BindingVariable::Source source_;
|
||||
uint32_t family_;
|
||||
};
|
||||
|
||||
std::string valid_v4_exp = "pkt4.mac";
|
||||
std::string valid_v6_exp = "pkt6.transid";
|
||||
|
||||
std::list<Scenario> scenarios = {
|
||||
{
|
||||
__LINE__, "my-var", valid_v4_exp, BindingVariable::QUERY ,AF_INET
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", valid_v4_exp, BindingVariable::RESPONSE ,AF_INET
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", valid_v6_exp, BindingVariable::QUERY, AF_INET6
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", valid_v6_exp, BindingVariable::RESPONSE, AF_INET6
|
||||
}
|
||||
};
|
||||
|
||||
for (auto const& scenario : scenarios) {
|
||||
ASSERT_NO_THROW_LOG(bv.reset(new BindingVariable(scenario.name_,
|
||||
scenario.expression_str_,
|
||||
scenario.source_,
|
||||
scenario.family_)));
|
||||
ASSERT_TRUE(bv);
|
||||
EXPECT_EQ(bv->getName(), scenario.name_);
|
||||
EXPECT_EQ(bv->getExpressionStr(), scenario.expression_str_);
|
||||
ASSERT_TRUE(bv->getExpression());
|
||||
EXPECT_EQ(bv->getSource(), scenario.source_);
|
||||
EXPECT_EQ(bv->getFamily(), scenario.family_);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Test BindingVariable invalid construction scenarios.
|
||||
TEST(BindingVariableTest, invalidConstructor) {
|
||||
BindingVariablePtr bv;
|
||||
|
||||
struct Scenario {
|
||||
uint32_t line_;
|
||||
std::string name_;
|
||||
std::string expression_str_;
|
||||
uint32_t family_;
|
||||
std::string expected_error_;
|
||||
};
|
||||
|
||||
std::string valid_v4_exp = "pkt4.mac";
|
||||
std::string valid_v6_exp = "pkt6.transid";
|
||||
|
||||
std::list<Scenario> scenarios = {
|
||||
{
|
||||
__LINE__, "", valid_v4_exp, AF_INET,
|
||||
"BindingVariable - name cannot be empty"
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", "", AF_INET,
|
||||
"BindingVariable - 'my-var' expression_str cannot be empty"
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", "bogus + stuff", AF_INET,
|
||||
"BindingVariable - 'my-var', error parsing expression: "
|
||||
"'bogus + stuff' : <string>:1.1: Invalid character: b"
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", valid_v4_exp, 99,
|
||||
"BindingVariable - 'my-var', invalid family: 99"
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", valid_v4_exp, AF_INET6,
|
||||
"BindingVariable - 'my-var', error parsing expression: "
|
||||
"'pkt4.mac' : <string>:1.1-4: pkt4 can only be used in DHCPv4."
|
||||
},
|
||||
{
|
||||
__LINE__, "my-var", valid_v6_exp, AF_INET,
|
||||
"BindingVariable - 'my-var', error parsing expression: "
|
||||
"'pkt6.transid' : <string>:1.1-4: pkt6 can only be used in DHCPv6."
|
||||
}
|
||||
};
|
||||
|
||||
for (auto const& scenario : scenarios) {
|
||||
ASSERT_THROW_MSG(bv.reset(new BindingVariable(scenario.name_,
|
||||
scenario.expression_str_,
|
||||
BindingVariable::QUERY,
|
||||
scenario.family_)),
|
||||
BadValue, scenario.expected_error_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BindingVariableCacheTest, basics) {
|
||||
|
||||
auto ref_time = boost::posix_time::second_clock::local_time();
|
||||
|
||||
// Create a new cache.
|
||||
BindingVariableCachePtr cache(new BindingVariableCache());
|
||||
|
||||
// Verify last flush time has been set to approximately now.
|
||||
EXPECT_GE(cache->getLastFlushTime(), ref_time);
|
||||
ref_time = cache->getLastFlushTime();
|
||||
|
||||
// Ensure getters return empty lists or pointers without harm.
|
||||
BindingVariableListPtr var_list;
|
||||
ASSERT_NO_THROW_LOG(var_list = cache->getAll());
|
||||
ASSERT_TRUE(var_list);
|
||||
EXPECT_EQ(var_list->size(), 0);
|
||||
|
||||
BindingVariablePtr var;
|
||||
ASSERT_NO_THROW_LOG(var = cache->getByName("foo"));
|
||||
ASSERT_FALSE(var);
|
||||
|
||||
ASSERT_NO_THROW_LOG(var_list = cache->getBySource(BindingVariable::QUERY));
|
||||
ASSERT_TRUE(var_list);
|
||||
EXPECT_EQ(var_list->size(), 0);
|
||||
|
||||
ASSERT_NO_THROW_LOG(var_list = cache->getBySource(BindingVariable::RESPONSE));
|
||||
ASSERT_TRUE(var_list);
|
||||
EXPECT_EQ(var_list->size(), 0);
|
||||
|
||||
// Add four variables.
|
||||
std::string valid_v6_exp = "pkt6.transid";
|
||||
BindingVariableList ref_list;
|
||||
ref_list.push_back(BindingVariablePtr(new BindingVariable("one", valid_v6_exp,
|
||||
BindingVariable::QUERY,
|
||||
AF_INET6)));
|
||||
|
||||
ref_list.push_back(BindingVariablePtr(new BindingVariable("two", valid_v6_exp,
|
||||
BindingVariable::RESPONSE,
|
||||
AF_INET6)));
|
||||
|
||||
ref_list.push_back(BindingVariablePtr(new BindingVariable("three", valid_v6_exp,
|
||||
BindingVariable::RESPONSE,
|
||||
AF_INET6)));
|
||||
|
||||
ref_list.push_back(BindingVariablePtr(new BindingVariable("four", valid_v6_exp,
|
||||
BindingVariable::QUERY,
|
||||
AF_INET6)));
|
||||
|
||||
for (auto const& ref_iter : ref_list) {
|
||||
ASSERT_NO_THROW_LOG(cache->cacheVariable(ref_iter));
|
||||
}
|
||||
|
||||
// Make sure getAll() returns all four in order added.
|
||||
ASSERT_NO_THROW_LOG(var_list = cache->getAll());
|
||||
ASSERT_TRUE(var_list);
|
||||
EXPECT_EQ(var_list->size(), 4);
|
||||
|
||||
auto var_iter = var_list->begin();
|
||||
for (auto const& ref_iter : ref_list) {
|
||||
EXPECT_EQ((*var_iter)->getName(), ref_iter->getName());
|
||||
EXPECT_EQ((*var_iter)->getSource(), ref_iter->getSource());
|
||||
++var_iter;
|
||||
}
|
||||
|
||||
// Make sure getByName() can return each one.
|
||||
for (auto const& ref_iter : ref_list) {
|
||||
ASSERT_NO_THROW_LOG(var = cache->getByName(ref_iter->getName()));
|
||||
ASSERT_TRUE(var);
|
||||
EXPECT_EQ(var->getName(), ref_iter->getName());
|
||||
}
|
||||
|
||||
// Make sure getBySource() works for QUERY.
|
||||
ASSERT_NO_THROW_LOG(var_list = cache->getBySource(BindingVariable::QUERY));
|
||||
ASSERT_TRUE(var_list);
|
||||
ASSERT_EQ(var_list->size(), 2);
|
||||
|
||||
var_iter = var_list->begin();
|
||||
for (auto const& ref_iter : ref_list) {
|
||||
if (ref_iter->getSource() == BindingVariable::QUERY) {
|
||||
EXPECT_EQ((*var_iter)->getName(), ref_iter->getName());
|
||||
++var_iter;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure getBySource() works for RESPONSE.
|
||||
ASSERT_NO_THROW_LOG(var_list = cache->getBySource(BindingVariable::RESPONSE));
|
||||
ASSERT_TRUE(var_list);
|
||||
ASSERT_EQ(var_list->size(), 2);
|
||||
|
||||
var_iter = var_list->begin();
|
||||
for (auto const& ref_iter : ref_list) {
|
||||
if (ref_iter->getSource() == BindingVariable::RESPONSE) {
|
||||
EXPECT_EQ((*var_iter)->getName(), ref_iter->getName());
|
||||
++var_iter;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure last flush time hasn't been touched.
|
||||
EXPECT_EQ(cache->getLastFlushTime(), ref_time);
|
||||
|
||||
// Sleep 1s so we can check flush time gets updated.
|
||||
usleep(1000000);
|
||||
ASSERT_NO_THROW_LOG(cache->clear());
|
||||
EXPECT_EQ(cache->size(), 0);
|
||||
|
||||
EXPECT_GT(cache->getLastFlushTime(), ref_time);
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
Reference in New Issue
Block a user