Parcourir la source

[2559] Basic parser and associated tests added

Able to construct a database access string from elements in the
configuration database.  No semantic checks have been done yet.
Stephen Morris il y a 12 ans
Parent
commit
6f2e770cfb

+ 1 - 0
src/bin/dhcp6/Makefile.am

@@ -46,6 +46,7 @@ pkglibexec_PROGRAMS = b10-dhcp6
 
 b10_dhcp6_SOURCES  = main.cc
 b10_dhcp6_SOURCES += ctrl_dhcp6_srv.cc ctrl_dhcp6_srv.h
+b10_dhcp6_SOURCES += dbaccess_parser.cc dbaccess_parser.h
 b10_dhcp6_SOURCES += config_parser.cc config_parser.h
 b10_dhcp6_SOURCES += dhcp6_log.cc dhcp6_log.h
 b10_dhcp6_SOURCES += dhcp6_srv.cc dhcp6_srv.h

+ 55 - 0
src/bin/dhcp6/dbaccess_parser.cc

@@ -0,0 +1,55 @@
+// Copyright (C) 2012  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 <dhcp6/dbaccess_parser.h>
+
+#include <boost/foreach.hpp>
+
+#include <map>
+#include <string>
+#include <utility>
+
+using namespace std;
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+/// @brief an auxiliary type used for storing an element name and its parser
+typedef map<string, ConstElementPtr> ConfigPairMap;
+typedef pair<string, ConstElementPtr> ConfigPair;
+
+// Parse the configuration and check that the various keywords are consistent.
+void
+DbAccessParser::build(isc::data::ConstElementPtr config_value) {
+
+    // All OK, build up the access string
+    dbaccess_ = "";
+    BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
+        if (! dbaccess_.empty()) {
+            dbaccess_ += std::string(" ");
+        }
+        dbaccess_ += (param.first + std::string("=") +
+                      param.second->stringValue());
+    }
+}
+
+// Commit the changes - reopen the database with the new parameters
+void
+DbAccessParser::commit() {
+}
+
+};  // namespace dhcp
+};  // namespace isc
+

+ 87 - 0
src/bin/dhcp6/dbaccess_parser.h

@@ -0,0 +1,87 @@
+// Copyright (C) 2012  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 DBACCESS_PARSER_H
+#define DBACCESS_PARSER_H
+
+#include <cc/data.h>
+#include <dhcp6/config_parser.h>
+
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Parse Lease Database Parameters
+///
+/// This class is the parser for the lease database configuration.  This is a
+/// map under the top-level "lease-database" element, and comprises a map of
+/// strings.
+///
+/// Only the "type" sub-element is mandatory: the remaining sub-elements 
+/// depend on the datbase chosen.
+class DbAccessParser: public DhcpConfigParser {
+public:
+
+    /// @brief Default constructor
+    ///
+    DbAccessParser()
+    {}
+
+    /// The destructor.
+    virtual ~DbAccessParser()
+    {}
+
+    /// @brief Prepare configuration value.
+    ///
+    /// Parses the set of strings forming the database access specification and
+    /// checks that all are OK.  In particular it checks:
+    ///
+    /// - "type" is "memfile" or "mysql"
+    /// - If "type" is "memfile", checks that no other values are present: if
+    ///   they are, logs a warning that they will be ignored.
+    ///
+    /// Once all has been validated, constructs the database access string
+    /// expected by the lease manager.
+    ///
+    /// @param config_value The configuration value for the "lease-database"
+    ///        identifier.
+    virtual void build(isc::data::ConstElementPtr config_value);
+
+    /// @brief Apply the prepared configuration value to the server.
+    ///
+    /// With the string validated, this closes the currently open database (if
+    /// any), then opens a database corresponding to the stored string.
+    ///
+    /// This method is expected to be called after \c build(), and only once.
+    /// The result is undefined otherwise.
+    virtual void commit();
+
+    /// @brief Get database access string
+    ///
+    /// Used in testing to check that the configuration information has been
+    /// parsed corrected.
+    std::string getDbAccessString() const {
+        return (dbaccess_);
+    }
+
+private:
+    std::string     dbaccess_;      ///< Database access string
+};
+
+};  // namespace dhcp
+};  // namespace isc
+
+
+#endif // DBACCESS_PARSER_H

+ 2 - 0
src/bin/dhcp6/tests/Makefile.am

@@ -47,8 +47,10 @@ dhcp6_unittests_SOURCES  = dhcp6_unittests.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
 dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc
 dhcp6_unittests_SOURCES += config_parser_unittest.cc
+dhcp6_unittests_SOURCES += dbaccess_parser_unittest.cc
 dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
 dhcp6_unittests_SOURCES += ../dhcp6_log.h ../dhcp6_log.cc
+dhcp6_unittests_SOURCES += ../dbaccess_parser.h ../dbaccess_parser.cc
 dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc
 dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h
 nodist_dhcp6_unittests_SOURCES = ../dhcp6_messages.h ../dhcp6_messages.cc

+ 185 - 0
src/bin/dhcp6/tests/dbaccess_parser_unittest.cc

@@ -0,0 +1,185 @@
+// Copyright (C) 2012 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 <dhcp6/dbaccess_parser.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <config/ccsession.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <arpa/inet.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::data;
+using namespace isc::config;
+
+namespace {
+
+/// @brief Database Access Parser test fixture class
+class DbAccessParserTest : public ::testing::Test {
+public:
+    /// @ Build JSON String
+    ///
+    /// Given a array of "const char*" strings representing in order, keyword,
+    /// value, keyword, value, ... and terminated by a NULL, return a string
+    /// that represents the JSON map for the keywords and values.
+    ///
+    /// @param keyval Array of "const char*" strings in the order keyword,
+    ///        value, keyword, value ...  A NULL entry terminates the list.
+    ///
+    /// @return JSON map for the keyword value array.
+    std::string toJson(const char* keyval[]) {
+        const std::string quote = "\"";
+        const std::string colon = ":";
+        const std::string space = " ";
+
+        string result = "{ ";
+
+        for (size_t i = 0; keyval[i] != NULL; i+= 2) {
+            // Get the value.  This should not be NULL.  As ASSERT_NE will
+            // cause a return - which gives compilation problems as a return
+            // statement is expected to return a string - use EXPECT_NE and
+            // explicitly return if the expected array is incorrect.
+            EXPECT_NE(static_cast<const char*>(NULL), keyval[i + 1]) <<
+                "Supplied reference keyword/value list does not contain values "
+                "for all keywords";
+            if (keyval[i + 1] == NULL) {
+                return (std::string(""));
+            }
+
+            // Add the separating comma if not the first.
+            if (i != 0) {
+                result += ", ";
+            }
+
+            // Add the keyword and value - make sure that they are quoted.
+            result += quote + keyval[i] + quote + colon + space +
+                      quote + keyval[i + 1] + quote;
+        }
+
+        // Add the terminating brace
+        result += " }";
+
+        return (result);
+    }
+
+    /// @brief Check for Keywords
+    ///
+    /// Takes a database access string and checks it against a list of keywords
+    /// and values.  It checks that:
+    ///
+    /// a. Every keyword in the string appears once and only once in the
+    ///    list.
+    /// b. Every keyword in the list appears in the string.
+    /// c. Every keyword's value is the same as that in the string.
+    ///
+    /// To parse the access string, we use the parsing function in the
+    /// DHCP lease manager.
+    ///
+    /// @param trace_string String that will be used to set the value of a
+    ///        SCOPED_TRACE for this call.
+    /// @param dbaccess Database access string to check
+    /// @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, std::string& dbaccess,
+                           const char* keyval[]) {
+        SCOPED_TRACE(trace_string);
+
+        // Construct a map of keyword value pairs.  Check that no keyword
+        // is repeated.
+        map<string, string> expected;
+        size_t expected_count = 0;
+        for (size_t i = 0; keyval[i] != NULL; i += 2) {
+            // Get the value.  This should not be NULL
+            ASSERT_NE(static_cast<const char*>(NULL), keyval[i + 1]) <<
+                "Supplied reference keyword/value list does not contain values "
+                "for all keywords";
+            expected[keyval[i]] = keyval[i + 1];
+
+            // One more keyword processed
+            ++expected_count;
+        }
+
+        // Check no duplicates in the supplied keywords
+        ASSERT_EQ(expected_count, expected.size()) << 
+            "Supplied reference keyword/value list contains duplicate keywords";
+
+        // Split the database access string.
+        const LeaseMgr::ParameterMap dbamap = LeaseMgrFactory::parse(dbaccess);
+
+        // It should have the same number keyword value pairs as the
+        EXPECT_EQ(expected_count, dbamap.size());
+
+        // Check that the keywords and keyword values are the same: loop
+        // through the keywords in the database access string.
+        for (LeaseMgr::ParameterMap::const_iterator actual = dbamap.begin();
+             actual != dbamap.end(); ++actual) {
+
+            // Does the keyword exist in the set of expected keywords?
+            map<string, string>::iterator corresponding =
+                expected.find(actual->first);
+            ASSERT_TRUE(corresponding != expected.end());
+
+            // Keyword exists, is the value the same?
+            EXPECT_EQ(corresponding->second, actual->second);
+        }
+    }
+};
+
+// Check that the parser works with a simple configuration.
+TEST_F(DbAccessParserTest, validMemfile) {
+    const char* config[] = {"type", "memfile",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    DbAccessParser parser;
+    EXPECT_NO_THROW(parser.build(json_elements));
+    string dbaccess = parser.getDbAccessString();
+
+    checkAccessString("Valid memfile", dbaccess, config);
+}
+
+// Check that it works with a valid MySQL configuration
+TEST_F(DbAccessParserTest, validMySql) {
+    const char* config[] = {"type",     "mysql",
+                            "host",     "erewhon",
+                            "user",     "kea",
+                            "password", "keapassword",
+                            "name",     "keatest",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    DbAccessParser parser;
+    EXPECT_NO_THROW(parser.build(json_elements));
+    string dbaccess = parser.getDbAccessString();
+
+    checkAccessString("Valid mysql", dbaccess, config);
+}
+
+};  // Anonymous namespace