Commit 6f2e770c authored by Stephen Morris's avatar Stephen Morris
Browse files

[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.
parent 8d8605b6
......@@ -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
......
// 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
// 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
......@@ -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
......
// 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
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