Commit c6ab3eb8 authored by Marcin Siodelski's avatar Marcin Siodelski

[3534] It is now possible to compare two Configuration objects for equality

parent 9c807997
......@@ -45,6 +45,9 @@ libkea_dhcpsrv_la_SOURCES =
libkea_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
libkea_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
libkea_dhcpsrv_la_SOURCES += configuration.h configuration.cc
libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h
libkea_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h
libkea_dhcpsrv_la_SOURCES += d2_client_cfg.cc d2_client_cfg.h
......@@ -52,16 +55,14 @@ libkea_dhcpsrv_la_SOURCES += d2_client_mgr.cc d2_client_mgr.h
libkea_dhcpsrv_la_SOURCES += daemon.cc daemon.h
libkea_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
libkea_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
libkea_dhcpsrv_la_SOURCES += dhcp_config_parser.h
libkea_dhcpsrv_la_SOURCES += dhcp_parsers.cc dhcp_parsers.h
libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
libkea_dhcpsrv_la_SOURCES += key_from_key.h
libkea_dhcpsrv_la_SOURCES += lease.cc lease.h
libkea_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
libkea_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
libkea_dhcpsrv_la_SOURCES += logging.cc logging.h
libkea_dhcpsrv_la_SOURCES += configuration.h configuration.cc
libkea_dhcpsrv_la_SOURCES += logging_info.cc logging_info.h
libkea_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
if HAVE_MYSQL
......
......@@ -73,5 +73,35 @@ Configuration::sequenceEquals(const Configuration& other) {
return (getSequence() == other.getSequence());
}
bool
Configuration::equals(const Configuration& other) const {
// If number of loggers is different, then configurations aren't equal.
if (logging_info_.size() != other.logging_info_.size()) {
return (false);
}
// Pass through all loggers and try to find the match for each of them
// with the loggers from the other configuration. The order doesn't
// matter so we can't simply compare the vectors.
for (LoggingInfoStorage::const_iterator this_it =
logging_info_.begin(); this_it != logging_info_.end();
++this_it) {
bool match = false;
for (LoggingInfoStorage::const_iterator other_it =
other.logging_info_.begin();
other_it != other.logging_info_.end(); ++other_it) {
if (this_it->equals(*other_it)) {
match = true;
break;
}
}
// No match found for the particular logger so return false.
if (!match) {
return (false);
}
}
// Logging information is equal between objects, so check other values.
return (cfg_iface_ == other.cfg_iface_);
}
}
}
......@@ -16,7 +16,7 @@
#define DHCPSRV_CONFIGURATION_H
#include <dhcpsrv/cfg_iface.h>
#include <log/logger_level.h>
#include <dhcpsrv/logging_info.h>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <stdint.h>
......@@ -26,59 +26,6 @@ namespace dhcp {
class CfgMgr;
/// @brief Defines single logging destination
///
/// This structure is used to keep log4cplus configuration parameters.
struct LoggingDestination {
/// @brief defines logging destination output
///
/// Values accepted are: stdout, stderr, syslog, syslog:name.
/// Any other destination will be considered a file name.
std::string output_;
/// @brief Maximum number of log files in rotation
int maxver_;
/// @brief Maximum log file size
uint64_t maxsize_;
};
/// @brief structure that describes one logging entry
///
/// This is a structure that conveys one logger entry configuration.
/// The structure in JSON form has the following syntax:
/// {
/// "name": "*",
/// "output_options": [
/// {
/// "output": "/path/to/the/logfile.log",
/// "maxver": 8,
/// "maxsize": 204800
/// }
/// ],
/// "severity": "WARN",
/// "debuglevel": 99
/// },
struct LoggingInfo {
/// @brief logging name
std::string name_;
/// @brief describes logging severity
isc::log::Severity severity_;
/// @brief debuglevel (used when severity_ == DEBUG)
///
/// We use range 0(least verbose)..99(most verbose)
int debuglevel_;
/// @brief specific logging destinations
std::vector<LoggingDestination> destinations_;
};
/// @brief storage for logging information in log4cplus format
typedef std::vector<isc::dhcp::LoggingInfo> LoggingInfoStorage;
/// @brief Specifies current DHCP configuration
///
......@@ -186,6 +133,58 @@ public:
cfg_iface_ = cfg_iface;
}
/// @name Methods and operators used to compare configurations.
///
//@{
///
/// @brief Compares two objects for equality.
///
/// It ignores the configuration sequence number when checking for
/// equality of objects.
///
/// @param other An object to be compared with this object.
///
/// @return true if two objects are equal, false otherwise.
bool equals(const Configuration& other) const;
/// @brief Compares two objects for inequality.
///
/// It ignores the configuration sequence number when checking for
/// inequality of objects.
///
/// @param other An object to be compared with this object.
///
/// @return true if two objects are not equal, false otherwise.
bool nequals(const Configuration& other) const {
return (!equals(other));
}
/// @brief Equality operator.
///
/// It ignores the configuration sequence number when checking for
/// equality of objects.
///
/// @param other An object to be compared with this object.
///
/// @return true if two objects are equal, false otherwise.
bool operator==(const Configuration& other) const {
return (equals(other));
}
/// @param other An object to be compared with this object.
///
/// It ignores the configuration sequence number when checking for
/// inequality of objects.
///
/// @param other An object to be compared with this object.
///
/// @return true if two objects are not equal, false otherwise.
bool operator!=(const Configuration& other) const {
return (nequals(other));
}
//@}
private:
/// @brief Sequence number identifying the configuration.
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcpsrv/logging_info.h>
namespace isc {
namespace dhcp {
bool
LoggingDestination::equals(const LoggingDestination& other) const {
return (output_ == other.output_ &&
maxver_ == other.maxver_ &&
maxsize_ == other.maxsize_);
}
bool
LoggingInfo::equals(const LoggingInfo& other) const {
// If number of destinations aren't equal, the objects are not equal.
if (destinations_.size() != other.destinations_.size()) {
return (false);
}
// If there is the same number of logging destinations verify that the
// destinations are equal. The order doesn't matter to we don't expect
// that they are at the same index of the vectors.
for (std::vector<LoggingDestination>::const_iterator
it_this = destinations_.begin();
it_this != destinations_.end();
++it_this) {
bool match = false;
for (std::vector<LoggingDestination>::const_iterator
it_other = other.destinations_.begin();
it_other != other.destinations_.end();
++it_other) {
if (it_this->equals(*it_other)) {
match = true;
break;
}
}
if (!match) {
return (false);
}
}
// Logging destinations are equal. Check the rest of the parameters for
// equality.
return (name_ == other.name_ &&
severity_ == other.severity_ &&
debuglevel_ == other.debuglevel_);
}
} // end of namespace isc::dhcp
} // end of namespace isc
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DHCPSRV_LOGGING_INFO_H
#define DHCPSRV_LOGGING_INFO_H
#include <log/logger_level.h>
#include <stdint.h>
#include <vector>
namespace isc {
namespace dhcp {
/// @brief Defines single logging destination
///
/// This structure is used to keep log4cplus configuration parameters.
struct LoggingDestination {
/// @brief defines logging destination output
///
/// Values accepted are: stdout, stderr, syslog, syslog:name.
/// Any other destination will be considered a file name.
std::string output_;
/// @brief Maximum number of log files in rotation
int maxver_;
/// @brief Maximum log file size
uint64_t maxsize_;
/// @brief Compares two objects for equality.
///
/// @param other Object to be compared with this object.
///
/// @return true if objects are equal, false otherwise.
bool equals(const LoggingDestination& other) const;
/// @brief Default constructor.
LoggingDestination()
: output_("stdout"), maxver_(1), maxsize_(204800) {
}
};
/// @brief structure that describes one logging entry
///
/// This is a structure that conveys one logger entry configuration.
/// The structure in JSON form has the following syntax:
/// {
/// "name": "*",
/// "output_options": [
/// {
/// "output": "/path/to/the/logfile.log",
/// "maxver": 8,
/// "maxsize": 204800
/// }
/// ],
/// "severity": "WARN",
/// "debuglevel": 99
/// },
struct LoggingInfo {
/// @brief logging name
std::string name_;
/// @brief describes logging severity
isc::log::Severity severity_;
/// @brief debuglevel (used when severity_ == DEBUG)
///
/// We use range 0(least verbose)..99(most verbose)
int debuglevel_;
/// @brief specific logging destinations
std::vector<LoggingDestination> destinations_;
/// @brief Default constructor.
LoggingInfo()
: name_("kea"), severity_(isc::log::INFO), debuglevel_(99) {
}
/// @brief Compares two objects for equality.
///
/// @param other An object to be compared with this object.
///
/// @return true if objects are equal, false otherwise.
bool equals(const LoggingInfo& other) const;
/// @brief Compares two objects for equality.
///
/// @param other An object to be compared with this object.
///
/// @return true if objects are equal, false otherwise.
bool operator==(const LoggingInfo& other) const {
return (equals(other));
}
/// @brief Compares two objects for inequality.
///
/// @param other An object to be compared with this object.
///
/// @return true if objects are not equal, false otherwise.
bool operator!=(const LoggingInfo& other) const {
return (!equals(other));
}
};
/// @brief storage for logging information in log4cplus format
typedef std::vector<isc::dhcp::LoggingInfo> LoggingInfoStorage;
}
}
#endif // DHCPSRV_LOGGING_INFO_H
......@@ -69,6 +69,7 @@ libdhcpsrv_unittests_SOURCES += lease_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += logging_unittest.cc
libdhcpsrv_unittests_SOURCES += logging_info_unittest.cc
libdhcpsrv_unittests_SOURCES += generic_lease_mgr_unittest.cc generic_lease_mgr_unittest.h
libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp_parsers_unittest.cc
......
......@@ -14,6 +14,7 @@
#include <config.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/configuration.h>
#include <dhcpsrv/subnet.h>
......@@ -38,7 +39,8 @@ public:
///
/// Creates IPv4 and IPv6 subnets for unit test. The number of subnets
/// is @c TEST_SUBNETS_NUM for IPv4 and IPv6 each.
ConfigurationTest() {
ConfigurationTest()
: iface_mgr_test_config_(true) {
// Remove any subnets dangling from previous unit tests.
clearSubnets();
......@@ -124,6 +126,8 @@ public:
Subnet4Collection test_subnets4_;
/// @brief A collection of IPv6 subnets used by unit tests.
Subnet6Collection test_subnets6_;
/// @brief Fakes interface configuration.
isc::dhcp::test::IfaceMgrTestConfig iface_mgr_test_config_;
};
......@@ -256,4 +260,49 @@ TEST_F(ConfigurationTest, summarySubnets) {
conf_.getConfigSummary(Configuration::CFGSEL_SUBNET));
}
// This test checks that two configurations can be compared for (in)equality.
TEST_F(ConfigurationTest, equality) {
Configuration conf1(32);
Configuration conf2(64);
// Initially, both objects should be equal, even though the configuration
// sequences are not matching.
EXPECT_TRUE(conf1 == conf2);
EXPECT_FALSE(conf1 != conf2);
// Differ by logging information.
LoggingInfo info1;
LoggingInfo info2;
info1.name_ = "foo";
info2.name_ = "bar";
conf1.addLoggingInfo(info1);
conf2.addLoggingInfo(info2);
EXPECT_FALSE(conf1 == conf2);
EXPECT_TRUE(conf1 != conf2);
conf1.addLoggingInfo(info2);
conf2.addLoggingInfo(info1);
EXPECT_TRUE(conf1 == conf2);
EXPECT_FALSE(conf1 != conf2);
// Differ by interface configuration.
CfgIface cfg_iface1;
CfgIface cfg_iface2;
cfg_iface1.use(CfgIface::V4, "eth0");
conf1.setCfgIface(cfg_iface1);
EXPECT_FALSE(conf1 == conf2);
EXPECT_TRUE(conf1 != conf2);
cfg_iface2.use(CfgIface::V4, "eth0");
conf2.setCfgIface(cfg_iface2);
EXPECT_TRUE(conf1 == conf2);
EXPECT_FALSE(conf1 != conf2);
}
} // end of anonymous namespace
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <dhcpsrv/logging_info.h>
#include <gtest/gtest.h>
using namespace isc::dhcp;
namespace {
// Checks if two destinations can be compared for equality.
TEST(LoggingDestintaion, equals) {
LoggingDestination dest1;
LoggingDestination dest2;
EXPECT_TRUE(dest1.equals(dest2));
dest1.output_ = "stderr";
EXPECT_FALSE(dest1.equals(dest2));
dest2.output_ = "stdout";
EXPECT_FALSE(dest1.equals(dest2));
dest2.output_ = "stderr";
EXPECT_TRUE(dest1.equals(dest2));
dest1.maxver_ = 10;
dest2.maxver_ = 5;
EXPECT_FALSE(dest1.equals(dest2));
dest2.maxver_ = 10;
EXPECT_TRUE(dest1.equals(dest2));
dest1.maxsize_ = 64;
dest2.maxsize_ = 32;
EXPECT_FALSE(dest1.equals(dest2));
dest1.maxsize_ = 32;
EXPECT_TRUE(dest1.equals(dest2));
}
// Checks if (in)equality operators work for LoggingInfo.
TEST(LoggingInfo, equality) {
LoggingInfo info1;
LoggingInfo info2;
// Initially, both objects are the same.
EXPECT_TRUE(info1 == info2);
// Differ by name.
info1.name_ = "foo";
info2.name_ = "bar";
EXPECT_FALSE(info1 == info2);
EXPECT_TRUE(info1 != info2);
// Names equal.
info2.name_ = "foo";
EXPECT_TRUE(info1 == info2);
EXPECT_FALSE(info1 != info2);
// Differ by severity.
info1.severity_ = isc::log::DEBUG;
info2.severity_ = isc::log::INFO;
EXPECT_FALSE(info1 == info2);
EXPECT_TRUE(info1 != info2);
// Severities equal.
info2.severity_ = isc::log::DEBUG;
EXPECT_TRUE(info1 == info2);
EXPECT_FALSE(info1 != info2);
// Differ by debug level.
info1.debuglevel_ = 99;
info2.debuglevel_ = 1;
EXPECT_FALSE(info1 == info2);
EXPECT_TRUE(info1 != info2);
// Debug level equal.
info2.debuglevel_ = 99;
EXPECT_TRUE(info1 == info2);
EXPECT_FALSE(info1 != info2);
// Create two different desinations.
LoggingDestination dest1;
LoggingDestination dest2;
dest1.output_ = "foo";
dest2.output_ = "bar";
// Push destinations in some order to info1.
info1.destinations_.push_back(dest1);
info1.destinations_.push_back(dest2);
// Push in reverse order to info2. Order shouldn't matter.
info2.destinations_.push_back(dest2);
info2.destinations_.push_back(dest1);
EXPECT_TRUE(info1 == info2);
EXPECT_FALSE(info1 != info2);
// Change one of the destinations.
LoggingDestination dest3;
dest3.output_ = "foobar";
info2.destinations_[1] = dest3;
// The should now be unequal.
EXPECT_FALSE(info1 == info2);
EXPECT_TRUE(info1 != info2);
}
} // end of anonymous namespace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment