From: Tomek Mrugalski Date: Tue, 1 Dec 2015 19:32:31 +0000 (+0100) Subject: [3569_rebase] MySQL host data source is now indeed created and stored. X-Git-Tag: trac4231_base~9^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3be59fccd1c8f2234ed550bd7911b992c5007977;p=thirdparty%2Fkea.git [3569_rebase] MySQL host data source is now indeed created and stored. --- diff --git a/src/lib/dhcpsrv/host_data_source_factory.cc b/src/lib/dhcpsrv/host_data_source_factory.cc index 245bf83fc1..3865c8184c 100644 --- a/src/lib/dhcpsrv/host_data_source_factory.cc +++ b/src/lib/dhcpsrv/host_data_source_factory.cc @@ -39,9 +39,9 @@ namespace isc { namespace dhcp { -boost::scoped_ptr& +HostDataSourcePtr& HostDataSourceFactory::getHostDataSourcePtr() { - static boost::scoped_ptr hostDataSourcePtr; + static HostDataSourcePtr hostDataSourcePtr; return (hostDataSourcePtr); } @@ -99,6 +99,7 @@ HostDataSourceFactory::destroy() { getHostDataSourcePtr().reset(); } +#if 0 BaseHostDataSource& HostDataSourceFactory::instance() { BaseHostDataSource* hdsptr = getHostDataSourcePtr().get(); @@ -108,6 +109,7 @@ HostDataSourceFactory::instance() { } return (*hdsptr); } +#endif }; // namespace dhcp }; // namespace isc diff --git a/src/lib/dhcpsrv/host_data_source_factory.h b/src/lib/dhcpsrv/host_data_source_factory.h index c0b38c643b..09fda5a597 100644 --- a/src/lib/dhcpsrv/host_data_source_factory.h +++ b/src/lib/dhcpsrv/host_data_source_factory.h @@ -88,23 +88,12 @@ public: /// host data source is available. static void destroy(); - /// @brief Return current host data source - /// - /// @returns An instance of the "current" host data source. An exception - /// will be thrown if none is available. - /// - /// @throw NoHostDataSourceManager No host data source is available: use - /// create() to create one before calling this method. - static BaseHostDataSource& instance(); - -private: /// @brief Hold pointer to host data source instance /// /// Holds a pointer to the singleton host data source. The singleton /// is encapsulated in this method to avoid a "static initialization /// fiasco" if defined in an external static variable. - static boost::scoped_ptr& getHostDataSourcePtr(); - + static HostDataSourcePtr& getHostDataSourcePtr(); }; diff --git a/src/lib/dhcpsrv/host_mgr.cc b/src/lib/dhcpsrv/host_mgr.cc index 125d36cc71..53bd746857 100644 --- a/src/lib/dhcpsrv/host_mgr.cc +++ b/src/lib/dhcpsrv/host_mgr.cc @@ -51,9 +51,10 @@ HostMgr::create(const std::string& access) { if (!access.empty()) { HostDataSourceFactory::create(access); - /// @todo Initialize alternate_source here. - //alternate_source = HostDataSourceFactory::getHostDataSourcePtr(); } + + // Now store the host data source pointer. + getHostMgrPtr()->alternate_source = HostDataSourceFactory::getHostDataSourcePtr(); } HostMgr& diff --git a/src/lib/dhcpsrv/mysql_connection.h b/src/lib/dhcpsrv/mysql_connection.h index 7a3c6ee09f..8d52c57a30 100755 --- a/src/lib/dhcpsrv/mysql_connection.h +++ b/src/lib/dhcpsrv/mysql_connection.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace isc { namespace dhcp { diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index 91677fcc01..3b6d8f6787 100755 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -104,6 +104,7 @@ libdhcpsrv_unittests_SOURCES += generic_host_data_source_unittest.cc generic_hos libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc libdhcpsrv_unittests_SOURCES += dhcp_parsers_unittest.cc if HAVE_MYSQL +libdhcpsrv_unittests_SOURCES += mysql_schema.cc mysql_schema.h libdhcpsrv_unittests_SOURCES += mysql_lease_mgr_unittest.cc libdhcpsrv_unittests_SOURCES += mysql_host_data_source_unittest.cc endif diff --git a/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc b/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc index 59c9ca6428..3ff645301c 100644 --- a/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,7 @@ using namespace std; using namespace isc; using namespace isc::dhcp; +using namespace isc::dhcp::test; using namespace isc::data; using namespace isc::config; @@ -536,6 +538,8 @@ TEST_F(DbAccessParserTest, getDbAccessString) { // that does not assume that the test has been built with MySQL support. TEST_F(DbAccessParserTest, commitLeaseDb) { + EXPECT_NO_THROW(createMySQLSchema()); + // Verify that no lease database is open EXPECT_THROW({ LeaseMgr& manager = LeaseMgrFactory::instance(); @@ -566,8 +570,11 @@ TEST_F(DbAccessParserTest, commitLeaseDb) { EXPECT_EQ(std::string("memfile"), dbtype); } +#ifdef HAVE_MYSQL // Check that the "commit" function actually opens the database, when type -// is set to HOSTS_DB. +// is set to HOSTS_DB. We're using MySQL here. Since the only currently supported +// host data source is the one that uses MySQL, we have no other choice, but to +// depend this test on MYSQL availability. TEST_F(DbAccessParserTest, commitHostsDb) { // Verify that no lease database is open @@ -577,7 +584,8 @@ TEST_F(DbAccessParserTest, commitHostsDb) { }, isc::dhcp::NoLeaseManager); // Set up the parser to open the memfile database. - const char* config[] = {"type", "memfile", "persist", "false", NULL}; + const char* config[] = {"type", "mysql", "user", "keatest", + "password", "keatest", "name", "keatest", NULL}; string json_config = toJson(config); ConstElementPtr json_elements = Element::fromJSON(json_config); @@ -588,24 +596,29 @@ TEST_F(DbAccessParserTest, commitHostsDb) { EXPECT_NO_THROW(parser.build(json_elements)); // Ensure that the access string is as expected. - EXPECT_EQ("persist=false type=memfile universe=4", + EXPECT_EQ("name=keatest password=keatest type=mysql universe=4 user=keatest", parser.getDbAccessString()); // Destroy lease mgr (if there's any) LeaseMgrFactory::destroy(); + EXPECT_NO_THROW(createMySQLSchema()); + // Committal of the parser changes should not create LeaseMgr. // It should create HostDataSource instead. EXPECT_NO_THROW(parser.commit()); - // Check that LeaseMgr was NOT created (it shouldn't, this is for HOSTS_DB. + // Check that LeaseMgr was NOT created (it shouldn't, this is for HOSTS_DB). EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager); + // Verify that HostDataSource has been created. HostDataSourcePtr hds = HostMgr::instance().getHostDataSource(); + ASSERT_TRUE(hds); + + EXPECT_EQ("mysql", hds->getType()); - /// @todo: Uncomment this once 3682 is merged. The whole unit-test - /// should create MySQL database and be ifdefed appropriately. - // ASSERT_TRUE(hds); + EXPECT_NO_THROW(destroyMySQLSchema()); } +#endif }; // Anonymous namespace diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc index 289a7917ec..aaf3b32f54 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc @@ -27,7 +27,7 @@ namespace dhcp { namespace test { GenericHostDataSourceTest::GenericHostDataSourceTest() - :hdsptr_(NULL) { + :hdsptr_() { } diff --git a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h index d73d8ec6c5..ced6d9d7ec 100644 --- a/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h +++ b/src/lib/dhcpsrv/tests/generic_host_data_source_unittest.h @@ -125,7 +125,7 @@ public: const ClientClasses& classes2); /// @brief Pointer to the host data source - BaseHostDataSource* hdsptr_; + HostDataSourcePtr hdsptr_; /// @brief Test that checks that simple host with IPv4 reservation /// can be inserted and later retrieved. diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index 5a44365c60..04cb5f474c 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -166,7 +166,7 @@ public: throw; } - hdsptr_ = &(HostDataSourceFactory::instance()); + hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr(); } /// @brief Destructor @@ -189,7 +189,7 @@ public: void reopen(Universe) { HostDataSourceFactory::destroy(); HostDataSourceFactory::create(validConnectionString()); - hdsptr_ = &(HostDataSourceFactory::instance()); + hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr(); } }; @@ -211,7 +211,7 @@ TEST(MySqlHostDataSource, OpenDatabase) { // If it fails, print the error message. try { HostDataSourceFactory::create(validConnectionString()); - EXPECT_NO_THROW((void) HostDataSourceFactory::instance()); + EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr()); HostDataSourceFactory::destroy(); } catch (const isc::Exception& ex) { FAIL() << "*** ERROR: unable to open database, reason:\n" @@ -222,7 +222,7 @@ TEST(MySqlHostDataSource, OpenDatabase) { // Check that attempting to get an instance of the lease manager when // none is set throws an exception. - EXPECT_THROW(HostDataSourceFactory::instance(), NoHostDataSourceManager); + EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr()); // Check that wrong specification of backend throws an exception. // (This is really a check on LeaseMgrFactory, but is convenient to diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc index ec5d558099..0fc905cc5c 100755 --- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -38,108 +39,6 @@ using namespace std; namespace { -// This holds statements to create and destroy the schema. -#include "schema_mysql_copy.h" - -// Connection strings. -// Database: keatest -// Host: localhost -// Username: keatest -// Password: keatest -const char* VALID_TYPE = "type=mysql"; -const char* INVALID_TYPE = "type=unknown"; -const char* VALID_NAME = "name=keatest"; -const char* INVALID_NAME = "name=invalidname"; -const char* VALID_HOST = "host=localhost"; -const char* INVALID_HOST = "host=invalidhost"; -const char* VALID_USER = "user=keatest"; -const char* INVALID_USER = "user=invaliduser"; -const char* VALID_PASSWORD = "password=keatest"; -const char* INVALID_PASSWORD = "password=invalid"; - -// Given a combination of strings above, produce a connection string. -string connectionString(const char* type, const char* name, const char* host, - const char* user, const char* password) { - const string space = " "; - string result = ""; - - if (type != NULL) { - result += string(type); - } - if (name != NULL) { - if (! result.empty()) { - result += space; - } - result += string(name); - } - - if (host != NULL) { - if (! result.empty()) { - result += space; - } - result += string(host); - } - - if (user != NULL) { - if (! result.empty()) { - result += space; - } - result += string(user); - } - - if (password != NULL) { - if (! result.empty()) { - result += space; - } - result += string(password); - } - - return (result); -} - -// Return valid connection string -string -validConnectionString() { - return (connectionString(VALID_TYPE, VALID_NAME, VALID_HOST, - VALID_USER, VALID_PASSWORD)); -} - -// @brief Clear everything from the database -// -// There is no error checking in this code: if something fails, one of the -// tests will (should) fall over. -void destroySchema() { - MySqlHolder mysql; - - // Open database - (void) mysql_real_connect(mysql, "localhost", "keatest", - "keatest", "keatest", 0, NULL, 0); - - // Get rid of everything in it. - for (int i = 0; destroy_statement[i] != NULL; ++i) { - (void) mysql_query(mysql, destroy_statement[i]); - } -} - -// @brief Create the Schema -// -// Creates all the tables in what is assumed to be an empty database. -// -// There is no error checking in this code: if it fails, one of the tests -// will fall over. -void createSchema() { - MySqlHolder mysql; - - // Open database - (void) mysql_real_connect(mysql, "localhost", "keatest", - "keatest", "keatest", 0, NULL, 0); - - // Execute creation statements. - for (int i = 0; create_statement[i] != NULL; ++i) { - ASSERT_EQ(0, mysql_query(mysql, create_statement[i])) - << "Failed on statement " << i << ": " << create_statement[i]; - } -} /// @brief Test fixture class for testing MySQL Lease Manager /// @@ -154,12 +53,12 @@ public: MySqlLeaseMgrTest() { // Ensure schema is the correct one. - destroySchema(); - createSchema(); + destroyMySQLSchema(); + createMySQLSchema(); // Connect to the database try { - LeaseMgrFactory::create(validConnectionString()); + LeaseMgrFactory::create(validMySQLConnectionString()); } catch (...) { std::cerr << "*** ERROR: unable to open database. The test\n" "*** environment is broken and must be fixed before\n" @@ -178,7 +77,7 @@ public: virtual ~MySqlLeaseMgrTest() { lmptr_->rollback(); LeaseMgrFactory::destroy(); - destroySchema(); + destroyMySQLSchema(); } /// @brief Reopen the database @@ -190,7 +89,7 @@ public: /// the same database. void reopen(Universe) { LeaseMgrFactory::destroy(); - LeaseMgrFactory::create(validConnectionString()); + LeaseMgrFactory::create(validMySQLConnectionString()); lmptr_ = &(LeaseMgrFactory::instance()); } @@ -206,13 +105,13 @@ public: TEST(MySqlOpenTest, OpenDatabase) { // Schema needs to be created for the test to work. - destroySchema(); - createSchema(); + destroyMySQLSchema(); + createMySQLSchema(); // Check that lease manager open the database opens correctly and tidy up. // If it fails, print the error message. try { - LeaseMgrFactory::create(validConnectionString()); + LeaseMgrFactory::create(validMySQLConnectionString()); EXPECT_NO_THROW((void) LeaseMgrFactory::instance()); LeaseMgrFactory::destroy(); } catch (const isc::Exception& ex) { @@ -256,7 +155,7 @@ TEST(MySqlOpenTest, OpenDatabase) { NoDatabaseName); // Tidy up after the test - destroySchema(); + destroyMySQLSchema(); } /// @brief Check the getType() method diff --git a/src/lib/dhcpsrv/tests/mysql_schema.cc b/src/lib/dhcpsrv/tests/mysql_schema.cc new file mode 100644 index 0000000000..ade43e3e40 --- /dev/null +++ b/src/lib/dhcpsrv/tests/mysql_schema.cc @@ -0,0 +1,131 @@ +// Copyright (C) 2015 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 + +// This holds statements to create and destroy the schema. +#include "schema_mysql_copy.h" + +using namespace std; + +namespace isc { +namespace dhcp { +namespace test { + +// Connection strings. +// Database: keatest +// Host: localhost +// Username: keatest +// Password: keatest +const char* VALID_TYPE = "type=mysql"; +const char* INVALID_TYPE = "type=unknown"; +const char* VALID_NAME = "name=keatest"; +const char* INVALID_NAME = "name=invalidname"; +const char* VALID_HOST = "host=localhost"; +const char* INVALID_HOST = "host=invalidhost"; +const char* VALID_USER = "user=keatest"; +const char* INVALID_USER = "user=invaliduser"; +const char* VALID_PASSWORD = "password=keatest"; +const char* INVALID_PASSWORD = "password=invalid"; + +string connectionString(const char* type, const char* name, const char* host, + const char* user, const char* password) { + const string space = " "; + string result = ""; + + if (type != NULL) { + result += string(type); + } + if (name != NULL) { + if (! result.empty()) { + result += space; + } + result += string(name); + } + + if (host != NULL) { + if (! result.empty()) { + result += space; + } + result += string(host); + } + + if (user != NULL) { + if (! result.empty()) { + result += space; + } + result += string(user); + } + + if (password != NULL) { + if (! result.empty()) { + result += space; + } + result += string(password); + } + + return (result); +} + +// Return valid connection string +string +validMySQLConnectionString() { + return (connectionString(VALID_TYPE, VALID_NAME, VALID_HOST, + VALID_USER, VALID_PASSWORD)); +} + +// @brief Clear everything from the database +// +// There is no error checking in this code: if something fails, one of the +// tests will (should) fall over. +void destroyMySQLSchema() { + MySqlHolder mysql; + + // Open database + (void) mysql_real_connect(mysql, "localhost", "keatest", + "keatest", "keatest", 0, NULL, 0); + + // Get rid of everything in it. + for (int i = 0; destroy_statement[i] != NULL; ++i) { + (void) mysql_query(mysql, destroy_statement[i]); + } +} + +// @brief Create the Schema +// +// Creates all the tables in what is assumed to be an empty database. +// +// There is no error checking in this code: if it fails, one of the tests +// will fall over. +void createMySQLSchema() { + MySqlHolder mysql; + + // Open database + (void) mysql_real_connect(mysql, "localhost", "keatest", + "keatest", "keatest", 0, NULL, 0); + + // Execute creation statements. + for (int i = 0; create_statement[i] != NULL; ++i) { + ASSERT_EQ(0, mysql_query(mysql, create_statement[i])) + << "Failed on statement " << i << ": " << create_statement[i]; + } +} + +}; +}; +}; diff --git a/src/lib/dhcpsrv/tests/mysql_schema.h b/src/lib/dhcpsrv/tests/mysql_schema.h new file mode 100644 index 0000000000..063f21a73c --- /dev/null +++ b/src/lib/dhcpsrv/tests/mysql_schema.h @@ -0,0 +1,69 @@ +// Copyright (C) 2015 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 TEST_MYSQL_SCHEMA_H +#define TEST_MYSQL_SCHEMA_H + +#include +#include + +namespace isc { +namespace dhcp { +namespace test { + +extern const char* VALID_TYPE; +extern const char* INVALID_TYPE; +extern const char* VALID_NAME; +extern const char* INVALID_NAME; +extern const char* VALID_HOST; +extern const char* INVALID_HOST; +extern const char* VALID_USER; +extern const char* INVALID_USER; +extern const char* VALID_PASSWORD; +extern const char* INVALID_PASSWORD; + +/// @brief Create the Schema +/// +/// Creates all the tables in what is assumed to be an empty database. +/// +/// There is no error checking in this code: if it fails, one of the tests +/// will fall over. +void createMySQLSchema(); + +/// @brief Clear everything from the database +/// +/// There is no error checking in this code: if something fails, one of the +/// tests will (should) fall over. +void destroyMySQLSchema(); + +/// Return valid connection string +/// +/// @return valid MySQL connection string. +std::string validMySQLConnectionString(); + +/// @brief Given a combination of strings above, produce a connection string. +/// +/// @param type type of the database +/// @param name name of the database to connect to +/// @param host hostname +/// @param user username used to authendicate during connection attempt +/// @param password password used to authendicate during connection attempt +/// @return string containing all specified parameters +std::string connectionString(const char* type, const char* name, const char* host, + const char* user, const char* password); +}; +}; +}; + +#endif