diff --git a/src/bin/agent/parser_context.cc b/src/bin/agent/parser_context.cc index 7c18e034e3..675fda3db6 100644 --- a/src/bin/agent/parser_context.cc +++ b/src/bin/agent/parser_context.cc @@ -57,15 +57,14 @@ ParserContext::parseCommon() { isc_throw(ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/d2/parser_context.cc b/src/bin/d2/parser_context.cc index d70212e2fa..d71ea40d28 100644 --- a/src/bin/d2/parser_context.cc +++ b/src/bin/d2/parser_context.cc @@ -57,15 +57,14 @@ D2ParserContext::parseCommon() { isc_throw(D2ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(D2ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(D2ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h index 1c8e6dc8ad..8464ae245d 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.h +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h @@ -124,6 +124,7 @@ private: /// (that was sent from some yet unspecified sender). static void sessionReader(void); +protected: /// @brief Handler for processing 'shutdown' command /// /// This handler processes shutdown command, which initializes shutdown @@ -342,6 +343,7 @@ private: commandStatisticSetMaxSampleAgeAllHandler(const std::string& command, isc::data::ConstElementPtr args); +private: /// @brief Reclaims expired IPv4 leases and reschedules timer. /// /// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases4. diff --git a/src/bin/dhcp4/parser_context.cc b/src/bin/dhcp4/parser_context.cc index c0156c79bf..daca1e7022 100644 --- a/src/bin/dhcp4/parser_context.cc +++ b/src/bin/dhcp4/parser_context.cc @@ -55,15 +55,14 @@ Parser4Context::parseCommon() { isc_throw(Dhcp4ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(Dhcp4ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(Dhcp4ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/dhcp4/tests/kea_controller_unittest.cc b/src/bin/dhcp4/tests/kea_controller_unittest.cc index c636be1238..f61c90f58e 100644 --- a/src/bin/dhcp4/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp4/tests/kea_controller_unittest.cc @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -55,6 +56,7 @@ using namespace isc::db::test; using namespace isc::dhcp; using namespace isc::dhcp::test; using namespace isc::hooks; +using namespace isc::test; namespace { @@ -176,7 +178,7 @@ typedef boost::shared_ptr TestCBControlDHCPv4Ptr; /// /// Exposes internal fields and installs stub implementation of the /// @c CBControlDHCPv4 object. -class NakedControlledDhcpv4Srv: public ControlledDhcpv4Srv { +class NakedControlledDhcpv4Srv : public ControlledDhcpv4Srv { public: /// @brief Constructor. @@ -185,7 +187,14 @@ public: // We're replacing the @c CBControlDHCPv4 instance with our // stub implementation used in tests. cb_control_.reset(new TestCBControlDHCPv4()); + + CfgMgr::instance().setFamily(AF_INET); } + + using ControlledDhcpv4Srv::commandConfigGetHandler; + using ControlledDhcpv4Srv::commandConfigSetHandler; + using ControlledDhcpv4Srv::commandConfigReloadHandler; + using ControlledDhcpv4Srv::commandConfigWriteHandler; }; /// @brief test class for Kea configuration backend @@ -301,7 +310,6 @@ public: EXPECT_EQ(0, cb_control->getDatabaseCurrentConfigFetchCalls()); EXPECT_EQ(1, cb_control->getDatabaseStagingConfigFetchCalls()); - if (call_command) { // The case where there is no backend is tested in the // controlled server tests so we have only to verify @@ -1079,7 +1087,6 @@ testBackendReconfiguration(const std::string& backend_first, LeaseMgrFactory::instance().getType()); } - // This test verifies that backend specification can be added on // server reconfiguration. TEST_F(JSONFileBackendMySQLTest, reconfigureBackendUndefinedToMySQL) { @@ -1100,4 +1107,94 @@ TEST_F(JSONFileBackendMySQLTest, reconfigureBackendMemfileToMySQL) { #endif +/// @brief Test that all-keys.json config file can be loaded, written to disk +/// and reloaded. +TEST_F(JSONFileBackendTest, DISABLED_loadWriteReloadTest) { + + // Create server first. + boost::scoped_ptr srv; + ASSERT_NO_THROW( + srv.reset(new NakedControlledDhcpv4Srv()); + ); + + try { + srv->init(CFG_EXAMPLES"/all-keys.json"); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Exception thrown on load: " << ex.what() << endl; + } + + // Save initial configuration. + // ConstElementPtr expected_json; + + // Read contents of the file and parse it as JSON. + // { + // Parser4Context parser; + // expected_json = parser.parseFile(CFG_EXAMPLES"/all-keys.json", Parser4Context::PARSER_DHCP4); + // if (!expected_json) { + // ADD_FAILURE() << "Invalid configuration in " << CFG_EXAMPLES"/all-keys.json" << endl; + // } + // } + + // Set test file used write and reload configuration. + srv->setConfigFile(TEST_FILE); + + // Save initial configuration to check it with the reloaded configuration. + // ConstElementPtr expected; + // try { + // expected = srv->commandConfigGetHandler("", ConstElementPtr()); + // } catch (const std::exception& ex) { + // ADD_FAILURE() << "Exception thrown on get: " << ex.what() << endl; + // } + + ConstElementPtr result; + int rcode; + + // Configuration is written to test file. + try { + result = srv->commandConfigWriteHandler("", ConstElementPtr()); + result = parseAnswerText(rcode, result); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Exception thrown on write: " << ex.what() << endl; + } + + ASSERT_EQ(CONTROL_RESULT_SUCCESS, rcode); + ASSERT_EQ("Configuration written to test-config.json successful", result->stringValue()); + + // Save written configuration. + // ConstElementPtr actual_json; + + // { + // Parser4Context parser; + // actual_json = parser.parseFile(TEST_FILE, Parser4Context::PARSER_DHCP4); + // if (!actual_json) { + // ADD_FAILURE() << "Invalid configuration in written file " << TEST_FILE << endl; + // } + // } + + // Configuration is reloaded from test file. + try { + result = srv->commandConfigReloadHandler("", ConstElementPtr()); + result = parseAnswerText(rcode, result); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Exception thrown on reload: " << ex.what() << endl; + } + + ASSERT_EQ(CONTROL_RESULT_SUCCESS, rcode); + ASSERT_EQ("Configuration successful.", result->stringValue()); + + // Save reloaded configuration. + // ConstElementPtr actual; + // try { + // expected = srv->commandConfigGetHandler("", ConstElementPtr()); + // } catch (const std::exception& ex) { + // ADD_FAILURE() << "Exception thrown on get after reload: " << ex.what() << endl; + // } + + // Check initial configuration with reloaded configuration. + // expectEqWithDiff(expected_json, actual_json); + + // Check initial configuration with reloaded configuration. + // expectEqWithDiff(expected, actual); +} + } // End of anonymous namespace diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h index 3d75bae6f9..b86e9bf7ac 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.h +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h @@ -124,6 +124,7 @@ private: /// (that was sent from some yet unspecified sender). static void sessionReader(void); +protected: /// @brief Handler for processing 'shutdown' command /// /// This handler processes shutdown command, which initializes shutdown @@ -342,6 +343,7 @@ private: commandStatisticSetMaxSampleAgeAllHandler(const std::string& command, isc::data::ConstElementPtr args); +private: /// @brief Reclaims expired IPv6 leases and reschedules timer. /// /// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases6. diff --git a/src/bin/dhcp6/parser_context.cc b/src/bin/dhcp6/parser_context.cc index 04124a35b5..97a62c2636 100644 --- a/src/bin/dhcp6/parser_context.cc +++ b/src/bin/dhcp6/parser_context.cc @@ -55,15 +55,14 @@ Parser6Context::parseCommon() { isc_throw(Dhcp6ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(Dhcp6ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(Dhcp6ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/bin/dhcp6/tests/kea_controller_unittest.cc b/src/bin/dhcp6/tests/kea_controller_unittest.cc index 9ec596040e..08693ce6f8 100644 --- a/src/bin/dhcp6/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp6/tests/kea_controller_unittest.cc @@ -25,6 +25,7 @@ #endif #include +#include #include #include @@ -52,6 +53,7 @@ using namespace isc::db::test; using namespace isc::dhcp; using namespace isc::dhcp::test; using namespace isc::hooks; +using namespace isc::test; namespace { @@ -173,7 +175,7 @@ typedef boost::shared_ptr TestCBControlDHCPv6Ptr; /// /// Exposes internal fields and installs stub implementation of the /// @c CBControlDHCPv6 object. -class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv { +class NakedControlledDhcpv6Srv : public ControlledDhcpv6Srv { public: /// @brief Constructor. @@ -182,10 +184,22 @@ public: // We're replacing the @c CBControlDHCPv6 instance with our // stub implementation used in tests. cb_control_.reset(new TestCBControlDHCPv6()); + + CfgMgr::instance().setFamily(AF_INET6); } + + using ControlledDhcpv6Srv::commandConfigGetHandler; + using ControlledDhcpv6Srv::commandConfigSetHandler; + using ControlledDhcpv6Srv::commandConfigReloadHandler; + using ControlledDhcpv6Srv::commandConfigWriteHandler; }; - +/// @brief test class for Kea configuration backend +/// +/// This class is used for testing Kea configuration backend. +/// It is very simple and currently focuses on reading +/// config file from disk. It is expected to be expanded in the +/// near future. class JSONFileBackendTest : public dhcp::test::BaseServerTest { public: JSONFileBackendTest() { @@ -286,7 +300,6 @@ public: EXPECT_EQ(0, cb_control->getDatabaseCurrentConfigFetchCalls()); EXPECT_EQ(1, cb_control->getDatabaseStagingConfigFetchCalls()); - if (call_command) { // The case where there is no backend is tested in the // controlled server tests so we have only to verify @@ -796,7 +809,6 @@ TEST_F(JSONFileBackendTest, timers) { duid_expired, 1, 50, 60, SubnetID(1))); lease_expired->cltt_ = time(NULL) - 100; - // Create expired-reclaimed lease. The lease has expired 1000 - 60 seconds // ago. It should be removed from the lease database when the "flush" timer // goes off. @@ -1062,7 +1074,6 @@ testBackendReconfiguration(const std::string& backend_first, LeaseMgrFactory::instance().getType()); } - // This test verifies that backend specification can be added on // server reconfiguration. TEST_F(JSONFileBackendMySQLTest, reconfigureBackendUndefinedToMySQL) { @@ -1083,4 +1094,94 @@ TEST_F(JSONFileBackendMySQLTest, reconfigureBackendMemfileToMySQL) { #endif +/// @brief Test that all-keys.json config file can be loaded, written to disk +/// and reloaded. +TEST_F(JSONFileBackendTest, DISABLED_loadWriteReloadTest) { + + // Create server first. + boost::scoped_ptr srv; + ASSERT_NO_THROW( + srv.reset(new NakedControlledDhcpv6Srv()); + ); + + try { + srv->init(CFG_EXAMPLES"/all-keys.json"); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Exception thrown on load: " << ex.what() << endl; + } + + // Save initial configuration. + // ConstElementPtr expected_json; + + // Read contents of the file and parse it as JSON. + // { + // Parser6Context parser; + // expected_json = parser.parseFile(CFG_EXAMPLES"/all-keys.json", Parser6Context::PARSER_DHCP6); + // if (!expected_json) { + // ADD_FAILURE() << "Invalid configuration in " << CFG_EXAMPLES"/all-keys.json" << endl; + // } + // } + + // Set test file used write and reload configuration. + srv->setConfigFile(TEST_FILE); + + // Save initial configuration to check it with the reloaded configuration. + // ConstElementPtr expected; + // try { + // expected = srv->commandConfigGetHandler("", ConstElementPtr()); + // } catch (const std::exception& ex) { + // ADD_FAILURE() << "Exception thrown on get: " << ex.what() << endl; + // } + + ConstElementPtr result; + int rcode; + + // Configuration is written to test file. + try { + result = srv->commandConfigWriteHandler("", ConstElementPtr()); + result = parseAnswerText(rcode, result); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Exception thrown on write: " << ex.what() << endl; + } + + ASSERT_EQ(CONTROL_RESULT_SUCCESS, rcode); + ASSERT_EQ("Configuration written to test-config.json successful", result->stringValue()); + + // Save written configuration. + // ConstElementPtr actual_json; + + // { + // Parser6Context parser; + // actual_json = parser.parseFile(TEST_FILE, Parser6Context::PARSER_DHCP6); + // if (!actual_json) { + // ADD_FAILURE() << "Invalid configuration in written file " << TEST_FILE << endl; + // } + // } + + // Configuration is reloaded from test file. + try { + result = srv->commandConfigReloadHandler("", ConstElementPtr()); + result = parseAnswerText(rcode, result); + } catch (const std::exception& ex) { + ADD_FAILURE() << "Exception thrown on reload: " << ex.what() << endl; + } + + ASSERT_EQ(CONTROL_RESULT_SUCCESS, rcode); + ASSERT_EQ("Configuration successful.", result->stringValue()); + + // Save reloaded configuration. + // ConstElementPtr actual; + // try { + // expected = srv->commandConfigGetHandler("", ConstElementPtr()); + // } catch (const std::exception& ex) { + // ADD_FAILURE() << "Exception thrown on get after reload: " << ex.what() << endl; + // } + + // Check initial configuration with reloaded configuration. + // expectEqWithDiff(expected_json, actual_json); + + // Check initial configuration with reloaded configuration. + // expectEqWithDiff(expected, actual); +} + } // End of anonymous namespace diff --git a/src/bin/netconf/parser_context.cc b/src/bin/netconf/parser_context.cc index d0e20fc111..3e57c51e9f 100644 --- a/src/bin/netconf/parser_context.cc +++ b/src/bin/netconf/parser_context.cc @@ -57,15 +57,14 @@ ParserContext::parseCommon() { isc_throw(ParseError, "Parser abort"); } scanEnd(); - } - catch (...) { + } catch (...) { scanEnd(); throw; } if (stack_.size() == 1) { return (stack_[0]); } else { - isc_throw(ParseError, "Expected exactly one terminal Element expected, found " + isc_throw(ParseError, "Expected exactly one terminal Element, found " << stack_.size()); } } diff --git a/src/lib/database/database_connection.cc b/src/lib/database/database_connection.cc index 29f99f6ec1..99a0bdf7b0 100644 --- a/src/lib/database/database_connection.cc +++ b/src/lib/database/database_connection.cc @@ -241,7 +241,8 @@ DatabaseConnection::toElement(const ParameterMap& params) { .arg(keyword).arg(value); } } else if ((keyword == "persist") || - (keyword == "readonly")) { + (keyword == "readonly") || + (keyword == "retry-on-startup")) { if (value == "true") { result->set(keyword, isc::data::Element::create(true)); } else if (value == "false") { @@ -256,7 +257,6 @@ DatabaseConnection::toElement(const ParameterMap& params) { (keyword == "host") || (keyword == "name") || (keyword == "on-fail") || - (keyword == "retry-on-startup") || (keyword == "trust-anchor") || (keyword == "cert-file") || (keyword == "key-file") || diff --git a/src/lib/database/tests/database_connection_unittest.cc b/src/lib/database/tests/database_connection_unittest.cc index a0ee38ae02..de1ae2d72d 100644 --- a/src/lib/database/tests/database_connection_unittest.cc +++ b/src/lib/database/tests/database_connection_unittest.cc @@ -536,6 +536,7 @@ TEST(DatabaseConnection, toElementDbAccessStringValid) { "\"port\" : 300, \n" "\"readonly\" : false, \n" "\"reconnect-wait-time\": 99, \n" + "\"retry-on-startup\" : true, \n" "\"type\": \"memfile\", \n" "\"user\": \"user_str\", \n" "\"max-row-errors\": 50, \n"