Browse Source

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

Marcin Siodelski 10 years ago
parent
commit
c6ab3eb8b4

+ 4 - 3
src/lib/dhcpsrv/Makefile.am

@@ -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

+ 30 - 0
src/lib/dhcpsrv/configuration.cc

@@ -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_);
+}
+
 }
 }

+ 53 - 54
src/lib/dhcpsrv/configuration.h

@@ -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.

+ 64 - 0
src/lib/dhcpsrv/logging_info.cc

@@ -0,0 +1,64 @@
+// 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

+ 124 - 0
src/lib/dhcpsrv/logging_info.h

@@ -0,0 +1,124 @@
+// 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

+ 1 - 0
src/lib/dhcpsrv/tests/Makefile.am

@@ -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

+ 50 - 1
src/lib/dhcpsrv/tests/configuration_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

+ 124 - 0
src/lib/dhcpsrv/tests/logging_info_unittest.cc

@@ -0,0 +1,124 @@
+// 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