2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 04:57:52 +00:00

[5533a] Move factory to shared pointer, added cache tests

This commit is contained in:
Francis Dupont 2018-02-24 18:11:31 +01:00
parent 2ea993e6d6
commit c6b080197e
7 changed files with 595 additions and 16 deletions

View File

@ -134,11 +134,11 @@ struct MySqlHostDataSourceInit {
}
// Factory class method
static BaseHostDataSource*
static HostDataSourcePtr
factory(const DatabaseConnection::ParameterMap& parameters) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
return (new MySqlHostDataSource(parameters));
return (HostDataSourcePtr(new MySqlHostDataSource(parameters)));
}
};
@ -159,11 +159,11 @@ struct PgSqlHostDataSourceInit {
}
// Factory class method
static BaseHostDataSource*
static HostDataSourcePtr
factory(const DatabaseConnection::ParameterMap& parameters) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
return (new PgSqlHostDataSource(parameters));
return (HostDataSourcePtr(new PgSqlHostDataSource(parameters)));
}
};
@ -184,11 +184,11 @@ struct CqlHostDataSourceInit {
}
// Factory class method
static BaseHostDataSource*
static HostDataSourcePtr
factory(const DatabaseConnection::ParameterMap& parameters) {
LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
.arg(DatabaseConnection::redactedAccessString(parameters));
return (new CqlHostDataSource(parameters));
return (HostDataSourcePtr(new CqlHostDataSource(parameters)));
}
};

View File

@ -77,7 +77,7 @@ public:
///
/// A factory takes a parameter map and returns a pointer to a host
/// data source. In case of failure it must throw and not return NULL.
typedef boost::function<BaseHostDataSource*(const DatabaseConnection::ParameterMap&)> Factory;
typedef boost::function<HostDataSourcePtr (const DatabaseConnection::ParameterMap&)> Factory;
/// @brief Register a host data source factory
///

View File

@ -91,6 +91,7 @@ libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += host_cache_unittest.cc
libdhcpsrv_unittests_SOURCES += host_data_source_factory_unittest.cc
libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += host_unittest.cc

View File

@ -0,0 +1,578 @@
// Copyright (C) 2018 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 <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/cache_host_data_source.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
#include <dhcpsrv/testutils/memory_host_data_source.h>
#include <exceptions/exceptions.h>
#include <gtest/gtest.h>
#include <iostream>
#include <sstream>
using namespace std;
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
namespace {
/// @brief Test dump cache class.
class TestHostCache : public MemHostDataSource, public CacheHostDataSource {
public:
/// Constructor
TestHostCache() : adds_(0), inserts_(0) { }
/// Destructor
virtual ~TestHostCache() { }
/// Override add
bool add(const HostPtr& host) {
isc_throw(NotImplemented,
"add is not implemented: " << host->toText());
}
/// Insert
bool insert(const ConstHostPtr& host, int& overwrite) {
if (overwrite < 0) {
++adds_;
} else {
++inserts_;
}
HostPtr host_copy(new Host(*host));
store_.push_back(host_copy);
return (true);
}
/// Remove
bool remove(const HostPtr& host) {
for (auto h = store_.begin(); h != store_.end(); ++h) {
if (*h == host) {
store_.erase(h);
return (true);
}
}
return (false);
}
/// Flush
void flush(size_t count) {
isc_throw(NotImplemented, "flush is not implemented");
}
/// Size
size_t size() const {
return (store_.size());
}
/// Capacity
size_t capacity() const {
return (0);
}
/// Type
string getType() const {
return ("cache");
}
/// Add counter
size_t adds_;
/// Insert counter
size_t inserts_;
};
/// @brief TestHostCache pointer type
typedef boost::shared_ptr<TestHostCache> TestHostCachePtr;
/// @brief Test data source class.
class TestHostDataSource : public MemHostDataSource {
public:
/// Destructor
virtual ~TestHostDataSource() { }
/// Type
string getType() const {
return ("test");
}
};
/// @brief TestHostDataSource pointer type
typedef boost::shared_ptr<TestHostDataSource> TestHostDataSourcePtr;
/// @brief Test fixture for testing cache feature.
class HostCacheTest : public ::testing::Test {
public:
/// @brief Constructor.
HostCacheTest() {
HostMgr::create();
// Host cache.
hcptr_.reset(new TestHostCache());
auto cacheFactory = [this](const DatabaseConnection::ParameterMap&) {
return (hcptr_);
};
HostDataSourceFactory::registerFactory("cache", cacheFactory);
HostMgr::addSource("type=cache");
// Host data source.
memptr_.reset(new TestHostDataSource());
auto testFactory = [this](const DatabaseConnection::ParameterMap&) {
return (memptr_);
};
HostDataSourceFactory::registerFactory("test", testFactory);
HostMgr::addSource("type=test");
}
/// @brief Destructor.
virtual ~HostCacheTest() {
HostDataSourceFactory::deregisterFactory("test");
HostDataSourceFactory::deregisterFactory("cache");
}
/// @brief Test host cache.
TestHostCachePtr hcptr_;
/// @brief Test host data source.
TestHostDataSourcePtr memptr_;
};
// Check basic cache feature for IPv4.
TEST_F(HostCacheTest, identifier4) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->inserts_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1",
Host::IDENT_HWADDR);
ASSERT_TRUE(host); // Make sure the host is generate properly.
const IOAddress& address = host->getIPv4Reservation();
// Try to add it to the host data source.
bool added = false;
ASSERT_NO_THROW(added = memptr_->add(host));
EXPECT_TRUE(added);
// Try to get it cached.
ConstHostPtr got = HostMgr::instance().get4(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify it was cached.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
// Remove it from test host data source.
EXPECT_TRUE(memptr_->del(host->getIPv4SubnetID(), address));
// It is cached so we can still get it.
got = HostMgr::instance().get4(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Even by address.
got = HostMgr::instance().get4(host->getIPv4SubnetID(), address);
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify cache status.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
}
// Check basic cache feature for IPv6.
TEST_F(HostCacheTest, identifier6) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->inserts_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1",
Host::IDENT_DUID,
false);
ASSERT_TRUE(host); // Make sure the host is generate properly.
// Get the address.
IPv6ResrvRange resrvs = host->getIPv6Reservations();
ASSERT_EQ(1, std::distance(resrvs.first, resrvs.second));
const IOAddress& address = resrvs.first->second.getPrefix();
ASSERT_EQ("2001:db8::1", address.toText());
// Try to add it to the host data source.
bool added = false;
ASSERT_NO_THROW(added = memptr_->add(host));
EXPECT_TRUE(added);
// Try to get it cached.
ConstHostPtr got = HostMgr::instance().get6(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify it was cached.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
// Remove it from test host data source.
EXPECT_TRUE(memptr_->del(host->getIPv6SubnetID(), address));
// It is cached so we can still get it.
got = HostMgr::instance().get6(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Even by address.
got = HostMgr::instance().get6(host->getIPv6SubnetID(), address);
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify cache status.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
}
// Check by address caching for IPv4.
TEST_F(HostCacheTest, address4) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->inserts_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1",
Host::IDENT_HWADDR);
ASSERT_TRUE(host); // Make sure the host is generate properly.
const IOAddress& address = host->getIPv4Reservation();
// Try to add it to the host data source.
bool added = false;
ASSERT_NO_THROW(added = memptr_->add(host));
EXPECT_TRUE(added);
// Try to get it cached.
ConstHostPtr got = HostMgr::instance().get4(host->getIPv4SubnetID(),
address);
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify it was cached.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
// Remove it from test host data source.
EXPECT_TRUE(memptr_->del(host->getIPv4SubnetID(), address));
// It is cached so we can still get it.
got = HostMgr::instance().get4(host->getIPv4SubnetID(), address);
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Even by identifier.
got = HostMgr::instance().get4(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify cache status.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
}
// Check by address caching for IPv6.
TEST_F(HostCacheTest, address6) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->inserts_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1",
Host::IDENT_DUID,
false);
ASSERT_TRUE(host); // Make sure the host is generate properly.
// Get the address.
IPv6ResrvRange resrvs = host->getIPv6Reservations();
ASSERT_EQ(1, std::distance(resrvs.first, resrvs.second));
const IOAddress& address = resrvs.first->second.getPrefix();
ASSERT_EQ("2001:db8::1", address.toText());
// Try to add it to the host data source.
bool added = false;
ASSERT_NO_THROW(added = memptr_->add(host));
EXPECT_TRUE(added);
// Try to get it cached.
ConstHostPtr got = HostMgr::instance().get6(host->getIPv6SubnetID(),
address);
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify it was cached.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
// Remove it from test host data source.
EXPECT_TRUE(memptr_->del(host->getIPv6SubnetID(), address));
// It is cached so we can still get it.
got = HostMgr::instance().get6(host->getIPv6SubnetID(), address);
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Even by identifier.
got = HostMgr::instance().get6(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
HostDataSourceUtils::compareHosts(got, host);
// Verify cache status.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->inserts_);
}
// Check negative cache feature for IPv4.
TEST_F(HostCacheTest, negativeIdentifier4) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->adds_);
ASSERT_TRUE(memptr_);
ASSERT_FALSE(HostMgr::instance().getNegativeCaching());
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1",
Host::IDENT_HWADDR);
ASSERT_TRUE(host); // Make sure the host is generate properly.
// Do not add it to the host data source.
// Try to get it cached.
ConstHostPtr got = HostMgr::instance().get4(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_FALSE(got);
// Again to be sure it was not negatively cached.
got = HostMgr::instance().get4Any(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_FALSE(got);
// Enable negative caching.
HostMgr::instance().setNegativeCaching(true);
ASSERT_TRUE(HostMgr::instance().getNegativeCaching());
// Try it but it will be cached only the second time.
got = HostMgr::instance().get4Any(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_FALSE(got);
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->adds_);
got = HostMgr::instance().get4Any(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
EXPECT_TRUE(got->getNegative());
// Look at inside the negative cached value.
EXPECT_EQ(host->getIPv4SubnetID(), got->getIPv4SubnetID());
EXPECT_EQ(host->getIdentifierType(), got->getIdentifierType());
ASSERT_EQ(host->getIdentifier().size(), got->getIdentifier().size());
EXPECT_EQ(0, memcmp(&host->getIdentifier()[0],
&got->getIdentifier()[0],
host->getIdentifier().size()));
EXPECT_EQ("0.0.0.0", got->getIPv4Reservation().toText());
// get4() (vs get4Any()) does not return negative cached values.
got = HostMgr::instance().get4(host->getIPv4SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
EXPECT_FALSE(got);
// Verify cache status.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->adds_);
EXPECT_EQ(0, hcptr_->inserts_);
}
// Check negative cache feature for IPv6.
TEST_F(HostCacheTest, negativeIdentifier6) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->adds_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1",
Host::IDENT_DUID,
false);
ASSERT_TRUE(host); // Make sure the host is generate properly.
// Do not add it to the host data source.
// Try to get it cached.
ConstHostPtr got = HostMgr::instance().get6(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_FALSE(got);
// Again to be sure it was not negatively cached.
got = HostMgr::instance().get6Any(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_FALSE(got);
// Enable negative caching.
HostMgr::instance().setNegativeCaching(true);
ASSERT_TRUE(HostMgr::instance().getNegativeCaching());
// Try it but it will be cached only the second time.
got = HostMgr::instance().get6Any(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_FALSE(got);
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->adds_);
got = HostMgr::instance().get6Any(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
ASSERT_TRUE(got);
EXPECT_TRUE(got->getNegative());
// Look at inside the negative cached value.
EXPECT_EQ(host->getIPv6SubnetID(), got->getIPv6SubnetID());
EXPECT_EQ(host->getIdentifierType(), got->getIdentifierType());
ASSERT_EQ(host->getIdentifier().size(), got->getIdentifier().size());
EXPECT_EQ(0, memcmp(&host->getIdentifier()[0],
&got->getIdentifier()[0],
host->getIdentifier().size()));
EXPECT_FALSE(got->hasIPv6Reservation());
// get6() (vs get6Any()) does not return negative cached values.
got = HostMgr::instance().get6(host->getIPv6SubnetID(),
host->getIdentifierType(),
&host->getIdentifier()[0],
host->getIdentifier().size());
EXPECT_FALSE(got);
// Verify cache status.
EXPECT_EQ(1, hcptr_->size());
EXPECT_EQ(1, hcptr_->adds_);
EXPECT_EQ(0, hcptr_->inserts_);
}
// Check that negative caching by address is not done for IPv4.
TEST_F(HostCacheTest, negativeAddress4) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->adds_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1",
Host::IDENT_HWADDR);
ASSERT_TRUE(host); // Make sure the host is generate properly.
const IOAddress& address = host->getIPv4Reservation();
// Do not add it to the host data source.
// Enable negative caching.
HostMgr::instance().setNegativeCaching(true);
ASSERT_TRUE(HostMgr::instance().getNegativeCaching());
// Try to get it in negative cache.
ConstHostPtr got = HostMgr::instance().get4(host->getIPv4SubnetID(),
address);
ASSERT_FALSE(got);
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->adds_);
}
// Check that negative caching by address is not done for IPv6.
TEST_F(HostCacheTest, negativeAddress6) {
// Check we have what we need.
ASSERT_TRUE(hcptr_);
EXPECT_TRUE(HostMgr::checkCacheSource());
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->adds_);
ASSERT_TRUE(memptr_);
// Create a host reservation.
HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1",
Host::IDENT_DUID,
false);
ASSERT_TRUE(host); // Make sure the host is generate properly.
// Get the address.
IPv6ResrvRange resrvs = host->getIPv6Reservations();
ASSERT_EQ(1, std::distance(resrvs.first, resrvs.second));
const IOAddress& address = resrvs.first->second.getPrefix();
ASSERT_EQ("2001:db8::1", address.toText());
// Do not add it to the host data source.
// Enable negative caching.
HostMgr::instance().setNegativeCaching(true);
ASSERT_TRUE(HostMgr::instance().getNegativeCaching());
// Try to get it in negative cache.
ConstHostPtr got = HostMgr::instance().get6(host->getIPv6SubnetID(),
address);
ASSERT_FALSE(got);
EXPECT_EQ(0, hcptr_->size());
EXPECT_EQ(0, hcptr_->adds_);
}
}; // end of anonymous namespace

View File

@ -36,9 +36,9 @@ public:
};
// @brief Factory of mem1
BaseHostDataSource*
HostDataSourcePtr
mem1Factory(const DatabaseConnection::ParameterMap&) {
return (new Mem1HostDataSource());
return (HostDataSourcePtr(new Mem1HostDataSource()));
}
// @brief Register mem1Factory
@ -55,9 +55,9 @@ public:
};
// @brief Factory of mem2
BaseHostDataSource*
HostDataSourcePtr
mem2Factory(const DatabaseConnection::ParameterMap&) {
return (new Mem2HostDataSource());
return (HostDataSourcePtr(new Mem2HostDataSource()));
}
// @brief Register mem2Factory
@ -66,8 +66,8 @@ bool registerFactory2() {
}
// @brief Factory function returning 0
BaseHostDataSource* factory0(const DatabaseConnection::ParameterMap&) {
return (0);
HostDataSourcePtr factory0(const DatabaseConnection::ParameterMap&) {
return (HostDataSourcePtr());
}
// @brief Test fixture class

View File

@ -223,9 +223,9 @@ MemHostDataSource::size() const {
return (store_.size());
}
BaseHostDataSource*
HostDataSourcePtr
memFactory(const DatabaseConnection::ParameterMap& /*parameters*/) {
return (new MemHostDataSource());
return (HostDataSourcePtr(new MemHostDataSource()));
}
} // namespace isc::dhcp::test

View File

@ -225,7 +225,7 @@ typedef boost::shared_ptr<MemHostDataSource> MemHostDataSourcePtr;
///
/// @param parameters
/// @return A pointer to a base host data source instance.
BaseHostDataSource*
HostDataSourcePtr
memFactory(const DatabaseConnection::ParameterMap& /*parameters*/);
} // namespace isc::dhcp::test