]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#32,!23] Added ControlConfigInfo to lib/config
authorThomas Markwalder <tmark@isc.org>
Wed, 26 Sep 2018 14:17:04 +0000 (10:17 -0400)
committerThomas Markwalder <tmark@isc.org>
Fri, 5 Oct 2018 13:05:44 +0000 (09:05 -0400)
src/lib/config/config_ctl_info.*
    New files, implementing ConfigDbInfo and ConfigControlInfo
    classes use for housing configuration backend and control
    information

src/lib/config/Makefile.am
    Added config_ctl_info.h/cc
    Added libkea-database.la

src/lib/config/tests/config_ctl_info_unitests.cc
    New file which unit tests new classes

src/lib/database/database_connection.*
    DatabaseConnection::toElement(const ParameterMap& params) - new
    static function which turns a parameter map into Elements

    DatabaseConnection::toElementDbAccessString(const std::string& dbaccess)
    - new static function which turns an access string into Elements

src/lib/database/dbaccess_parser.*
    Replaced StringPairMap with DatabaseConnection::ParameterMap

src/lib/database/tests/database_connection_unittest.cc
    TEST(DatabaseConnection, toElementDbAccessStringValid)
    TEST(DatabaseConnection, toElementDbAccessStringInvalid)
    TEST(DatabaseConnection, toElementDbAccessStringEmpty) - new tests

src/lib/dhcpsrv/cfg_db_access.*
    CfgDbAccess::toElementDbAccessString() - moved to
    lib/database/database_connection.cc so it can be shared

13 files changed:
src/lib/config/Makefile.am
src/lib/config/config_ctl_info.cc [new file with mode: 0644]
src/lib/config/config_ctl_info.h [new file with mode: 0644]
src/lib/config/tests/Makefile.am
src/lib/config/tests/config_ctl_info_unittests.cc [new file with mode: 0644]
src/lib/database/database_connection.cc
src/lib/database/database_connection.h
src/lib/database/dbaccess_parser.cc
src/lib/database/dbaccess_parser.h
src/lib/database/tests/database_connection_unittest.cc
src/lib/database/tests/dbaccess_parser_unittest.cc
src/lib/dhcpsrv/cfg_db_access.cc
src/lib/dhcpsrv/cfg_db_access.h

index 8b2102dfd208fe535b15fd925e6517d27482938a..1f2203033e4835c9fae44e273f1ed848f0210533 100644 (file)
@@ -19,11 +19,13 @@ libkea_cfgclient_la_SOURCES  = cmds_impl.h
 libkea_cfgclient_la_SOURCES += base_command_mgr.cc base_command_mgr.h
 libkea_cfgclient_la_SOURCES += client_connection.cc client_connection.h
 libkea_cfgclient_la_SOURCES += command_mgr.cc command_mgr.h
+libkea_cfgclient_la_SOURCES += config_ctl_info.h config_ctl_info.cc
 libkea_cfgclient_la_SOURCES += config_log.h config_log.cc
 libkea_cfgclient_la_SOURCES += hooked_command_mgr.cc hooked_command_mgr.h
 libkea_cfgclient_la_SOURCES += timeouts.h
 
 libkea_cfgclient_la_LIBADD = $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la
 libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
 libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
 libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
diff --git a/src/lib/config/config_ctl_info.cc b/src/lib/config/config_ctl_info.cc
new file mode 100644 (file)
index 0000000..1907731
--- /dev/null
@@ -0,0 +1,98 @@
+// 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 <config/config_ctl_info.h>
+
+using namespace isc::data;
+
+namespace isc {
+namespace config {
+
+void
+ConfigDbInfo::setAccessString(const std::string access_str) {
+    access_str_ = access_str;
+    access_params_.clear();
+    access_params_ = db::DatabaseConnection::parse(access_str_);
+}
+
+bool
+ConfigDbInfo::equals(const ConfigDbInfo& other) const {
+    return (access_params_ == other.access_params_);
+}
+
+isc::data::ElementPtr
+ConfigDbInfo::toElement() const {
+    return (isc::db::DatabaseConnection::toElementDbAccessString(access_str_));
+}
+
+bool
+ConfigDbInfo::getParameterValue(const std::string& name, std::string& value) const {
+    auto param = access_params_.find(name);
+    if (param == access_params_.end()) {
+        return(false);
+    }
+
+    value = param->second;
+    return(true);
+}
+
+void
+ConfigControlInfo::addConfigDatabase(const std::string& access_str) {
+    ConfigDbInfo new_db;
+    new_db.setAccessString(access_str);
+
+    for (auto db : db_infos_) {
+        if (new_db == db) {
+            // we have a duplicate!
+            isc_throw(BadValue, "database with access parameters: "
+                      << access_str << " already exists");
+        }
+    }
+
+    db_infos_.push_back(new_db);
+}
+
+const ConfigDbInfo&
+ConfigControlInfo::findConfigDb(const std::string param_name,
+                                const std::string param_value) {
+    for (ConfigDbInfoList::iterator db = db_infos_.begin();
+         db != db_infos_.end(); ++db) {
+        std::string db_value;
+        if (db->getParameterValue(param_name, db_value) &&
+            (param_value == db_value)) {
+                return (*db);
+            }
+    }
+
+    return (EMPTY_DB());
+}
+
+const ConfigDbInfo&
+ConfigControlInfo::EMPTY_DB() {
+    static ConfigDbInfo empty;
+    return (empty);
+}
+
+void
+ConfigControlInfo::clear() {
+    db_infos_.clear();
+}
+
+ElementPtr
+ConfigControlInfo::toElement() const {
+    ElementPtr result = Element::createMap();
+    ElementPtr db_list = Element::createList();
+    for (auto db_info : db_infos_) {
+        db_list->add(db_info.toElement());
+    }
+
+    result->set("config-databases", db_list);
+    return(result);
+}
+
+} // end of namespace isc::config
+} // end of namespace isc
diff --git a/src/lib/config/config_ctl_info.h b/src/lib/config/config_ctl_info.h
new file mode 100644 (file)
index 0000000..7c940bc
--- /dev/null
@@ -0,0 +1,181 @@
+// 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/.
+
+#ifndef CONFIG_CONFIG_CTL_H
+#define CONFIG_CONFIG_CTL_H
+
+#include <cc/cfg_to_element.h>
+#include <database/database_connection.h>
+
+#include <boost/shared_ptr.hpp>
+#include <stdint.h>
+#include <vector>
+
+namespace isc {
+namespace config {
+
+/// @brief Provides configuration information used during a server's
+/// configuration process
+///
+class ConfigDbInfo : public isc::data::CfgToElement {
+public:
+    /// @brief Constructor
+    ConfigDbInfo() {};
+
+    /// @brief Set the access string
+    ///
+    /// Sest the db's access string to the given value and then parses it
+    /// into name-value pairs and storing them internally as a
+    /// DatabaseConnection::ParameterMap.  It discards the existing content
+    /// of the map first.  It does not validate the parameter names of values,
+    /// ensuring the validity of the string content is placed upon the caller.
+    ///
+    /// @param access_str string of name=value pairs seperated by spaces
+    void setAccessString(const std::string access_str);
+
+    /// @brief Retrieves the database access string.
+    ///
+    /// @return database access string
+    std::string getAccessString() const {
+        return (access_str_);
+    }
+
+    /// @brief Retrieve the map of parameter values.
+    ///
+    /// @return Constant reference to the database's parameter map.
+    const db::DatabaseConnection::ParameterMap& getParameters() const {
+        return (access_params_);
+    }
+
+    /// @brief Fetch the value of a given parmeter
+    ///
+    /// @param name name of the parameter value to fetch
+    /// @param[out] value string which will contain the value of the
+    /// parameter (if found).
+    ///
+    /// @return Boolean true if the parameter named is found in the map,
+    /// false otherwise.
+    bool getParameterValue(const std::string& name,
+                           std::string& value) const;
+
+    /// @brief Unparse a configuration object
+    ///
+    /// @return a pointer to unparsed configuration
+    virtual isc::data::ElementPtr toElement() 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 equals(const ConfigDbInfo& 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 ConfigDbInfo& 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 ConfigDbInfo& other) const {
+        return (!equals(other));
+    }
+
+private:
+    /// @brief Access string of parameters used to acces this database
+    std::string access_str_;
+
+    /// @brief Map of the access parameters and their values
+    db::DatabaseConnection::ParameterMap access_params_;
+};
+
+typedef std::vector<ConfigDbInfo> ConfigDbInfoList;
+
+/// @brief Embodies configuration information used during a server's
+/// configuration process
+///
+/// This is class conveys the configuration control information
+/// described by the following JSON text:
+///
+/// "ConfigCtl" :
+/// {
+///     "config-databases":
+///     [
+///     {
+///         # first config db
+///         # common database access parameters
+///         "type": <"mysql"|"postgresql"|"cql">,
+///         "name": <"db name">,
+///         "host": <"db host name">,
+///             :
+///     },
+///     {
+///         # next config db
+///     }
+///     ]
+/// }
+
+class ConfigControlInfo : public isc::data::CfgToElement {
+public:
+
+    /// @brief Constructor.
+    ConfigControlInfo() {};
+
+    /// @brief Sets host database access string.
+    ///
+    /// @param host_db_access New host database access string.
+    /// @param front Add at front if true, at back if false (default).
+    /// @throw BadValue if an entry exists that matches the parameters
+    /// in the given access string, or if the access string is invalid.
+    void addConfigDatabase(const std::string& access_str);
+
+    /// @brief Retrieves the list of databases
+    ///
+    /// @return a reference to a const list of databases
+    const ConfigDbInfoList& getConfigDatabases() const {
+        return (db_infos_);
+    }
+
+    /// @brief Retrieves the datbase with the given access parameter value
+    ///
+    /// @return A reference to the matching database or the not-found value
+    /// available via @c EMPTY_DB()
+    const ConfigDbInfo& findConfigDb(const std::string param_name,
+                                     const std::string param_value);
+
+    /// @brief Empties the contents of the class, including the database list
+    void clear();
+
+    /// @brief Unparse a configuration object
+    ///
+    /// @return a pointer to unparsed configuration
+    virtual isc::data::ElementPtr toElement() const;
+
+    /// @brief Fetches the not-found value returned by database list searches
+    ///
+    /// @return a reference to the empty ConfigDBInfo
+    static const ConfigDbInfo& EMPTY_DB();
+
+private:
+
+    /// @brief List of configuration databases
+    ConfigDbInfoList db_infos_;
+};
+
+/// @brief Defines a pointer to a ConfigControlInfo
+typedef boost::shared_ptr<ConfigControlInfo> ConfigControlInfoPtr;
+
+} // namespace config
+} // end namespace isc
+
+#endif // CONFIG_CONFIG_CTL_H
index 69e28545789d73f2e6a4a8af5a700695793eecc9..77330bf0dd10bc58cba7e76007760fff74644e84 100644 (file)
@@ -22,6 +22,7 @@ TESTS += run_unittests
 run_unittests_SOURCES = client_connection_unittests.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_SOURCES += command_mgr_unittests.cc
+run_unittests_SOURCES += config_ctl_info_unittests.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/config/tests/config_ctl_info_unittests.cc b/src/lib/config/tests/config_ctl_info_unittests.cc
new file mode 100644 (file)
index 0000000..f2726f6
--- /dev/null
@@ -0,0 +1,143 @@
+// 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 <config/config_ctl_info.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+#include <iostream>
+
+using namespace isc::config;
+using namespace isc::data;
+
+// Verifies initializing via an access string and unparsing into elements
+// We just test basic unparsing, as more rigorous testing is done in
+// libkea-db testing which ConfibDBInfo uses.
+TEST(ConfigDbInfo, basicOperation) {
+    ConfigDbInfo db;
+    std::string access = "type=mysql user=tom password=terrific";
+    std::string access_json = "{\n"
+        " \"type\":\"mysql\", \n"
+        " \"user\":\"tom\", \n"
+        " \"password\":\"terrific\" \n"
+        "} \n";
+
+    // Convert the above configuration into Elements for comparison.
+    ElementPtr exp_elems;
+    ASSERT_NO_THROW(exp_elems = Element::fromJSON(access_json))
+        << "test is broken";
+
+    // Initialize the db from an the access string
+    db.setAccessString(access);
+    EXPECT_EQ(access, db.getAccessString());
+
+    // Convert the db into Elements and make sure they are as expected.
+    ElementPtr db_elems;
+    ASSERT_NO_THROW(db_elems = db.toElement());
+    EXPECT_TRUE(db_elems->equals(*exp_elems));
+}
+
+// Verify that db parameter values may be retrieved.
+TEST(ConfigDbInfo, getParameterValue) {
+    ConfigDbInfo db1;
+    std::string access1 = "type=mysql name=keatest port=33 readonly=false";
+    db1.setAccessString(access1);
+
+    std::string value;
+    bool found = false;
+
+    // Should find "type"
+    ASSERT_NO_THROW(found = db1.getParameterValue("type", value));
+    EXPECT_TRUE(found);
+    EXPECT_EQ("mysql", value);
+
+    // Should find "name"
+    ASSERT_NO_THROW(found = db1.getParameterValue("name", value));
+    EXPECT_TRUE(found);
+    EXPECT_EQ("keatest", value);
+
+    // Should find "port"
+    ASSERT_NO_THROW(found = db1.getParameterValue("port", value));
+    EXPECT_TRUE(found);
+    EXPECT_EQ("33", value);
+
+    // Should find "readonly"
+    ASSERT_NO_THROW(found = db1.getParameterValue("readonly", value));
+    EXPECT_TRUE(found);
+    EXPECT_EQ("false", value);
+
+    // Should not find "bogus"
+    ASSERT_NO_THROW(found = db1.getParameterValue("bogus", value));
+    EXPECT_FALSE(found);
+}
+
+// Verify that db equality operators work correctly.
+TEST(ConfigDbInfo, equalityOperators) {
+    ConfigDbInfo db1;
+    std::string access1 = "type=mysql user=tom password=terrific";
+    ASSERT_NO_THROW(db1.setAccessString(access1));
+
+    ConfigDbInfo db2;
+    std::string access2 = "type=postgresql user=tom password=terrific";
+    ASSERT_NO_THROW(db2.setAccessString(access2));
+
+    // Verify that the two unequal dbs are in fact not equal.
+    EXPECT_FALSE(db1.equals(db2));
+    EXPECT_FALSE(db1 == db2);
+    EXPECT_TRUE(db1 != db2);
+
+    // Verify that the two equal dbs are in fact equal.
+    db2.setAccessString(access1);
+    EXPECT_TRUE(db1.equals(db2));
+    EXPECT_TRUE(db1 == db2);
+    EXPECT_FALSE(db1 != db2);
+}
+
+// Verifies the basic operations of ConfigControlInfo
+TEST(ConfigControlInfo, basicOperation) {
+
+    ConfigControlInfo ctl;
+    // We should have no dbs in the list.
+    EXPECT_EQ(0, ctl.getConfigDatabases().size());
+
+    // We should be able to add two distinct, valid dbs
+    std::string access_str1 = "type=mysql host=machine1.org";
+    ASSERT_NO_THROW(ctl.addConfigDatabase(access_str1));
+
+    std::string access_str2 = "type=postgresql host=machine2.org";
+    ASSERT_NO_THROW(ctl.addConfigDatabase(access_str2));
+
+    // We should fail on a duplicate db.
+    ASSERT_THROW(ctl.addConfigDatabase(access_str1), isc::BadValue);
+
+    // We should have two dbs in the list.
+    const ConfigDbInfoList& db_list = ctl.getConfigDatabases();
+    EXPECT_EQ(2, db_list.size());
+
+    // Verify the dbs in the list are as we expect them to be.
+    EXPECT_EQ (access_str1, db_list[0].getAccessString());
+    EXPECT_EQ (access_str2, db_list[1].getAccessString());
+
+    // Verify we can find dbs based on a property values.
+    const ConfigDbInfo& db_info = ctl.findConfigDb("type", "mysql");
+    EXPECT_FALSE(db_info == ConfigControlInfo::EMPTY_DB());
+    EXPECT_EQ (access_str1, db_info.getAccessString());
+
+    const ConfigDbInfo& db_info2 = ctl.findConfigDb("host", "machine2.org");
+    EXPECT_FALSE(db_info2 == ConfigControlInfo::EMPTY_DB());
+    EXPECT_EQ (access_str2, db_info2.getAccessString());
+
+    // Verify not finding a db reutrns EMPTY_DB().
+    const ConfigDbInfo& db_info3 = ctl.findConfigDb("type", "bogus");
+    EXPECT_TRUE(db_info3 == ConfigControlInfo::EMPTY_DB());
+
+    // Verify we can clear the list of dbs.
+    ctl.clear();
+    EXPECT_EQ(0, ctl.getConfigDatabases().size());
+}
index 2f736e2e42c6ed96cb3019a3c649b455daf75283..e58ebb47522dbeda61efa07052b3c3bb3c069d2c 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <config.h>
 
+#include <cc/cfg_to_element.h>
 #include <database/database_connection.h>
 #include <database/db_exceptions.h>
 #include <database/db_log.h>
@@ -151,6 +152,58 @@ DatabaseConnection::invokeDbLostCallback() const {
     return (false);
 }
 
+isc::data::ElementPtr
+DatabaseConnection::toElement(const ParameterMap& params) {
+    isc::data::ElementPtr result = isc::data::Element::createMap();
+
+    for (auto param: params) {
+        std::string keyword = param.first;
+        std::string value = param.second;
+
+        if ((keyword == "lfc-interval") ||
+            (keyword == "connect-timeout") ||
+            (keyword == "port")) {
+            // integer parameters
+            int64_t int_value;
+            try {
+                int_value = boost::lexical_cast<int64_t>(value);
+                result->set(keyword, isc::data::Element::create(int_value));
+            } catch (...) {
+                isc_throw(ToElementError, "invalid DB access "
+                          << "integer parameter: " << keyword << "=" << value);
+            }
+        } else if ((keyword == "persist") ||
+                   (keyword == "readonly")) {
+            if (value == "true") {
+                result->set(keyword, isc::data::Element::create(true));
+            } else if (value == "false") {
+                result->set(keyword, isc::data::Element::create(false));
+            } else {
+                isc_throw(ToElementError, "invalid DB access "
+                          << "boolean parameter: " << keyword << "=" << value);
+            }
+        } else if ((keyword == "type") ||
+                   (keyword == "user") ||
+                   (keyword == "password") ||
+                   (keyword == "host") ||
+                   (keyword == "name") ||
+                   (keyword == "contact-points") ||
+                   (keyword == "keyspace")) {
+            result->set(keyword, isc::data::Element::create(value));
+        } else {
+            isc_throw(ToElementError, "unknown DB access parameter: "
+                      << keyword << "=" << value);
+        }
+    }
+
+    return (result);
+}
+
+isc::data::ElementPtr
+DatabaseConnection::toElementDbAccessString(const std::string& dbaccess) {
+    ParameterMap params = parse(dbaccess);
+    return (toElement(params));
+}
 
 DatabaseConnection::DbLostCallback
 DatabaseConnection::db_lost_callback = 0;
index 515e20c5b561d0ab6946c69a6fc5b27ce84de9ae..5770a143665c5069a1022e1053470e02aca4c185 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef DATABASE_CONNECTION_H
 #define DATABASE_CONNECTION_H
 
+#include <cc/data.h>
 #include <boost/noncopyable.hpp>
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
@@ -96,7 +97,7 @@ public:
         return (retries_left_ ? --retries_left_ : false);
     }
 
-    /// @brief Returns the maximum number for retries allowed 
+    /// @brief Returns the maximum number for retries allowed
     unsigned int maxRetries() {
         return (max_retries_);
     }
@@ -215,6 +216,18 @@ public:
     /// callback.
     bool invokeDbLostCallback() const;
 
+    /// @brief Unparse a parameter map
+    ///
+    /// @param params the parameter map to unparse
+    /// @return a pointer to configuration
+    static isc::data::ElementPtr toElement(const ParameterMap& params);
+
+    /// @brief Unparse an access string
+    ///
+    /// @param dbaccess the database access string
+    /// @return a pointer to configuration
+    static isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
+
     /// @brief Optional call back function to invoke if a successfully
     /// open connection subsequently fails
     static DbLostCallback db_lost_callback;
index 79f5bb51964e0eb575dbd7677e086f06bc9a0cab..9afb625cd961e7e2a167a3c72f24a6921d7b6787 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <config.h>
 
+#include <database/database_connection.h>
 #include <database/db_exceptions.h>
 #include <database/dbaccess_parser.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
@@ -45,7 +46,7 @@ DbAccessParser::parse(std::string& access_string,
     // a flex/bison parser.
 
     // 1. Take a copy of the stored keyword/value pairs.
-    std::map<string, string> values_copy = values_;
+    DatabaseConnection::ParameterMap values_copy = values_;
 
     int64_t lfc_interval = 0;
     int64_t timeout = 0;
@@ -112,7 +113,7 @@ DbAccessParser::parse(std::string& access_string,
     // 3. Perform validation checks on the updated set of keyword/values.
     //
     // a. Check if the "type" keyword exists and thrown an exception if not.
-    StringPairMap::const_iterator type_ptr = values_copy.find("type");
+    auto type_ptr = values_copy.find("type");
     if (type_ptr == values_copy.end()) {
         isc_throw(DbConfigError,
                   "database access parameters must "
@@ -214,7 +215,7 @@ DbAccessParser::getDbAccessString() const {
     // Construct the database access string from all keywords and values in the
     // parameter map where the value is not null.
     string dbaccess;
-    for (StringPair keyval : values_) {
+    for (auto keyval : values_) {
         if (!keyval.second.empty()) {
 
             // Separate keyword/value pair from predecessor (if there is one).
index dc8a2ab94808475597221526d485056f669c08cd..c2be71ef9eb6f2f2aa8ed45da10359a3c9b04540 100644 (file)
@@ -24,13 +24,6 @@ namespace db {
 ///
 class DbAccessParser: public isc::data::SimpleParser {
 public:
-
-    /// @brief Keyword and associated value
-    typedef std::pair<std::string, std::string> StringPair;
-
-    /// @brief Keyword/value collection of database access parameters
-    typedef std::map<std::string, std::string> StringPairMap;
-
     /// @brief Constructor
     DbAccessParser();
 
@@ -60,8 +53,6 @@ public:
     void parse(std::string& access_string,
                isc::data::ConstElementPtr database_config);
 
-
-protected:
     /// @brief Get database access parameters
     ///
     /// Used in testing to check that the configuration information has been
@@ -70,10 +61,10 @@ protected:
     /// @return Reference to the internal map of keyword/value pairs
     ///         representing database access information.  This is valid only
     ///         for so long as the the parser remains in existence.
-    const StringPairMap& getDbAccessParameters() const {
+    const DatabaseConnection::ParameterMap& getDbAccessParameters() const {
         return (values_);
     }
-
+protected:
 
     /// @brief Construct database access string
     ///
@@ -84,7 +75,7 @@ protected:
 
 private:
 
-    std::map<std::string, std::string> values_; ///< Stored parameter values
+    DatabaseConnection::ParameterMap values_; ///< Stored parameter values
 };
 
 };  // namespace db
index a56469750fc2fdc68c7807bb7208abf4cb9cf6bb..4939365e43575ea6a9f7032b14a0f18f8de015f0 100644 (file)
@@ -5,12 +5,16 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
-#include <exceptions/exceptions.h>
+#include <cc/cfg_to_element.h>
+#include <cc/data.h>
 #include <database/database_connection.h>
+#include <database/dbaccess_parser.h>
+#include <exceptions/exceptions.h>
 #include <gtest/gtest.h>
 
 #include <boost/bind.hpp>
 
+using namespace isc::data;
 using namespace isc::db;
 
 /// @brief Test fixture for exercising DbLostCallback invocation
@@ -247,3 +251,67 @@ TEST(DatabaseConnectionTest, redactAccessStringNoPassword) {
     EXPECT_EQ("kea", parameters["name"]);
     EXPECT_EQ("mysql", parameters["type"]);
 }
+
+// Check that the toElementDbAccessString() handles all valid parameters
+// Note that because toElementDbAccessString() utilizes
+// toElement() this tests both.
+TEST(DatabaseConnection, toElementDbAccessStringValid) {
+    const char* configs[] = {
+        "{\n"
+        "\"type\": \"memfile\", \n"
+        "\"user\": \"user_str\", \n"
+        "\"name\": \"name_str\", \n"
+        "\"host\": \"host_str\", \n"
+        "\"password\": \"password_str\", \n"
+        "\"contact-points\": \"contact_str\", \n"
+        "\"keyspace\": \"keyspace_str\", \n"
+        "\"lfc-interval\" : 100, \n"
+        "\"connect-timeout\" : 200, \n"
+        "\"port\" : 300, \n"
+        "\"persist\" : true, \n"
+        "\"readonly\" : false \n"
+        "}\n"
+    };
+
+    DbAccessParser parser;
+    std::string access_str;
+    ConstElementPtr json_elements;
+
+    ASSERT_NO_THROW(json_elements = Element::fromJSON(configs[0]));
+    ASSERT_NO_THROW(parser.parse(access_str, json_elements));
+
+    ElementPtr round_trip = DatabaseConnection::toElementDbAccessString(access_str);
+
+    ASSERT_TRUE(json_elements->equals(*round_trip));
+}
+
+// Check that toElementDbAccessString() catches invalid parameters.
+// Note that because toElementDbAccessString() utilizes
+// toElement() this tests both.
+TEST(DatabaseConnection, toElementDbAccessStringInvalid) {
+    std::vector<std::string> access_strs = {
+        "bogus-param=memfile",
+        "lfc-interval=not-an-integer",
+        "connect-timeout=not-an-integer",
+        "port=not-an-integer",
+        "persist=not-boolean",
+        "readonly=not-boolean"
+    };
+
+    for (auto access_str : access_strs) {
+        ASSERT_THROW(DatabaseConnection::toElementDbAccessString(access_str),
+                     isc::ToElementError)
+                    << "access string should have failed, string=["
+                    << access_str << "]";
+    }
+}
+
+// Check that toElementDbAccessString() handles empty access string
+// Note that because toElementDbAccessString() utilizes
+// toElement() this tests both.
+TEST(DatabaseConnection, toElementDbAccessStringEmpty) {
+    ConstElementPtr elements;
+    ASSERT_NO_THROW(elements = DatabaseConnection::toElementDbAccessString(""));
+    ASSERT_TRUE(elements);
+    ASSERT_EQ(0, elements->size());
+}
index dc735dfbe40fc48fc9eff45550b060be73cc06c0..260032b4f984d0e9352e344397c7fc1ed68034dc 100644 (file)
@@ -114,7 +114,7 @@ public:
     /// @param keyval Array of "const char*" strings in the order keyword,
     ///        value, keyword, value ...  A NULL entry terminates the list.
     void checkAccessString(const char* trace_string,
-                           const DbAccessParser::StringPairMap& parameters,
+                           const DatabaseConnection::ParameterMap& parameters,
                            const char* keyval[]) {
         SCOPED_TRACE(trace_string);
 
@@ -183,7 +183,7 @@ class TestDbAccessParser : public DbAccessParser {
 public:
 
     /// @brief Constructor
-    TestDbAccessParser() 
+    TestDbAccessParser()
         : DbAccessParser()
     {}
 
@@ -206,7 +206,7 @@ public:
     ///
     /// @return Map of keyword/value pairs representing database access
     ///         information.
-    const StringPairMap& getDbAccessParameters() const {
+    const DatabaseConnection::ParameterMap& getDbAccessParameters() const {
         return (DbAccessParser::getDbAccessParameters());
     }
 
@@ -664,7 +664,7 @@ TEST_F(DbAccessParserTest, multipleHost) {
     string json_config2 = toJson(config2);
     ConstElementPtr json_elements1 = Element::fromJSON(json_config1);
     ConstElementPtr json_elements2 = Element::fromJSON(json_config2);
-    
+
     TestDbAccessParser parser1;
     TestDbAccessParser parser2;
     EXPECT_NO_THROW(parser1.parse(json_elements1));
index 77bc826b1256a35a2c4a07e9902c7c23c7a0646f..333bd557eb47a52c2e29651fe9cf2de5eaea1423 100644 (file)
@@ -69,7 +69,7 @@ CfgDbAccess::createManagers() const {
     HostMgr::checkCacheBackend(true);
 }
 
-std::string 
+std::string
 CfgDbAccess::getAccessString(const std::string& access_string) const {
     std::ostringstream s;
     s << access_string;
@@ -84,63 +84,5 @@ CfgDbAccess::getAccessString(const std::string& access_string) const {
     return (s.str());
 }
 
-ElementPtr
-CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
-    ElementPtr result = Element::createMap();
-    // Code from DatabaseConnection::parse
-    if (dbaccess.empty()) {
-        return (result);
-    }
-    std::vector<std::string> tokens;
-    boost::split(tokens, dbaccess, boost::is_any_of(std::string("\t ")));
-    BOOST_FOREACH(std::string token, tokens) {
-        size_t pos = token.find("=");
-        if (pos != std::string::npos) {
-            std::string keyword = token.substr(0, pos);
-            std::string value = token.substr(pos + 1);
-            if ((keyword == "lfc-interval") ||
-                (keyword == "connect-timeout") ||
-                (keyword == "port")) {
-                // integer parameters
-                int64_t int_value;
-                try {
-                    int_value = boost::lexical_cast<int64_t>(value);
-                    result->set(keyword, Element::create(int_value));
-                } catch (...) {
-                    isc_throw(ToElementError, "invalid DB access "
-                              << "integer parameter: "
-                              << keyword << "=" << value);
-                }
-            } else if ((keyword == "persist") ||
-                       (keyword == "readonly")) {
-                if (value == "true") {
-                    result->set(keyword, Element::create(true));
-                } else if (value == "false") {
-                    result->set(keyword, Element::create(false));
-                } else {
-                    isc_throw(ToElementError, "invalid DB access "
-                              << "boolean parameter: "
-                              << keyword << "=" << value);
-                }
-            } else if ((keyword == "type") ||
-                       (keyword == "user") ||
-                       (keyword == "password") ||
-                       (keyword == "host") ||
-                       (keyword == "name") ||
-                       (keyword == "contact-points") ||
-                       (keyword == "keyspace")) {
-                result->set(keyword, Element::create(value));
-            } else {
-                isc_throw(ToElementError, "unknown DB access parameter: "
-                          << keyword << "=" << value);
-            }
-        } else {
-            isc_throw(ToElementError, "Cannot unparse " << token
-                      << ", expected format is name=value");
-        }
-    }
-    return (result);
-}
-
 } // end of isc::dhcp namespace
 } // end of isc namespace
index db4ae335b8dff777abc2fd002877437b780c45a7..b4ac00c24572348939c7f3ad8bf28961c3df9ff3 100644 (file)
@@ -78,13 +78,6 @@ public:
     /// according to the configuration specified.
     void createManagers() const;
 
-    /// @brief Unparse an access string
-    ///
-    /// @param dbaccess the database access string
-    /// @return a pointer to configuration
-    static
-    isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
-
 protected:
 
     /// @brief Returns lease or host database access string.
@@ -121,7 +114,7 @@ struct CfgLeaseDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
     ///
     /// @result a pointer to a configuration
     virtual isc::data::ElementPtr toElement() const {
-        return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
+        return (db::DatabaseConnection::toElementDbAccessString(lease_db_access_));
     }
 };
 
@@ -138,7 +131,7 @@ struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
         isc::data::ElementPtr result = isc::data::Element::createList();
         for (const std::string& dbaccess : host_db_access_) {
             isc::data::ElementPtr entry =
-                CfgDbAccess::toElementDbAccessString(dbaccess);
+                db::DatabaseConnection::toElementDbAccessString(dbaccess);
             if (entry->size() > 0) {
                 result->add(entry);
             }