From: Francis Dupont Date: Tue, 13 Jul 2021 09:59:05 +0000 (+0200) Subject: [#1950] Added extended configured UT X-Git-Tag: Kea-1.9.10~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3ac82c0c8a3325452f348a132c57fc56a71dfcf2;p=thirdparty%2Fkea.git [#1950] Added extended configured UT --- diff --git a/configure.ac b/configure.ac index 3520af5c08..6e77decc05 100644 --- a/configure.ac +++ b/configure.ac @@ -1673,7 +1673,8 @@ AC_CONFIG_FILES([src/bin/d2/Makefile]) AC_CONFIG_FILES([src/bin/d2/tests/Makefile]) AC_CONFIG_FILES([src/bin/d2/tests/d2_process_tests.sh], [chmod +x src/bin/d2/tests/d2_process_tests.sh]) -AC_CONFIG_FILES([src/bin/d2/tests/test_libraries.h]) +AC_CONFIG_FILES([src/bin/d2/tests/test_callout_libraries.h]) +AC_CONFIG_FILES([src/bin/d2/tests/test_configured_libraries.h]) AC_CONFIG_FILES([src/bin/d2/tests/test_data_files_config.h]) AC_CONFIG_FILES([src/bin/dhcp4/Makefile]) AC_CONFIG_FILES([src/bin/dhcp4/tests/Makefile]) diff --git a/src/bin/d2/d2_process.cc b/src/bin/d2/d2_process.cc index a85607a9d0..f6f2a32cb5 100644 --- a/src/bin/d2/d2_process.cc +++ b/src/bin/d2/d2_process.cc @@ -287,6 +287,8 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) { // The config can be rejected by a hook. if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) { callout_handle->getArgument("error", error); + LOG_ERROR(d2_logger, DHCP_DDNS_CONFIGURED_CALLOUT_DROP) + .arg(error); reconf_queue_flag_ = false; answer = isc::config::createAnswer(1, error); return (answer); diff --git a/src/bin/d2/tests/.gitignore b/src/bin/d2/tests/.gitignore index 25b3812884..fa28318a7e 100644 --- a/src/bin/d2/tests/.gitignore +++ b/src/bin/d2/tests/.gitignore @@ -1,4 +1,5 @@ /d2_process_tests.sh /d2_unittests /test_data_files_config.h -/test_libraries.h +/test_callout_libraries.h +/test_configured_libraries.h diff --git a/src/bin/d2/tests/Makefile.am b/src/bin/d2/tests/Makefile.am index 9f8673a296..2d0013561c 100644 --- a/src/bin/d2/tests/Makefile.am +++ b/src/bin/d2/tests/Makefile.am @@ -108,11 +108,25 @@ libcallout_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la libcallout_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la libcallout_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere -noinst_LTLIBRARIES = libcallout.la +# The d2_srv_configured callout library +libconfigured_la_SOURCES = configured_library.cc +libconfigured_la_CXXFLAGS = $(AM_CXXFLAGS) +libconfigured_la_CPPFLAGS = $(AM_CPPFLAGS) +libconfigured_la_LIBADD = $(top_builddir)/src/lib/hooks/libkea-hooks.la +libconfigured_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la +libconfigured_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +libconfigured_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la +libconfigured_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la +libconfigured_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +libconfigured_la_LIBADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS) +libconfigured_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere + +noinst_LTLIBRARIES = libcallout.la libconfigured.la nodist_d2_unittests_SOURCES = nodist_d2_unittests_SOURCES += test_data_files_config.h -nodist_d2_unittests_SOURCES += test_libraries.h +nodist_d2_unittests_SOURCES += test_callout_libraries.h +nodist_d2_unittests_SOURCES += test_configured_libraries.h # Run C++ tests on "make check". TESTS += $(PROGRAM_TESTS) @@ -121,7 +135,8 @@ TESTS += $(PROGRAM_TESTS) # "make distclean", but not on "make clean". DISTCLEANFILES += d2_process_tests.sh DISTCLEANFILES += test_data_files_config.h -DISTCLEANFILES += test_libraries.h +DISTCLEANFILES += test_callout_libraries.h +DISTCLEANFILES += test_configured_libraries.h # Don't install C++ tests. noinst_PROGRAMS = $(PROGRAM_TESTS) diff --git a/src/bin/d2/tests/configured_library.cc b/src/bin/d2/tests/configured_library.cc new file mode 100644 index 0000000000..6bf872f636 --- /dev/null +++ b/src/bin/d2/tests/configured_library.cc @@ -0,0 +1,63 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// @brief d2_srv_configured callout testing library + +#include +#include +#include + +using namespace isc::data; +using namespace isc::hooks; +using namespace std; + +namespace { + +extern "C" { + +// d2_srv_configured callout. +int +d2_srv_configured(CalloutHandle& handle) { + // Get the parameters. + ConstElementPtr cfg; + string error; + handle.getArgument("json_config", cfg); + handle.getArgument("error", error); + + if (cfg) { + ConstElementPtr uc = cfg->get("user-context"); + if (uc) { + ConstElementPtr msg = uc->get("error"); + if (msg && (msg->getType() == Element::string)) { + error = msg->stringValue(); + } + } + } + + if (!error.empty()) { + handle.setArgument("error", error); + handle.setStatus(CalloutHandle::NEXT_STEP_DROP); + } + return (0); +} + +// Framework functions. +int +version() { + return (KEA_HOOKS_VERSION); +} + +// load() initializes the user library if the main image was statically linked. +int +load(isc::hooks::LibraryHandle&) { +#ifdef USE_STATIC_LINK + hooksStaticLinkInit(); +#endif + return (0); +} + +} +} diff --git a/src/bin/d2/tests/d2_cfg_mgr_unittests.cc b/src/bin/d2/tests/d2_cfg_mgr_unittests.cc index 3bb348abfa..5e27ff8a5c 100644 --- a/src/bin/d2/tests/d2_cfg_mgr_unittests.cc +++ b/src/bin/d2/tests/d2_cfg_mgr_unittests.cc @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/bin/d2/tests/d2_process_unittests.cc b/src/bin/d2/tests/d2_process_unittests.cc index 5a60b464a9..992c533fb6 100644 --- a/src/bin/d2/tests/d2_process_unittests.cc +++ b/src/bin/d2/tests/d2_process_unittests.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ using namespace std; using namespace isc; using namespace isc::config; using namespace isc::d2; +using namespace isc::data; using namespace isc::process; using namespace boost::posix_time; @@ -70,7 +72,7 @@ public: /// @brief Callback that will invoke shutdown method. void genShutdownCallback() { - shutdown(isc::data::ConstElementPtr()); + shutdown(ConstElementPtr()); } /// @brief Callback that throws an exception. @@ -95,8 +97,8 @@ public: return res; } - isc::data::ConstElementPtr answer = configure(config_set_, false); - isc::data::ConstElementPtr comment; + ConstElementPtr answer = configure(config_set_, false); + ConstElementPtr comment; comment = isc::config::parseAnswer(rcode, answer); if (rcode) { @@ -130,6 +132,17 @@ public: setShutdownType(shutdown_type); return (canShutdown()); } + + /// @brief Replaces %LIBRARY% with specified library name. + /// + /// @param config input config text (should contain "%LIBRARY%" string). + /// @param lib_name %LIBRARY% will be replaced with that name. + /// @return configuration text with library name replaced. + string pathReplacer(const char* config, const char* lib_name) { + string txt(config); + txt.replace(txt.find("%LIBRARY%"), strlen("%LIBRARY%"), string(lib_name)); + return (txt); + } }; /// @brief Verifies D2Process construction behavior. @@ -182,7 +195,7 @@ TEST_F(D2ProcessTest, configure) { ASSERT_TRUE(fromJSON(valid_d2_config)); // Invoke configure() with a valid D2 configuration. - isc::data::ConstElementPtr answer = configure(config_set_, false); + ConstElementPtr answer = configure(config_set_, false); // Verify that configure result is success and reconfigure queue manager // flag is true. @@ -268,7 +281,6 @@ TEST_F(D2ProcessTest, queueStopOnReconf) { ASSERT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState()); } - /// @brief Tests checkQueueStatus() logic for recovering from queue full /// This test manually creates a receive queue full condition and then /// "drains" the queue until the queue manager resumes listening. This @@ -371,7 +383,7 @@ TEST_F(D2ProcessTest, badConfigureRecovery) { // Invoke configure() with a valid config that contains an unusable IP ASSERT_TRUE(fromJSON(bad_ip_d2_config)); - isc::data::ConstElementPtr answer = configure(config_set_, false); + ConstElementPtr answer = configure(config_set_, false); // Verify that configure result is success and reconfigure queue manager // flag is true. @@ -411,8 +423,8 @@ TEST_F(D2ProcessTest, badConfigureRecovery) { /// success response; and for invalid values: sets the shutdown flag to false /// and returns a failure response. TEST_F(D2ProcessTest, shutdownArgs) { - isc::data::ElementPtr args; - isc::data::ConstElementPtr answer; + ElementPtr args; + ConstElementPtr answer; const char* default_args = "{}"; const char* normal_args = "{ \"type\" : \"normal\" }"; const char* drain_args = "{ \"type\" : \"drain_first\" }"; @@ -420,35 +432,35 @@ TEST_F(D2ProcessTest, shutdownArgs) { const char* bogus_args = "{ \"type\" : \"bogus\" }"; // Verify defaulting to SD_NORMAL if no argument is given. - ASSERT_NO_THROW(args = isc::data::Element::fromJSON(default_args)); + ASSERT_NO_THROW(args = Element::fromJSON(default_args)); EXPECT_NO_THROW(answer = shutdown(args)); ASSERT_TRUE(checkAnswer(answer, 0)); EXPECT_EQ(SD_NORMAL, getShutdownType()); EXPECT_TRUE(shouldShutdown()); // Verify argument value "normal". - ASSERT_NO_THROW(args = isc::data::Element::fromJSON(normal_args)); + ASSERT_NO_THROW(args = Element::fromJSON(normal_args)); EXPECT_NO_THROW(answer = shutdown(args)); ASSERT_TRUE(checkAnswer(answer, 0)); EXPECT_EQ(SD_NORMAL, getShutdownType()); EXPECT_TRUE(shouldShutdown()); // Verify argument value "drain_first". - ASSERT_NO_THROW(args = isc::data::Element::fromJSON(drain_args)); + ASSERT_NO_THROW(args = Element::fromJSON(drain_args)); EXPECT_NO_THROW(answer = shutdown(args)); ASSERT_TRUE(checkAnswer(answer, 0)); EXPECT_EQ(SD_DRAIN_FIRST, getShutdownType()); EXPECT_TRUE(shouldShutdown()); // Verify argument value "now". - ASSERT_NO_THROW(args = isc::data::Element::fromJSON(now_args)); + ASSERT_NO_THROW(args = Element::fromJSON(now_args)); EXPECT_NO_THROW(answer = shutdown(args)); ASSERT_TRUE(checkAnswer(answer, 0)); EXPECT_EQ(SD_NOW, getShutdownType()); EXPECT_TRUE(shouldShutdown()); // Verify correct handling of an invalid value. - ASSERT_NO_THROW(args = isc::data::Element::fromJSON(bogus_args)); + ASSERT_NO_THROW(args = Element::fromJSON(bogus_args)); EXPECT_NO_THROW(answer = shutdown(args)); ASSERT_TRUE(checkAnswer(answer, 1)); EXPECT_FALSE(shouldShutdown()); @@ -544,7 +556,6 @@ TEST_F(D2ProcessTest, canShutdown) { EXPECT_TRUE(checkCanShutdown(SD_NOW)); } - /// @brief Verifies that an "external" call to shutdown causes the run method /// to exit gracefully. TEST_F(D2ProcessTest, normalShutdown) { @@ -569,7 +580,6 @@ TEST_F(D2ProcessTest, normalShutdown) { elapsed.total_milliseconds() <= 2200); } - /// @brief Verifies that an "uncaught" exception thrown during event loop /// execution is treated as a fatal error. TEST_F(D2ProcessTest, fatalErrorShutdown) { @@ -612,7 +622,6 @@ TEST_F(D2ProcessTest, notLoopbackTest) { runWithConfig(config); } - /// @brief Used to permit visual inspection of logs to ensure /// DHCP_DDNS_NOT_ON_LOOPBACK is not issued. TEST_F(D2ProcessTest, v4LoopbackTest) { @@ -639,4 +648,46 @@ TEST_F(D2ProcessTest, v6LoopbackTest) { ASSERT_TRUE(runWithConfig(config)); } +/// @brief Check the configured callout (positive case). +TEST_F(D2ProcessTest, configuredNoFail) { + const char* config = "{\n" + "\"hooks-libraries\": [ {\n" + " \"library\": \"%LIBRARY%\",\n" + " \"parameters\": {\n" + " } } ] }\n"; + string cfg = pathReplacer(config, CONFIGURED_LIBRARY); + + ConstElementPtr json; + ASSERT_NO_THROW(json = Element::fromJSON(cfg)); + ConstElementPtr answer; + ASSERT_NO_THROW(answer = configure(json, false)); + int rcode = -1; + ConstElementPtr comment; + comment = isc::config::parseAnswer(rcode, answer); + EXPECT_EQ(0, rcode) << comment->str(); +} + +/// @brief Check the configured callout (negative case). +TEST_F(D2ProcessTest, configuredFail) { + const char* config = "{\n" + "\"user-context\": { \"error\": \"Fail!\" },\n" + "\"hooks-libraries\": [ {\n" + " \"library\": \"%LIBRARY%\",\n" + " \"parameters\": {\n" + " } } ] }\n"; + string cfg = pathReplacer(config, CONFIGURED_LIBRARY); + + ConstElementPtr json; + ASSERT_NO_THROW(json = Element::fromJSON(cfg)); + ConstElementPtr answer; + ASSERT_NO_THROW(answer = configure(json, false)); + int rcode = -1; + ConstElementPtr comment; + comment = isc::config::parseAnswer(rcode, answer); + EXPECT_EQ(1, rcode); + ASSERT_TRUE(comment); + ASSERT_EQ(Element::string, comment->getType()); + EXPECT_EQ("Fail!", comment->stringValue()); +} + } // end of anonymous namespace diff --git a/src/bin/d2/tests/get_config_unittest.cc b/src/bin/d2/tests/get_config_unittest.cc index 3f265beabc..0936e82160 100644 --- a/src/bin/d2/tests/get_config_unittest.cc +++ b/src/bin/d2/tests/get_config_unittest.cc @@ -21,7 +21,7 @@ #include #include "test_data_files_config.h" -#include "test_libraries.h" +#include "test_callout_libraries.h" using namespace isc::config; using namespace isc::d2; diff --git a/src/bin/d2/tests/test_libraries.h.in b/src/bin/d2/tests/test_callout_libraries.h.in similarity index 87% rename from src/bin/d2/tests/test_libraries.h.in rename to src/bin/d2/tests/test_callout_libraries.h.in index 983aa1619b..a88d131011 100644 --- a/src/bin/d2/tests/test_libraries.h.in +++ b/src/bin/d2/tests/test_callout_libraries.h.in @@ -4,8 +4,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -#ifndef D2_TEST_LIBRARIES_H -#define D2_TEST_LIBRARIES_H +#ifndef D2_TEST_CALLOUT_LIBRARIES_H +#define D2_TEST_CALLOUT_LIBRARIES_H #include @@ -21,4 +21,4 @@ static const char* CALLOUT_LIBRARY = "@abs_builddir@/.libs/libcallout.so"; } // anonymous namespace -#endif // D2_TEST_LIBRARIES_H +#endif // D2_TEST_CALLOUT_LIBRARIES_H diff --git a/src/bin/d2/tests/test_configured_libraries.h.in b/src/bin/d2/tests/test_configured_libraries.h.in new file mode 100644 index 0000000000..2b235ae68f --- /dev/null +++ b/src/bin/d2/tests/test_configured_libraries.h.in @@ -0,0 +1,26 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef D2_TEST_CONFIGURED_LIBRARIES_H +#define D2_TEST_CONFIGURED_LIBRARIES_H + +#include + +namespace { + +// Names of the libraries used in these tests. These libraries are built using +// libtool, so we need to look in the hidden ".libs" directory to locate the +// .so file. Note that we access the .so file - libtool creates this as a +// like to the real shared library. + +// Configured library with d2_srv_configured testing: if there is a toplevel +// user context with an error entry the returned status is DROP with the +// content of the error entry. +static const char* CONFIGURED_LIBRARY = "@abs_builddir@/.libs/libconfigured.so"; + +} // anonymous namespace + +#endif // D2_TEST_CONFIGURED_LIBRARIES_H diff --git a/src/lib/d2srv/d2_messages.cc b/src/lib/d2srv/d2_messages.cc index 3a36be2391..74b7d14bf4 100644 --- a/src/lib/d2srv/d2_messages.cc +++ b/src/lib/d2srv/d2_messages.cc @@ -14,6 +14,7 @@ extern const isc::log::MessageID DHCP_DDNS_AT_MAX_TRANSACTIONS = "DHCP_DDNS_AT_M extern const isc::log::MessageID DHCP_DDNS_CLEARED_FOR_SHUTDOWN = "DHCP_DDNS_CLEARED_FOR_SHUTDOWN"; extern const isc::log::MessageID DHCP_DDNS_COMMAND = "DHCP_DDNS_COMMAND"; extern const isc::log::MessageID DHCP_DDNS_CONFIGURE = "DHCP_DDNS_CONFIGURE"; +extern const isc::log::MessageID DHCP_DDNS_CONFIGURED_CALLOUT_DROP = "DHCP_DDNS_CONFIGURED_CALLOUT_DROP"; extern const isc::log::MessageID DHCP_DDNS_CONFIG_CHECK_FAIL = "DHCP_DDNS_CONFIG_CHECK_FAIL"; extern const isc::log::MessageID DHCP_DDNS_CONFIG_FAIL = "DHCP_DDNS_CONFIG_FAIL"; extern const isc::log::MessageID DHCP_DDNS_FAILED = "DHCP_DDNS_FAILED"; @@ -95,6 +96,7 @@ const char* values[] = { "DHCP_DDNS_CLEARED_FOR_SHUTDOWN", "application has met shutdown criteria for shutdown type: %1", "DHCP_DDNS_COMMAND", "command directive received, command: %1 - args: %2", "DHCP_DDNS_CONFIGURE", "configuration %1 received: %2", + "DHCP_DDNS_CONFIGURED_CALLOUT_DROP", "configuration was rejected because a callout set the next step to 'drop': %1", "DHCP_DDNS_CONFIG_CHECK_FAIL", "DHCP-DDNS server configuration check failed: %1", "DHCP_DDNS_CONFIG_FAIL", "DHCP-DDNS server configuration failed: %1", "DHCP_DDNS_FAILED", "application experienced a fatal error: %1", diff --git a/src/lib/d2srv/d2_messages.h b/src/lib/d2srv/d2_messages.h index c69453e13a..cfa5c3fe2f 100644 --- a/src/lib/d2srv/d2_messages.h +++ b/src/lib/d2srv/d2_messages.h @@ -15,6 +15,7 @@ extern const isc::log::MessageID DHCP_DDNS_AT_MAX_TRANSACTIONS; extern const isc::log::MessageID DHCP_DDNS_CLEARED_FOR_SHUTDOWN; extern const isc::log::MessageID DHCP_DDNS_COMMAND; extern const isc::log::MessageID DHCP_DDNS_CONFIGURE; +extern const isc::log::MessageID DHCP_DDNS_CONFIGURED_CALLOUT_DROP; extern const isc::log::MessageID DHCP_DDNS_CONFIG_CHECK_FAIL; extern const isc::log::MessageID DHCP_DDNS_CONFIG_FAIL; extern const isc::log::MessageID DHCP_DDNS_FAILED; diff --git a/src/lib/d2srv/d2_messages.mes b/src/lib/d2srv/d2_messages.mes index 4b3d47dd0a..cb62f9010b 100644 --- a/src/lib/d2srv/d2_messages.mes +++ b/src/lib/d2srv/d2_messages.mes @@ -41,6 +41,11 @@ has been invoked. This is a debug message issued when the DHCP-DDNS application configure method has been invoked. +% DHCP_DDNS_CONFIGURED_CALLOUT_DROP configuration was rejected because a callout set the next step to 'drop': %1 +This error message indicates that the DHCP-DDNS had failed configuration +attempt because the next stop of the configured callout was set to 'drop' +by a hook library. The error message provided by the hook library is displayed. + % DHCP_DDNS_CONFIG_CHECK_FAIL DHCP-DDNS server configuration check failed: %1 This error message indicates that the DHCP-DDNS had failed configuration check. Details are provided. Additional details may be available