]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1950] Added extended configured UT
authorFrancis Dupont <fdupont@isc.org>
Tue, 13 Jul 2021 09:59:05 +0000 (11:59 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 13 Jul 2021 09:59:05 +0000 (11:59 +0200)
13 files changed:
configure.ac
src/bin/d2/d2_process.cc
src/bin/d2/tests/.gitignore
src/bin/d2/tests/Makefile.am
src/bin/d2/tests/configured_library.cc [new file with mode: 0644]
src/bin/d2/tests/d2_cfg_mgr_unittests.cc
src/bin/d2/tests/d2_process_unittests.cc
src/bin/d2/tests/get_config_unittest.cc
src/bin/d2/tests/test_callout_libraries.h.in [moved from src/bin/d2/tests/test_libraries.h.in with 87% similarity]
src/bin/d2/tests/test_configured_libraries.h.in [new file with mode: 0644]
src/lib/d2srv/d2_messages.cc
src/lib/d2srv/d2_messages.h
src/lib/d2srv/d2_messages.mes

index 3520af5c08e5b3ac02b19ad92eb884c4a25875f6..6e77decc052c06b50209f9bedb442d21375ce643 100644 (file)
@@ -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])
index a85607a9d013792c2122c2693f87bf9fcd7b9f3b..f6f2a32cb585a0075769ea0d8f829848845de726 100644 (file)
@@ -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);
index 25b3812884aabec64c09e32e6d9842ba4db08a8d..fa28318a7efd7f991412db7af9410185401c97b1 100644 (file)
@@ -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
index 9f8673a2966e17244db648c5eea1a7f5da9b3ab5..2d0013561c070b95f5c5345ea8fcffe7fd830241 100644 (file)
@@ -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 (file)
index 0000000..6bf872f
--- /dev/null
@@ -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 <config.h>
+#include <cc/data.h>
+#include <hooks/hooks.h>
+
+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);
+}
+
+}
+}
index 3bb348abfa4320c877bf7c0baf28689038f877d7..5e27ff8a5c2a07806b591ffb763443a27c577138 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <d2/parser_context.h>
 #include <d2/tests/parser_unittest.h>
-#include <d2/tests/test_libraries.h>
+#include <d2/tests/test_callout_libraries.h>
 #include <d2srv/d2_cfg_mgr.h>
 #include <d2srv/d2_config.h>
 #include <d2srv/d2_simple_parser.h>
index 5a60b464a976fa47d0c503f0ebcc0e18d75967be..992c533fb669e91ff8f6aba4ecca14f29c69d432 100644 (file)
@@ -12,6 +12,7 @@
 #include <dhcp_ddns/ncr_io.h>
 #include <process/testutils/d_test_stubs.h>
 #include <d2/tests/nc_test_utils.h>
+#include <d2/tests/test_configured_libraries.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <gtest/gtest.h>
@@ -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
index 3f265beabcfa3301f146e68f8f08464c060fdbcd..0936e82160d26298761813bcf6c7ca6e604f1160 100644 (file)
@@ -21,7 +21,7 @@
 #include <sstream>
 
 #include "test_data_files_config.h"
-#include "test_libraries.h"
+#include "test_callout_libraries.h"
 
 using namespace isc::config;
 using namespace isc::d2;
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 983aa1619bea5a274551ac9839977ab0cf97edb7..a88d131011acd2fa16339ce6830258508f91253e 100644 (file)
@@ -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 <config.h>
 
@@ -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 (file)
index 0000000..2b235ae
--- /dev/null
@@ -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 <config.h>
+
+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
index 3a36be2391d3ce6387b07505cae529aa229984e6..74b7d14bf4402ef711b7ec97b1a4cc685138f6b1 100644 (file)
@@ -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",
index c69453e13ae94d91bf7ce6332785d61083baba6a..cfa5c3fe2f8c89ea2faa684df03ebac68a37ba2b 100644 (file)
@@ -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;
index 4b3d47dd0a0828a2766e8b4940f2a1e829044420..cb62f9010b1d8e15e91a9bf6e6b18a940b90d3c6 100644 (file)
@@ -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