From: Stephen Morris Date: Thu, 20 Dec 2012 21:01:00 +0000 (+0000) Subject: [2559] Basic parser and associated tests added X-Git-Tag: bind10-1.0.0-rc-release~76^2~21^2~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6f2e770cfbec4ffed1f314bed4e1b8b480c32c16;p=thirdparty%2Fkea.git [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. --- diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 1d9766f51e..40a7eefdf8 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/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 diff --git a/src/bin/dhcp6/dbaccess_parser.cc b/src/bin/dhcp6/dbaccess_parser.cc new file mode 100644 index 0000000000..9a13d9bea9 --- /dev/null +++ b/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 + +#include + +#include +#include +#include + +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 ConfigPairMap; +typedef pair 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 + diff --git a/src/bin/dhcp6/dbaccess_parser.h b/src/bin/dhcp6/dbaccess_parser.h new file mode 100644 index 0000000000..8cfec7e4d0 --- /dev/null +++ b/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 +#include + +#include + +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 diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index b01b8777aa..d84cf57a95 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/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 diff --git a/src/bin/dhcp6/tests/dbaccess_parser_unittest.cc b/src/bin/dhcp6/tests/dbaccess_parser_unittest.cc new file mode 100644 index 0000000000..0e66ad188b --- /dev/null +++ b/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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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(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 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(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::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