summaryrefslogtreecommitdiffstats
path: root/src/lib/hooks/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hooks/tests')
-rw-r--r--src/lib/hooks/tests/Makefile.am152
-rw-r--r--src/lib/hooks/tests/Makefile.in1547
-rw-r--r--src/lib/hooks/tests/async_callout_library.cc153
-rw-r--r--src/lib/hooks/tests/basic_callout_library.cc145
-rw-r--r--src/lib/hooks/tests/callout_handle_associate_unittest.cc35
-rw-r--r--src/lib/hooks/tests/callout_handle_unittest.cc384
-rw-r--r--src/lib/hooks/tests/callout_manager_unittest.cc944
-rw-r--r--src/lib/hooks/tests/callout_params_library.cc129
-rw-r--r--src/lib/hooks/tests/common_test_class.h174
-rw-r--r--src/lib/hooks/tests/framework_exception_library.cc41
-rw-r--r--src/lib/hooks/tests/full_callout_library.cc177
-rw-r--r--src/lib/hooks/tests/handles_unittest.cc777
-rw-r--r--src/lib/hooks/tests/hooks_manager_unittest.cc1081
-rw-r--r--src/lib/hooks/tests/incorrect_version_library.cc26
-rw-r--r--src/lib/hooks/tests/library_manager_collection_unittest.cc314
-rw-r--r--src/lib/hooks/tests/library_manager_unittest.cc735
-rw-r--r--src/lib/hooks/tests/load_callout_library.cc152
-rw-r--r--src/lib/hooks/tests/load_error_callout_library.cc47
-rw-r--r--src/lib/hooks/tests/marker_file.h.in19
-rw-r--r--src/lib/hooks/tests/no_version_library.cc24
-rw-r--r--src/lib/hooks/tests/parking_lots_unittest.cc339
-rw-r--r--src/lib/hooks/tests/run_unittests.cc19
-rw-r--r--src/lib/hooks/tests/server_hooks_unittest.cc232
-rw-r--r--src/lib/hooks/tests/test_libraries.h.in61
-rw-r--r--src/lib/hooks/tests/unload_callout_library.cc46
25 files changed, 7753 insertions, 0 deletions
diff --git a/src/lib/hooks/tests/Makefile.am b/src/lib/hooks/tests/Makefile.am
new file mode 100644
index 0000000..8cbe413
--- /dev/null
+++ b/src/lib/hooks/tests/Makefile.am
@@ -0,0 +1,152 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+# Kea libraries against which the test user libraries are linked.
+HOOKS_LIB = $(top_builddir)/src/lib/hooks/libkea-hooks.la
+LOG_LIB = $(top_builddir)/src/lib/log/libkea-log.la
+UTIL_LIB = $(top_builddir)/src/lib/util/libkea-util.la
+EXCEPTIONS_LIB = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+
+ALL_LIBS = $(HOOKS_LIB) $(LOG_LIB) $(UTIL_LIB) $(EXCEPTIONS_LIB) $(LOG4CPLUS_LIBS)
+
+# Files to clean include the file created by testing.
+CLEANFILES = *.gcno *.gcda $(builddir)/marker_file.dat
+
+# Files generated by configure
+DISTCLEANFILES = marker_file.h test_libraries.h
+
+TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+# Build shared libraries for testing. The libtool way to create a shared library
+# is to specify "-avoid-version -export-dynamic -module" in the library LDFLAGS
+# (see http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html).
+# Use of these switches will guarantee that the .so files are created in the
+# .libs folder and they can be dlopened.
+#
+# Note that the shared libraries with callouts should not be used together with
+# the --enable-static-link option. With this option, the bind10 libraries are
+# statically linked with the program and if the callout invokes the methods
+# which belong to these libraries, the library with the callout will get its
+# own copy of the static objects (e.g. logger, ServerHooks) and that will lead
+# to unexpected errors. For this reason, the --enable-static-link option is
+# ignored for unit tests built here.
+
+noinst_LTLIBRARIES = libnvl.la libivl.la libfxl.la libbcl.la liblcl.la
+noinst_LTLIBRARIES += liblecl.la libucl.la libfcl.la libpcl.la libacl.la
+
+# -rpath /nowhere is a hack to trigger libtool to not create a
+# convenience archive, resulting in shared modules
+
+# No version function
+libnvl_la_SOURCES = no_version_library.cc
+libnvl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libnvl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libnvl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# Incorrect version function
+libivl_la_SOURCES = incorrect_version_library.cc
+libivl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libivl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libivl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# All framework functions throw an exception
+libfxl_la_SOURCES = framework_exception_library.cc
+libfxl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libfxl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libfxl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The basic callout library - contains standard callouts
+libbcl_la_SOURCES = basic_callout_library.cc
+libbcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libbcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libbcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The load callout library - contains a load function
+liblcl_la_SOURCES = load_callout_library.cc
+liblcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+liblcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+liblcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The load error callout library - contains a load function that returns
+# an error.
+liblecl_la_SOURCES = load_error_callout_library.cc
+liblecl_la_CXXFLAGS = $(AM_CXXFLAGS)
+liblecl_la_CPPFLAGS = $(AM_CPPFLAGS)
+liblecl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The unload callout library - contains an unload function that
+# creates a marker file.
+libucl_la_SOURCES = unload_callout_library.cc
+libucl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libucl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libucl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The full callout library - contains all three framework functions.
+libfcl_la_SOURCES = full_callout_library.cc
+libfcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libfcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libfcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The parameters checking callout library - expects
+libpcl_la_SOURCES = callout_params_library.cc
+libpcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libpcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libpcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+libpcl_la_LDFLAGS += $(top_builddir)/src/lib/util/libkea-util.la
+
+# The async callout library - parks object for asynchronous task
+libacl_la_SOURCES = async_callout_library.cc
+libacl_la_CXXFLAGS = $(AM_CXXFLAGS)
+libacl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libacl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += callout_handle_unittest.cc
+run_unittests_SOURCES += callout_handle_associate_unittest.cc
+run_unittests_SOURCES += callout_manager_unittest.cc
+run_unittests_SOURCES += common_test_class.h
+run_unittests_SOURCES += handles_unittest.cc
+run_unittests_SOURCES += hooks_manager_unittest.cc
+run_unittests_SOURCES += library_manager_collection_unittest.cc
+run_unittests_SOURCES += library_manager_unittest.cc
+run_unittests_SOURCES += parking_lots_unittest.cc
+run_unittests_SOURCES += server_hooks_unittest.cc
+
+nodist_run_unittests_SOURCES = marker_file.h
+nodist_run_unittests_SOURCES += test_libraries.h
+
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+if USE_STATIC_LINK
+run_unittests_LDFLAGS += -static -export-dynamic
+endif
+
+run_unittests_LDADD = $(AM_LDADD)
+run_unittests_LDADD += $(ALL_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(GTEST_LDADD) $(LOG4CPLUS_LIBS) $(BOOST_LIBS)
+# As noted in configure.ac, libtool doesn't work perfectly with Darwin: it
+# embeds the final install path in dynamic libraries and loadable modules refer
+# to that path even if its loaded within the source tree, so preventing tests
+# from working - but only when linking statically. The solution used in other
+# Makefiles (setting the path to the dynamic libraries via an environment
+# variable) don't seem to work. What does work is to run the unit test using
+# libtool and specifying paths via -dlopen switches. So... If running in an
+# environment where we have to set the library path AND if linking statically,
+# override the "check" target and run the unit tests ourselves.
+
+endif
+
+noinst_PROGRAMS = $(TESTS)
+
+EXTRA_DIST = marker_file.h.in test_libraries.h.in
diff --git a/src/lib/hooks/tests/Makefile.in b/src/lib/hooks/tests/Makefile.in
new file mode 100644
index 0000000..688124d
--- /dev/null
+++ b/src/lib/hooks/tests/Makefile.in
@@ -0,0 +1,1547 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+TESTS = $(am__EXEEXT_1)
+@HAVE_GTEST_TRUE@am__append_1 = run_unittests
+@HAVE_GTEST_TRUE@@USE_STATIC_LINK_TRUE@am__append_2 = -static -export-dynamic
+noinst_PROGRAMS = $(am__EXEEXT_2)
+subdir = src/lib/hooks/tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_cpp20.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_netconf.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = marker_file.h test_libraries.h
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_GTEST_TRUE@am__EXEEXT_1 = run_unittests$(EXEEXT)
+am__EXEEXT_2 = $(am__EXEEXT_1)
+PROGRAMS = $(noinst_PROGRAMS)
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libacl_la_LIBADD =
+am__libacl_la_SOURCES_DIST = async_callout_library.cc
+@HAVE_GTEST_TRUE@am_libacl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libacl_la-async_callout_library.lo
+libacl_la_OBJECTS = $(am_libacl_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libacl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libacl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libacl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libacl_la_rpath =
+libbcl_la_LIBADD =
+am__libbcl_la_SOURCES_DIST = basic_callout_library.cc
+@HAVE_GTEST_TRUE@am_libbcl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libbcl_la-basic_callout_library.lo
+libbcl_la_OBJECTS = $(am_libbcl_la_OBJECTS)
+libbcl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libbcl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libbcl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libbcl_la_rpath =
+libfcl_la_LIBADD =
+am__libfcl_la_SOURCES_DIST = full_callout_library.cc
+@HAVE_GTEST_TRUE@am_libfcl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libfcl_la-full_callout_library.lo
+libfcl_la_OBJECTS = $(am_libfcl_la_OBJECTS)
+libfcl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libfcl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libfcl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libfcl_la_rpath =
+libfxl_la_LIBADD =
+am__libfxl_la_SOURCES_DIST = framework_exception_library.cc
+@HAVE_GTEST_TRUE@am_libfxl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libfxl_la-framework_exception_library.lo
+libfxl_la_OBJECTS = $(am_libfxl_la_OBJECTS)
+libfxl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libfxl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libfxl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libfxl_la_rpath =
+libivl_la_LIBADD =
+am__libivl_la_SOURCES_DIST = incorrect_version_library.cc
+@HAVE_GTEST_TRUE@am_libivl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libivl_la-incorrect_version_library.lo
+libivl_la_OBJECTS = $(am_libivl_la_OBJECTS)
+libivl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libivl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libivl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libivl_la_rpath =
+liblcl_la_LIBADD =
+am__liblcl_la_SOURCES_DIST = load_callout_library.cc
+@HAVE_GTEST_TRUE@am_liblcl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ liblcl_la-load_callout_library.lo
+liblcl_la_OBJECTS = $(am_liblcl_la_OBJECTS)
+liblcl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(liblcl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(liblcl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_liblcl_la_rpath =
+liblecl_la_LIBADD =
+am__liblecl_la_SOURCES_DIST = load_error_callout_library.cc
+@HAVE_GTEST_TRUE@am_liblecl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ liblecl_la-load_error_callout_library.lo
+liblecl_la_OBJECTS = $(am_liblecl_la_OBJECTS)
+liblecl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(liblecl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(liblecl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_liblecl_la_rpath =
+libnvl_la_LIBADD =
+am__libnvl_la_SOURCES_DIST = no_version_library.cc
+@HAVE_GTEST_TRUE@am_libnvl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libnvl_la-no_version_library.lo
+libnvl_la_OBJECTS = $(am_libnvl_la_OBJECTS)
+libnvl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libnvl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libnvl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libnvl_la_rpath =
+libpcl_la_LIBADD =
+am__libpcl_la_SOURCES_DIST = callout_params_library.cc
+@HAVE_GTEST_TRUE@am_libpcl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libpcl_la-callout_params_library.lo
+libpcl_la_OBJECTS = $(am_libpcl_la_OBJECTS)
+libpcl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libpcl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libpcl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libpcl_la_rpath =
+libucl_la_LIBADD =
+am__libucl_la_SOURCES_DIST = unload_callout_library.cc
+@HAVE_GTEST_TRUE@am_libucl_la_OBJECTS = \
+@HAVE_GTEST_TRUE@ libucl_la-unload_callout_library.lo
+libucl_la_OBJECTS = $(am_libucl_la_OBJECTS)
+libucl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libucl_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libucl_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_GTEST_TRUE@am_libucl_la_rpath =
+am__run_unittests_SOURCES_DIST = run_unittests.cc \
+ callout_handle_unittest.cc \
+ callout_handle_associate_unittest.cc \
+ callout_manager_unittest.cc common_test_class.h \
+ handles_unittest.cc hooks_manager_unittest.cc \
+ library_manager_collection_unittest.cc \
+ library_manager_unittest.cc parking_lots_unittest.cc \
+ server_hooks_unittest.cc
+@HAVE_GTEST_TRUE@am_run_unittests_OBJECTS = \
+@HAVE_GTEST_TRUE@ run_unittests-run_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-callout_handle_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-callout_handle_associate_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-callout_manager_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-handles_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-hooks_manager_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-library_manager_collection_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-library_manager_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-parking_lots_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-server_hooks_unittest.$(OBJEXT)
+nodist_run_unittests_OBJECTS =
+run_unittests_OBJECTS = $(am_run_unittests_OBJECTS) \
+ $(nodist_run_unittests_OBJECTS)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = $(HOOKS_LIB) $(LOG_LIB) $(UTIL_LIB) \
+ $(EXCEPTIONS_LIB) $(am__DEPENDENCIES_1)
+@HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1)
+run_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(run_unittests_CXXFLAGS) $(CXXFLAGS) $(run_unittests_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/libacl_la-async_callout_library.Plo \
+ ./$(DEPDIR)/libbcl_la-basic_callout_library.Plo \
+ ./$(DEPDIR)/libfcl_la-full_callout_library.Plo \
+ ./$(DEPDIR)/libfxl_la-framework_exception_library.Plo \
+ ./$(DEPDIR)/libivl_la-incorrect_version_library.Plo \
+ ./$(DEPDIR)/liblcl_la-load_callout_library.Plo \
+ ./$(DEPDIR)/liblecl_la-load_error_callout_library.Plo \
+ ./$(DEPDIR)/libnvl_la-no_version_library.Plo \
+ ./$(DEPDIR)/libpcl_la-callout_params_library.Plo \
+ ./$(DEPDIR)/libucl_la-unload_callout_library.Plo \
+ ./$(DEPDIR)/run_unittests-callout_handle_associate_unittest.Po \
+ ./$(DEPDIR)/run_unittests-callout_handle_unittest.Po \
+ ./$(DEPDIR)/run_unittests-callout_manager_unittest.Po \
+ ./$(DEPDIR)/run_unittests-handles_unittest.Po \
+ ./$(DEPDIR)/run_unittests-hooks_manager_unittest.Po \
+ ./$(DEPDIR)/run_unittests-library_manager_collection_unittest.Po \
+ ./$(DEPDIR)/run_unittests-library_manager_unittest.Po \
+ ./$(DEPDIR)/run_unittests-parking_lots_unittest.Po \
+ ./$(DEPDIR)/run_unittests-run_unittests.Po \
+ ./$(DEPDIR)/run_unittests-server_hooks_unittest.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libacl_la_SOURCES) $(libbcl_la_SOURCES) \
+ $(libfcl_la_SOURCES) $(libfxl_la_SOURCES) $(libivl_la_SOURCES) \
+ $(liblcl_la_SOURCES) $(liblecl_la_SOURCES) \
+ $(libnvl_la_SOURCES) $(libpcl_la_SOURCES) $(libucl_la_SOURCES) \
+ $(run_unittests_SOURCES) $(nodist_run_unittests_SOURCES)
+DIST_SOURCES = $(am__libacl_la_SOURCES_DIST) \
+ $(am__libbcl_la_SOURCES_DIST) $(am__libfcl_la_SOURCES_DIST) \
+ $(am__libfxl_la_SOURCES_DIST) $(am__libivl_la_SOURCES_DIST) \
+ $(am__liblcl_la_SOURCES_DIST) $(am__liblecl_la_SOURCES_DIST) \
+ $(am__libnvl_la_SOURCES_DIST) $(am__libpcl_la_SOURCES_DIST) \
+ $(am__libucl_la_SOURCES_DIST) \
+ $(am__run_unittests_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/marker_file.h.in \
+ $(srcdir)/test_libraries.h.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@
+DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@
+DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_NETCONF = @HAVE_NETCONF@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@
+LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@
+LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@
+LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@
+LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@
+LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@
+LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@
+LIBYANG_LIBS = @LIBYANG_LIBS@
+LIBYANG_PREFIX = @LIBYANG_PREFIX@
+LIBYANG_VERSION = @LIBYANG_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_PLUGINS_PATH = @SR_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@
+SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@
+SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@
+SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_PREFIX = @SYSREPO_PREFIX@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = .
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \
+ $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+# Kea libraries against which the test user libraries are linked.
+HOOKS_LIB = $(top_builddir)/src/lib/hooks/libkea-hooks.la
+LOG_LIB = $(top_builddir)/src/lib/log/libkea-log.la
+UTIL_LIB = $(top_builddir)/src/lib/util/libkea-util.la
+EXCEPTIONS_LIB = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+ALL_LIBS = $(HOOKS_LIB) $(LOG_LIB) $(UTIL_LIB) $(EXCEPTIONS_LIB) $(LOG4CPLUS_LIBS)
+
+# Files to clean include the file created by testing.
+CLEANFILES = *.gcno *.gcda $(builddir)/marker_file.dat
+
+# Files generated by configure
+DISTCLEANFILES = marker_file.h test_libraries.h
+TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+# Build shared libraries for testing. The libtool way to create a shared library
+# is to specify "-avoid-version -export-dynamic -module" in the library LDFLAGS
+# (see http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html).
+# Use of these switches will guarantee that the .so files are created in the
+# .libs folder and they can be dlopened.
+#
+# Note that the shared libraries with callouts should not be used together with
+# the --enable-static-link option. With this option, the bind10 libraries are
+# statically linked with the program and if the callout invokes the methods
+# which belong to these libraries, the library with the callout will get its
+# own copy of the static objects (e.g. logger, ServerHooks) and that will lead
+# to unexpected errors. For this reason, the --enable-static-link option is
+# ignored for unit tests built here.
+@HAVE_GTEST_TRUE@noinst_LTLIBRARIES = libnvl.la libivl.la libfxl.la \
+@HAVE_GTEST_TRUE@ libbcl.la liblcl.la liblecl.la libucl.la \
+@HAVE_GTEST_TRUE@ libfcl.la libpcl.la libacl.la
+
+# -rpath /nowhere is a hack to trigger libtool to not create a
+# convenience archive, resulting in shared modules
+
+# No version function
+@HAVE_GTEST_TRUE@libnvl_la_SOURCES = no_version_library.cc
+@HAVE_GTEST_TRUE@libnvl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libnvl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libnvl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# Incorrect version function
+@HAVE_GTEST_TRUE@libivl_la_SOURCES = incorrect_version_library.cc
+@HAVE_GTEST_TRUE@libivl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libivl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libivl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# All framework functions throw an exception
+@HAVE_GTEST_TRUE@libfxl_la_SOURCES = framework_exception_library.cc
+@HAVE_GTEST_TRUE@libfxl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libfxl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libfxl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The basic callout library - contains standard callouts
+@HAVE_GTEST_TRUE@libbcl_la_SOURCES = basic_callout_library.cc
+@HAVE_GTEST_TRUE@libbcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libbcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libbcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The load callout library - contains a load function
+@HAVE_GTEST_TRUE@liblcl_la_SOURCES = load_callout_library.cc
+@HAVE_GTEST_TRUE@liblcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@liblcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@liblcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The load error callout library - contains a load function that returns
+# an error.
+@HAVE_GTEST_TRUE@liblecl_la_SOURCES = load_error_callout_library.cc
+@HAVE_GTEST_TRUE@liblecl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@liblecl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@liblecl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The unload callout library - contains an unload function that
+# creates a marker file.
+@HAVE_GTEST_TRUE@libucl_la_SOURCES = unload_callout_library.cc
+@HAVE_GTEST_TRUE@libucl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libucl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libucl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The full callout library - contains all three framework functions.
+@HAVE_GTEST_TRUE@libfcl_la_SOURCES = full_callout_library.cc
+@HAVE_GTEST_TRUE@libfcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libfcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libfcl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+
+# The parameters checking callout library - expects
+@HAVE_GTEST_TRUE@libpcl_la_SOURCES = callout_params_library.cc
+@HAVE_GTEST_TRUE@libpcl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libpcl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libpcl_la_LDFLAGS = -avoid-version -export-dynamic \
+@HAVE_GTEST_TRUE@ -module -rpath /nowhere \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la
+
+# The async callout library - parks object for asynchronous task
+@HAVE_GTEST_TRUE@libacl_la_SOURCES = async_callout_library.cc
+@HAVE_GTEST_TRUE@libacl_la_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libacl_la_CPPFLAGS = $(AM_CPPFLAGS)
+@HAVE_GTEST_TRUE@libacl_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
+@HAVE_GTEST_TRUE@run_unittests_SOURCES = run_unittests.cc \
+@HAVE_GTEST_TRUE@ callout_handle_unittest.cc \
+@HAVE_GTEST_TRUE@ callout_handle_associate_unittest.cc \
+@HAVE_GTEST_TRUE@ callout_manager_unittest.cc \
+@HAVE_GTEST_TRUE@ common_test_class.h handles_unittest.cc \
+@HAVE_GTEST_TRUE@ hooks_manager_unittest.cc \
+@HAVE_GTEST_TRUE@ library_manager_collection_unittest.cc \
+@HAVE_GTEST_TRUE@ library_manager_unittest.cc \
+@HAVE_GTEST_TRUE@ parking_lots_unittest.cc \
+@HAVE_GTEST_TRUE@ server_hooks_unittest.cc
+@HAVE_GTEST_TRUE@nodist_run_unittests_SOURCES = marker_file.h \
+@HAVE_GTEST_TRUE@ test_libraries.h
+@HAVE_GTEST_TRUE@run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+@HAVE_GTEST_TRUE@run_unittests_LDFLAGS = $(AM_LDFLAGS) \
+@HAVE_GTEST_TRUE@ $(GTEST_LDFLAGS) $(am__append_2)
+@HAVE_GTEST_TRUE@run_unittests_LDADD = $(AM_LDADD) $(ALL_LIBS) \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \
+@HAVE_GTEST_TRUE@ $(GTEST_LDADD) $(LOG4CPLUS_LIBS) \
+@HAVE_GTEST_TRUE@ $(BOOST_LIBS)
+EXTRA_DIST = marker_file.h.in test_libraries.h.in
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/hooks/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib/hooks/tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+marker_file.h: $(top_builddir)/config.status $(srcdir)/marker_file.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+test_libraries.h: $(top_builddir)/config.status $(srcdir)/test_libraries.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libacl.la: $(libacl_la_OBJECTS) $(libacl_la_DEPENDENCIES) $(EXTRA_libacl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libacl_la_LINK) $(am_libacl_la_rpath) $(libacl_la_OBJECTS) $(libacl_la_LIBADD) $(LIBS)
+
+libbcl.la: $(libbcl_la_OBJECTS) $(libbcl_la_DEPENDENCIES) $(EXTRA_libbcl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libbcl_la_LINK) $(am_libbcl_la_rpath) $(libbcl_la_OBJECTS) $(libbcl_la_LIBADD) $(LIBS)
+
+libfcl.la: $(libfcl_la_OBJECTS) $(libfcl_la_DEPENDENCIES) $(EXTRA_libfcl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libfcl_la_LINK) $(am_libfcl_la_rpath) $(libfcl_la_OBJECTS) $(libfcl_la_LIBADD) $(LIBS)
+
+libfxl.la: $(libfxl_la_OBJECTS) $(libfxl_la_DEPENDENCIES) $(EXTRA_libfxl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libfxl_la_LINK) $(am_libfxl_la_rpath) $(libfxl_la_OBJECTS) $(libfxl_la_LIBADD) $(LIBS)
+
+libivl.la: $(libivl_la_OBJECTS) $(libivl_la_DEPENDENCIES) $(EXTRA_libivl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libivl_la_LINK) $(am_libivl_la_rpath) $(libivl_la_OBJECTS) $(libivl_la_LIBADD) $(LIBS)
+
+liblcl.la: $(liblcl_la_OBJECTS) $(liblcl_la_DEPENDENCIES) $(EXTRA_liblcl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liblcl_la_LINK) $(am_liblcl_la_rpath) $(liblcl_la_OBJECTS) $(liblcl_la_LIBADD) $(LIBS)
+
+liblecl.la: $(liblecl_la_OBJECTS) $(liblecl_la_DEPENDENCIES) $(EXTRA_liblecl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liblecl_la_LINK) $(am_liblecl_la_rpath) $(liblecl_la_OBJECTS) $(liblecl_la_LIBADD) $(LIBS)
+
+libnvl.la: $(libnvl_la_OBJECTS) $(libnvl_la_DEPENDENCIES) $(EXTRA_libnvl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libnvl_la_LINK) $(am_libnvl_la_rpath) $(libnvl_la_OBJECTS) $(libnvl_la_LIBADD) $(LIBS)
+
+libpcl.la: $(libpcl_la_OBJECTS) $(libpcl_la_DEPENDENCIES) $(EXTRA_libpcl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libpcl_la_LINK) $(am_libpcl_la_rpath) $(libpcl_la_OBJECTS) $(libpcl_la_LIBADD) $(LIBS)
+
+libucl.la: $(libucl_la_OBJECTS) $(libucl_la_DEPENDENCIES) $(EXTRA_libucl_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libucl_la_LINK) $(am_libucl_la_rpath) $(libucl_la_OBJECTS) $(libucl_la_LIBADD) $(LIBS)
+
+run_unittests$(EXEEXT): $(run_unittests_OBJECTS) $(run_unittests_DEPENDENCIES) $(EXTRA_run_unittests_DEPENDENCIES)
+ @rm -f run_unittests$(EXEEXT)
+ $(AM_V_CXXLD)$(run_unittests_LINK) $(run_unittests_OBJECTS) $(run_unittests_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libacl_la-async_callout_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbcl_la-basic_callout_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfcl_la-full_callout_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfxl_la-framework_exception_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libivl_la-incorrect_version_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblcl_la-load_callout_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblecl_la-load_error_callout_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnvl_la-no_version_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpcl_la-callout_params_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libucl_la-unload_callout_library.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-callout_handle_associate_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-callout_handle_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-callout_manager_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-handles_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-hooks_manager_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-library_manager_collection_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-library_manager_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-parking_lots_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-run_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-server_hooks_unittest.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+libacl_la-async_callout_library.lo: async_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libacl_la_CPPFLAGS) $(CPPFLAGS) $(libacl_la_CXXFLAGS) $(CXXFLAGS) -MT libacl_la-async_callout_library.lo -MD -MP -MF $(DEPDIR)/libacl_la-async_callout_library.Tpo -c -o libacl_la-async_callout_library.lo `test -f 'async_callout_library.cc' || echo '$(srcdir)/'`async_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libacl_la-async_callout_library.Tpo $(DEPDIR)/libacl_la-async_callout_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='async_callout_library.cc' object='libacl_la-async_callout_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libacl_la_CPPFLAGS) $(CPPFLAGS) $(libacl_la_CXXFLAGS) $(CXXFLAGS) -c -o libacl_la-async_callout_library.lo `test -f 'async_callout_library.cc' || echo '$(srcdir)/'`async_callout_library.cc
+
+libbcl_la-basic_callout_library.lo: basic_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbcl_la_CPPFLAGS) $(CPPFLAGS) $(libbcl_la_CXXFLAGS) $(CXXFLAGS) -MT libbcl_la-basic_callout_library.lo -MD -MP -MF $(DEPDIR)/libbcl_la-basic_callout_library.Tpo -c -o libbcl_la-basic_callout_library.lo `test -f 'basic_callout_library.cc' || echo '$(srcdir)/'`basic_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libbcl_la-basic_callout_library.Tpo $(DEPDIR)/libbcl_la-basic_callout_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='basic_callout_library.cc' object='libbcl_la-basic_callout_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbcl_la_CPPFLAGS) $(CPPFLAGS) $(libbcl_la_CXXFLAGS) $(CXXFLAGS) -c -o libbcl_la-basic_callout_library.lo `test -f 'basic_callout_library.cc' || echo '$(srcdir)/'`basic_callout_library.cc
+
+libfcl_la-full_callout_library.lo: full_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfcl_la_CPPFLAGS) $(CPPFLAGS) $(libfcl_la_CXXFLAGS) $(CXXFLAGS) -MT libfcl_la-full_callout_library.lo -MD -MP -MF $(DEPDIR)/libfcl_la-full_callout_library.Tpo -c -o libfcl_la-full_callout_library.lo `test -f 'full_callout_library.cc' || echo '$(srcdir)/'`full_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfcl_la-full_callout_library.Tpo $(DEPDIR)/libfcl_la-full_callout_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='full_callout_library.cc' object='libfcl_la-full_callout_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfcl_la_CPPFLAGS) $(CPPFLAGS) $(libfcl_la_CXXFLAGS) $(CXXFLAGS) -c -o libfcl_la-full_callout_library.lo `test -f 'full_callout_library.cc' || echo '$(srcdir)/'`full_callout_library.cc
+
+libfxl_la-framework_exception_library.lo: framework_exception_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfxl_la_CPPFLAGS) $(CPPFLAGS) $(libfxl_la_CXXFLAGS) $(CXXFLAGS) -MT libfxl_la-framework_exception_library.lo -MD -MP -MF $(DEPDIR)/libfxl_la-framework_exception_library.Tpo -c -o libfxl_la-framework_exception_library.lo `test -f 'framework_exception_library.cc' || echo '$(srcdir)/'`framework_exception_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfxl_la-framework_exception_library.Tpo $(DEPDIR)/libfxl_la-framework_exception_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='framework_exception_library.cc' object='libfxl_la-framework_exception_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfxl_la_CPPFLAGS) $(CPPFLAGS) $(libfxl_la_CXXFLAGS) $(CXXFLAGS) -c -o libfxl_la-framework_exception_library.lo `test -f 'framework_exception_library.cc' || echo '$(srcdir)/'`framework_exception_library.cc
+
+libivl_la-incorrect_version_library.lo: incorrect_version_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libivl_la_CPPFLAGS) $(CPPFLAGS) $(libivl_la_CXXFLAGS) $(CXXFLAGS) -MT libivl_la-incorrect_version_library.lo -MD -MP -MF $(DEPDIR)/libivl_la-incorrect_version_library.Tpo -c -o libivl_la-incorrect_version_library.lo `test -f 'incorrect_version_library.cc' || echo '$(srcdir)/'`incorrect_version_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libivl_la-incorrect_version_library.Tpo $(DEPDIR)/libivl_la-incorrect_version_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='incorrect_version_library.cc' object='libivl_la-incorrect_version_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libivl_la_CPPFLAGS) $(CPPFLAGS) $(libivl_la_CXXFLAGS) $(CXXFLAGS) -c -o libivl_la-incorrect_version_library.lo `test -f 'incorrect_version_library.cc' || echo '$(srcdir)/'`incorrect_version_library.cc
+
+liblcl_la-load_callout_library.lo: load_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblcl_la_CPPFLAGS) $(CPPFLAGS) $(liblcl_la_CXXFLAGS) $(CXXFLAGS) -MT liblcl_la-load_callout_library.lo -MD -MP -MF $(DEPDIR)/liblcl_la-load_callout_library.Tpo -c -o liblcl_la-load_callout_library.lo `test -f 'load_callout_library.cc' || echo '$(srcdir)/'`load_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblcl_la-load_callout_library.Tpo $(DEPDIR)/liblcl_la-load_callout_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_callout_library.cc' object='liblcl_la-load_callout_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblcl_la_CPPFLAGS) $(CPPFLAGS) $(liblcl_la_CXXFLAGS) $(CXXFLAGS) -c -o liblcl_la-load_callout_library.lo `test -f 'load_callout_library.cc' || echo '$(srcdir)/'`load_callout_library.cc
+
+liblecl_la-load_error_callout_library.lo: load_error_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblecl_la_CPPFLAGS) $(CPPFLAGS) $(liblecl_la_CXXFLAGS) $(CXXFLAGS) -MT liblecl_la-load_error_callout_library.lo -MD -MP -MF $(DEPDIR)/liblecl_la-load_error_callout_library.Tpo -c -o liblecl_la-load_error_callout_library.lo `test -f 'load_error_callout_library.cc' || echo '$(srcdir)/'`load_error_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblecl_la-load_error_callout_library.Tpo $(DEPDIR)/liblecl_la-load_error_callout_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='load_error_callout_library.cc' object='liblecl_la-load_error_callout_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblecl_la_CPPFLAGS) $(CPPFLAGS) $(liblecl_la_CXXFLAGS) $(CXXFLAGS) -c -o liblecl_la-load_error_callout_library.lo `test -f 'load_error_callout_library.cc' || echo '$(srcdir)/'`load_error_callout_library.cc
+
+libnvl_la-no_version_library.lo: no_version_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnvl_la_CPPFLAGS) $(CPPFLAGS) $(libnvl_la_CXXFLAGS) $(CXXFLAGS) -MT libnvl_la-no_version_library.lo -MD -MP -MF $(DEPDIR)/libnvl_la-no_version_library.Tpo -c -o libnvl_la-no_version_library.lo `test -f 'no_version_library.cc' || echo '$(srcdir)/'`no_version_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnvl_la-no_version_library.Tpo $(DEPDIR)/libnvl_la-no_version_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='no_version_library.cc' object='libnvl_la-no_version_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnvl_la_CPPFLAGS) $(CPPFLAGS) $(libnvl_la_CXXFLAGS) $(CXXFLAGS) -c -o libnvl_la-no_version_library.lo `test -f 'no_version_library.cc' || echo '$(srcdir)/'`no_version_library.cc
+
+libpcl_la-callout_params_library.lo: callout_params_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcl_la_CPPFLAGS) $(CPPFLAGS) $(libpcl_la_CXXFLAGS) $(CXXFLAGS) -MT libpcl_la-callout_params_library.lo -MD -MP -MF $(DEPDIR)/libpcl_la-callout_params_library.Tpo -c -o libpcl_la-callout_params_library.lo `test -f 'callout_params_library.cc' || echo '$(srcdir)/'`callout_params_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpcl_la-callout_params_library.Tpo $(DEPDIR)/libpcl_la-callout_params_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_params_library.cc' object='libpcl_la-callout_params_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcl_la_CPPFLAGS) $(CPPFLAGS) $(libpcl_la_CXXFLAGS) $(CXXFLAGS) -c -o libpcl_la-callout_params_library.lo `test -f 'callout_params_library.cc' || echo '$(srcdir)/'`callout_params_library.cc
+
+libucl_la-unload_callout_library.lo: unload_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libucl_la_CPPFLAGS) $(CPPFLAGS) $(libucl_la_CXXFLAGS) $(CXXFLAGS) -MT libucl_la-unload_callout_library.lo -MD -MP -MF $(DEPDIR)/libucl_la-unload_callout_library.Tpo -c -o libucl_la-unload_callout_library.lo `test -f 'unload_callout_library.cc' || echo '$(srcdir)/'`unload_callout_library.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libucl_la-unload_callout_library.Tpo $(DEPDIR)/libucl_la-unload_callout_library.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='unload_callout_library.cc' object='libucl_la-unload_callout_library.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libucl_la_CPPFLAGS) $(CPPFLAGS) $(libucl_la_CXXFLAGS) $(CXXFLAGS) -c -o libucl_la-unload_callout_library.lo `test -f 'unload_callout_library.cc' || echo '$(srcdir)/'`unload_callout_library.cc
+
+run_unittests-run_unittests.o: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+
+run_unittests-run_unittests.obj: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+
+run_unittests-callout_handle_unittest.o: callout_handle_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-callout_handle_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-callout_handle_unittest.Tpo -c -o run_unittests-callout_handle_unittest.o `test -f 'callout_handle_unittest.cc' || echo '$(srcdir)/'`callout_handle_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-callout_handle_unittest.Tpo $(DEPDIR)/run_unittests-callout_handle_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_handle_unittest.cc' object='run_unittests-callout_handle_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-callout_handle_unittest.o `test -f 'callout_handle_unittest.cc' || echo '$(srcdir)/'`callout_handle_unittest.cc
+
+run_unittests-callout_handle_unittest.obj: callout_handle_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-callout_handle_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-callout_handle_unittest.Tpo -c -o run_unittests-callout_handle_unittest.obj `if test -f 'callout_handle_unittest.cc'; then $(CYGPATH_W) 'callout_handle_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/callout_handle_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-callout_handle_unittest.Tpo $(DEPDIR)/run_unittests-callout_handle_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_handle_unittest.cc' object='run_unittests-callout_handle_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-callout_handle_unittest.obj `if test -f 'callout_handle_unittest.cc'; then $(CYGPATH_W) 'callout_handle_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/callout_handle_unittest.cc'; fi`
+
+run_unittests-callout_handle_associate_unittest.o: callout_handle_associate_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-callout_handle_associate_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-callout_handle_associate_unittest.Tpo -c -o run_unittests-callout_handle_associate_unittest.o `test -f 'callout_handle_associate_unittest.cc' || echo '$(srcdir)/'`callout_handle_associate_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-callout_handle_associate_unittest.Tpo $(DEPDIR)/run_unittests-callout_handle_associate_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_handle_associate_unittest.cc' object='run_unittests-callout_handle_associate_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-callout_handle_associate_unittest.o `test -f 'callout_handle_associate_unittest.cc' || echo '$(srcdir)/'`callout_handle_associate_unittest.cc
+
+run_unittests-callout_handle_associate_unittest.obj: callout_handle_associate_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-callout_handle_associate_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-callout_handle_associate_unittest.Tpo -c -o run_unittests-callout_handle_associate_unittest.obj `if test -f 'callout_handle_associate_unittest.cc'; then $(CYGPATH_W) 'callout_handle_associate_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/callout_handle_associate_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-callout_handle_associate_unittest.Tpo $(DEPDIR)/run_unittests-callout_handle_associate_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_handle_associate_unittest.cc' object='run_unittests-callout_handle_associate_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-callout_handle_associate_unittest.obj `if test -f 'callout_handle_associate_unittest.cc'; then $(CYGPATH_W) 'callout_handle_associate_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/callout_handle_associate_unittest.cc'; fi`
+
+run_unittests-callout_manager_unittest.o: callout_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-callout_manager_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-callout_manager_unittest.Tpo -c -o run_unittests-callout_manager_unittest.o `test -f 'callout_manager_unittest.cc' || echo '$(srcdir)/'`callout_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-callout_manager_unittest.Tpo $(DEPDIR)/run_unittests-callout_manager_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_manager_unittest.cc' object='run_unittests-callout_manager_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-callout_manager_unittest.o `test -f 'callout_manager_unittest.cc' || echo '$(srcdir)/'`callout_manager_unittest.cc
+
+run_unittests-callout_manager_unittest.obj: callout_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-callout_manager_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-callout_manager_unittest.Tpo -c -o run_unittests-callout_manager_unittest.obj `if test -f 'callout_manager_unittest.cc'; then $(CYGPATH_W) 'callout_manager_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/callout_manager_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-callout_manager_unittest.Tpo $(DEPDIR)/run_unittests-callout_manager_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='callout_manager_unittest.cc' object='run_unittests-callout_manager_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-callout_manager_unittest.obj `if test -f 'callout_manager_unittest.cc'; then $(CYGPATH_W) 'callout_manager_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/callout_manager_unittest.cc'; fi`
+
+run_unittests-handles_unittest.o: handles_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-handles_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-handles_unittest.Tpo -c -o run_unittests-handles_unittest.o `test -f 'handles_unittest.cc' || echo '$(srcdir)/'`handles_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-handles_unittest.Tpo $(DEPDIR)/run_unittests-handles_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='handles_unittest.cc' object='run_unittests-handles_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-handles_unittest.o `test -f 'handles_unittest.cc' || echo '$(srcdir)/'`handles_unittest.cc
+
+run_unittests-handles_unittest.obj: handles_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-handles_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-handles_unittest.Tpo -c -o run_unittests-handles_unittest.obj `if test -f 'handles_unittest.cc'; then $(CYGPATH_W) 'handles_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/handles_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-handles_unittest.Tpo $(DEPDIR)/run_unittests-handles_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='handles_unittest.cc' object='run_unittests-handles_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-handles_unittest.obj `if test -f 'handles_unittest.cc'; then $(CYGPATH_W) 'handles_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/handles_unittest.cc'; fi`
+
+run_unittests-hooks_manager_unittest.o: hooks_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-hooks_manager_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-hooks_manager_unittest.Tpo -c -o run_unittests-hooks_manager_unittest.o `test -f 'hooks_manager_unittest.cc' || echo '$(srcdir)/'`hooks_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-hooks_manager_unittest.Tpo $(DEPDIR)/run_unittests-hooks_manager_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hooks_manager_unittest.cc' object='run_unittests-hooks_manager_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-hooks_manager_unittest.o `test -f 'hooks_manager_unittest.cc' || echo '$(srcdir)/'`hooks_manager_unittest.cc
+
+run_unittests-hooks_manager_unittest.obj: hooks_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-hooks_manager_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-hooks_manager_unittest.Tpo -c -o run_unittests-hooks_manager_unittest.obj `if test -f 'hooks_manager_unittest.cc'; then $(CYGPATH_W) 'hooks_manager_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/hooks_manager_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-hooks_manager_unittest.Tpo $(DEPDIR)/run_unittests-hooks_manager_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hooks_manager_unittest.cc' object='run_unittests-hooks_manager_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-hooks_manager_unittest.obj `if test -f 'hooks_manager_unittest.cc'; then $(CYGPATH_W) 'hooks_manager_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/hooks_manager_unittest.cc'; fi`
+
+run_unittests-library_manager_collection_unittest.o: library_manager_collection_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-library_manager_collection_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-library_manager_collection_unittest.Tpo -c -o run_unittests-library_manager_collection_unittest.o `test -f 'library_manager_collection_unittest.cc' || echo '$(srcdir)/'`library_manager_collection_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-library_manager_collection_unittest.Tpo $(DEPDIR)/run_unittests-library_manager_collection_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='library_manager_collection_unittest.cc' object='run_unittests-library_manager_collection_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-library_manager_collection_unittest.o `test -f 'library_manager_collection_unittest.cc' || echo '$(srcdir)/'`library_manager_collection_unittest.cc
+
+run_unittests-library_manager_collection_unittest.obj: library_manager_collection_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-library_manager_collection_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-library_manager_collection_unittest.Tpo -c -o run_unittests-library_manager_collection_unittest.obj `if test -f 'library_manager_collection_unittest.cc'; then $(CYGPATH_W) 'library_manager_collection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/library_manager_collection_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-library_manager_collection_unittest.Tpo $(DEPDIR)/run_unittests-library_manager_collection_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='library_manager_collection_unittest.cc' object='run_unittests-library_manager_collection_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-library_manager_collection_unittest.obj `if test -f 'library_manager_collection_unittest.cc'; then $(CYGPATH_W) 'library_manager_collection_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/library_manager_collection_unittest.cc'; fi`
+
+run_unittests-library_manager_unittest.o: library_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-library_manager_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-library_manager_unittest.Tpo -c -o run_unittests-library_manager_unittest.o `test -f 'library_manager_unittest.cc' || echo '$(srcdir)/'`library_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-library_manager_unittest.Tpo $(DEPDIR)/run_unittests-library_manager_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='library_manager_unittest.cc' object='run_unittests-library_manager_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-library_manager_unittest.o `test -f 'library_manager_unittest.cc' || echo '$(srcdir)/'`library_manager_unittest.cc
+
+run_unittests-library_manager_unittest.obj: library_manager_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-library_manager_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-library_manager_unittest.Tpo -c -o run_unittests-library_manager_unittest.obj `if test -f 'library_manager_unittest.cc'; then $(CYGPATH_W) 'library_manager_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/library_manager_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-library_manager_unittest.Tpo $(DEPDIR)/run_unittests-library_manager_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='library_manager_unittest.cc' object='run_unittests-library_manager_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-library_manager_unittest.obj `if test -f 'library_manager_unittest.cc'; then $(CYGPATH_W) 'library_manager_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/library_manager_unittest.cc'; fi`
+
+run_unittests-parking_lots_unittest.o: parking_lots_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-parking_lots_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-parking_lots_unittest.Tpo -c -o run_unittests-parking_lots_unittest.o `test -f 'parking_lots_unittest.cc' || echo '$(srcdir)/'`parking_lots_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-parking_lots_unittest.Tpo $(DEPDIR)/run_unittests-parking_lots_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parking_lots_unittest.cc' object='run_unittests-parking_lots_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-parking_lots_unittest.o `test -f 'parking_lots_unittest.cc' || echo '$(srcdir)/'`parking_lots_unittest.cc
+
+run_unittests-parking_lots_unittest.obj: parking_lots_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-parking_lots_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-parking_lots_unittest.Tpo -c -o run_unittests-parking_lots_unittest.obj `if test -f 'parking_lots_unittest.cc'; then $(CYGPATH_W) 'parking_lots_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/parking_lots_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-parking_lots_unittest.Tpo $(DEPDIR)/run_unittests-parking_lots_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parking_lots_unittest.cc' object='run_unittests-parking_lots_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-parking_lots_unittest.obj `if test -f 'parking_lots_unittest.cc'; then $(CYGPATH_W) 'parking_lots_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/parking_lots_unittest.cc'; fi`
+
+run_unittests-server_hooks_unittest.o: server_hooks_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-server_hooks_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-server_hooks_unittest.Tpo -c -o run_unittests-server_hooks_unittest.o `test -f 'server_hooks_unittest.cc' || echo '$(srcdir)/'`server_hooks_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-server_hooks_unittest.Tpo $(DEPDIR)/run_unittests-server_hooks_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='server_hooks_unittest.cc' object='run_unittests-server_hooks_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-server_hooks_unittest.o `test -f 'server_hooks_unittest.cc' || echo '$(srcdir)/'`server_hooks_unittest.cc
+
+run_unittests-server_hooks_unittest.obj: server_hooks_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-server_hooks_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-server_hooks_unittest.Tpo -c -o run_unittests-server_hooks_unittest.obj `if test -f 'server_hooks_unittest.cc'; then $(CYGPATH_W) 'server_hooks_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/server_hooks_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-server_hooks_unittest.Tpo $(DEPDIR)/run_unittests-server_hooks_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='server_hooks_unittest.cc' object='run_unittests-server_hooks_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(run_unittests_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-server_hooks_unittest.obj `if test -f 'server_hooks_unittest.cc'; then $(CYGPATH_W) 'server_hooks_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/server_hooks_unittest.cc'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/libacl_la-async_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libbcl_la-basic_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libfcl_la-full_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libfxl_la-framework_exception_library.Plo
+ -rm -f ./$(DEPDIR)/libivl_la-incorrect_version_library.Plo
+ -rm -f ./$(DEPDIR)/liblcl_la-load_callout_library.Plo
+ -rm -f ./$(DEPDIR)/liblecl_la-load_error_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libnvl_la-no_version_library.Plo
+ -rm -f ./$(DEPDIR)/libpcl_la-callout_params_library.Plo
+ -rm -f ./$(DEPDIR)/libucl_la-unload_callout_library.Plo
+ -rm -f ./$(DEPDIR)/run_unittests-callout_handle_associate_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-callout_handle_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-callout_manager_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-handles_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-hooks_manager_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-library_manager_collection_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-library_manager_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-parking_lots_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-server_hooks_unittest.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/libacl_la-async_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libbcl_la-basic_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libfcl_la-full_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libfxl_la-framework_exception_library.Plo
+ -rm -f ./$(DEPDIR)/libivl_la-incorrect_version_library.Plo
+ -rm -f ./$(DEPDIR)/liblcl_la-load_callout_library.Plo
+ -rm -f ./$(DEPDIR)/liblecl_la-load_error_callout_library.Plo
+ -rm -f ./$(DEPDIR)/libnvl_la-no_version_library.Plo
+ -rm -f ./$(DEPDIR)/libpcl_la-callout_params_library.Plo
+ -rm -f ./$(DEPDIR)/libucl_la-unload_callout_library.Plo
+ -rm -f ./$(DEPDIR)/run_unittests-callout_handle_associate_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-callout_handle_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-callout_manager_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-handles_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-hooks_manager_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-library_manager_collection_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-library_manager_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-parking_lots_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-server_hooks_unittest.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-TESTS check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/lib/hooks/tests/async_callout_library.cc b/src/lib/hooks/tests/async_callout_library.cc
new file mode 100644
index 0000000..5f40e52
--- /dev/null
+++ b/src/lib/hooks/tests/async_callout_library.cc
@@ -0,0 +1,153 @@
+// Copyright (C) 2018 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/.
+
+/// @file
+/// @brief Async callout library
+///
+/// This is source of a test library for testing a "parking" feature, i.e.
+/// the callouts can schedule asynchronous operation and indicate that the
+/// packet should be parked until the asynchronous operation completes and
+/// the hooks library indicates that packet processing should be resumed.
+
+#include <config.h>
+#include <hooks/hooks.h>
+#include <hooks/parking_lots.h>
+#include <log/logger.h>
+#include <log/macros.h>
+#include <log/message_initializer.h>
+#include <algorithm>
+#include <functional>
+#include <sstream>
+#include <string>
+#include <vector>
+
+using namespace isc::hooks;
+using namespace isc::log;
+using namespace std;
+
+namespace {
+
+/// @brief Logger used by the library.
+isc::log::Logger logger("acl");
+
+/// @brief Log messages.
+const char* log_messages[] = {
+ "ACL_LOAD_START", "async callout load %1",
+ "ACL_LOAD_END", "async callout load end",
+ "ACL_LOAD_END", "duplicate of async callout load end",
+ NULL
+};
+
+/// @brief Initializer for log messages.
+const MessageInitializer message_initializer(log_messages);
+
+/// @brief Simple callback which unparks parked object.
+///
+/// @param parking_lot parking lot where the object is parked.
+/// @param parked_object parked object.
+void unpark(ParkingLotHandlePtr parking_lot, const std::string& parked_object) {
+ parking_lot->unpark(parked_object);
+}
+
+} // end of anonymous namespace
+
+extern "C" {
+
+/// @brief Callout scheduling object parking and providing function to unpark
+/// it.
+///
+/// This callout is crafted to test the following scenario. The callout returns
+/// status "park" to indicate that the packet should be parked. The callout
+/// performs asynchronous operation and indicates that the packet should be
+/// unparked when this operation completes. Unparking the packet triggers a
+/// function associated with the parked packet, e.g. a function which continues
+/// processing of this packet.
+///
+/// This test callout "parks" a string object instead of a packet. It assumes
+/// that there might be multiple callouts installed on this hook point, which
+/// all trigger asynchronous operation. The object must be unparked when the
+/// last asynchronous operation completes. Therefore, it calls the @c reference
+/// function on the parking lot object to increase the reference count. The
+/// object remains parked as long as the reference counter is greater than
+/// 0.
+///
+/// The callout returns 1 or more pointers to the functions which should be
+/// called by the unit tests to simulate completion of the asynchronous tasks.
+/// When the test calls those functions, @c unpark function is called, which
+/// decreases reference count on the parked object, or actually unparks the
+/// object when the reference count reaches 0.
+///
+/// @param handle Reference to callout handle used to set/get arguments.
+int
+hookpt_one(CalloutHandle& handle) {
+ // Using a string as "parked" object.
+ std::string parked_object;
+ handle.getArgument("parked_object", parked_object);
+
+ // Retrieve the parking lot handle for this hook point. It allows for
+ // increasing a reference count on the parked object and also for
+ // scheduling packet unparking.
+ ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
+
+ // Increase the reference count to indicate that this callout needs the
+ // object to remain parked until the asynchronous operation completes.
+ // Otherwise, other callouts could potentially call unpark and cause the
+ // packet processing to continue before the asynchronous operation
+ // completes.
+ parking_lot->reference(parked_object);
+
+ // Create pointer to the function that the test should call to simulate
+ // completion of the asynchronous operation scheduled by this callout.
+ std::function<void()> unpark_trigger_func =
+ std::bind(unpark, parking_lot, parked_object);
+
+ // Every callout (if multiple callouts installed on this hook point) should
+ // return the function pointer under unique name. The base name is
+ // "unpark_trigger" and the callouts append consecutive numbers to this
+ // base name, e.g. "unpark_trigger1", "unpark_trigger2" etc.
+
+ std::string fun_name;
+ std::vector<std::string> args = handle.getArgumentNames();
+ unsigned i = 1;
+ do {
+ std::ostringstream candidate_name;
+ candidate_name << "unpark_trigger" << i;
+ if (std::find(args.begin(), args.end(), candidate_name.str()) ==
+ args.end()) {
+ fun_name = candidate_name.str();
+
+ } else {
+ ++i;
+ }
+ } while (fun_name.empty());
+
+ handle.setArgument(fun_name, unpark_trigger_func);
+
+ handle.setStatus(CalloutHandle::NEXT_STEP_PARK);
+
+ 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
+ LOG_INFO(logger, "ACL_LOAD_START").arg("argument");
+ LOG_INFO(logger, "ACL_LOAD_END");
+ return (0);
+}
+
+}
+
diff --git a/src/lib/hooks/tests/basic_callout_library.cc b/src/lib/hooks/tests/basic_callout_library.cc
new file mode 100644
index 0000000..bd80555
--- /dev/null
+++ b/src/lib/hooks/tests/basic_callout_library.cc
@@ -0,0 +1,145 @@
+// Copyright (C) 2013-2015 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/.
+
+/// @file
+/// @brief Basic callout library
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - Only the "version" framework function is supplied.
+///
+/// - A context_create callout is supplied.
+///
+/// - Three "standard" callouts are supplied corresponding to the hooks
+/// "hookpt_one", "hookpt_two", "hookpt_three". All do some trivial
+/// calculations on the arguments supplied to it and the context variables,
+/// returning intermediate results through the "result" argument. The result
+/// of executing all four callouts in order is:
+///
+/// @f[ (10 + data_1) * data_2 - data_3 @f]
+///
+/// ...where data_1, data_2 and data_3 are the values passed in arguments of
+/// the same name to the three callouts (data_1 passed to hookpt_one, data_2
+/// to hookpt_two etc.) and the result is returned in the argument "result".
+///
+/// - The logger instance is created and some log messages are defined. Some
+/// log messages are duplicated purposely, to check that the logger handles
+/// the duplicates correctly.
+
+#include <config.h>
+#include <hooks/hooks.h>
+#include <fstream>
+#include <log/logger.h>
+#include <log/macros.h>
+#include <log/message_initializer.h>
+
+using namespace isc::hooks;
+using namespace isc::log;
+using namespace std;
+
+namespace {
+
+/// @brief Logger used by the library.
+isc::log::Logger logger("bcl");
+
+/// @brief Log messages.
+const char* log_messages[] = {
+ "BCL_LOAD_START", "basic callout load %1",
+ "BCL_LOAD_END", "basic callout load end",
+ "BCL_LOAD_END", "duplicate of basic callout load end",
+ NULL
+};
+
+/// @brief Initializer for log messages.
+const MessageInitializer message_initializer(log_messages);
+
+}
+
+extern "C" {
+
+// Callouts. All return their result through the "result" argument.
+
+int
+context_create(CalloutHandle& handle) {
+ handle.setContext("result", static_cast<int>(10));
+ handle.setArgument("result", static_cast<int>(10));
+ return (0);
+}
+
+// First callout adds the passed "data_1" argument to the initialized context
+// value of 10. (Note that the value set by context_create is accessed through
+// context and not the argument, so checking that context is correctly passed
+// between callouts in the same library.)
+
+int
+hookpt_one(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_1", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result += data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Second callout multiplies the current context value by the "data_2"
+// argument.
+
+int
+hookpt_two(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_2", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result *= data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Final callout subtracts the result in "data_3".
+
+int
+hookpt_three(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_3", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result -= data;
+ handle.setArgument("result", result);
+
+ 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
+ LOG_INFO(logger, "BCL_LOAD_START").arg("argument");
+ LOG_INFO(logger, "BCL_LOAD_END");
+ return (0);
+}
+
+}
+
diff --git a/src/lib/hooks/tests/callout_handle_associate_unittest.cc b/src/lib/hooks/tests/callout_handle_associate_unittest.cc
new file mode 100644
index 0000000..cf09388
--- /dev/null
+++ b/src/lib/hooks/tests/callout_handle_associate_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2018 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/.
+
+#include <config.h>
+
+#include <hooks/callout_handle.h>
+#include <hooks/callout_handle_associate.h>
+#include <gtest/gtest.h>
+
+using namespace isc::hooks;
+
+namespace {
+
+// This test verifies that the callout handle can be created and
+// retrieved from the CalloutHandleAssociate.
+TEST(CalloutHandleAssociate, getCalloutHandle) {
+ CalloutHandleAssociate associate;
+ // The handle should be initialized and returned.
+ CalloutHandlePtr callout_handle = associate.getCalloutHandle();
+ ASSERT_TRUE(callout_handle);
+
+ // When calling the second time, the same handle should be returned.
+ CalloutHandlePtr callout_handle2 = associate.getCalloutHandle();
+ EXPECT_TRUE(callout_handle == callout_handle2);
+
+ // A different associate should produce a different handle.
+ CalloutHandleAssociate associate2;
+ callout_handle2 = associate2.getCalloutHandle();
+ EXPECT_FALSE(callout_handle == callout_handle2);
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/hooks/tests/callout_handle_unittest.cc b/src/lib/hooks/tests/callout_handle_unittest.cc
new file mode 100644
index 0000000..bb20e0c
--- /dev/null
+++ b/src/lib/hooks/tests/callout_handle_unittest.cc
@@ -0,0 +1,384 @@
+// Copyright (C) 2013-2020 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/.
+
+#include <config.h>
+
+#include <hooks/callout_handle.h>
+#include <hooks/callout_manager.h>
+#include <hooks/library_handle.h>
+#include <hooks/server_hooks.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace isc::hooks;
+using namespace std;
+
+namespace {
+
+/// @file
+/// @brief Holds the CalloutHandle argument tests
+///
+/// Additional testing of the CalloutHandle - together with the interaction
+/// of the LibraryHandle - is done in the handles_unittests set of tests.
+
+class CalloutHandleTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor
+ ///
+ /// Sets up a callout manager to be referenced by the CalloutHandle in
+ /// these tests. (The "4" for the number of libraries in the
+ /// CalloutManager is arbitrary - it is not used in these tests.)
+ CalloutHandleTest() : manager_(new CalloutManager(4))
+ {}
+
+ /// Obtain hook manager
+ boost::shared_ptr<CalloutManager>& getCalloutManager() {
+ return (manager_);
+ }
+
+private:
+ /// Callout manager accessed by this CalloutHandle.
+ boost::shared_ptr<CalloutManager> manager_;
+};
+
+// *** Argument Tests ***
+//
+// The first set of tests check that the CalloutHandle can store and retrieve
+// arguments. These are very similar to the LibraryHandle context tests.
+
+// Test that we can store multiple values of the same type and that they
+// are distinct.
+
+TEST_F(CalloutHandleTest, ArgumentDistinctSimpleType) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Store and retrieve an int (random value).
+ int a = 42;
+ handle.setArgument("integer1", a);
+ EXPECT_EQ(42, a);
+
+ int b = 0;
+ handle.getArgument("integer1", b);
+ EXPECT_EQ(42, b);
+
+ // Add another integer (another random value).
+ int c = 142;
+ handle.setArgument("integer2", c);
+ EXPECT_EQ(142, c);
+
+ int d = 0;
+ handle.getArgument("integer2", d);
+ EXPECT_EQ(142, d);
+
+ // Add a short (random value).
+ short e = -81;
+ handle.setArgument("short", e);
+ EXPECT_EQ(-81, e);
+
+ short f = 0;
+ handle.getArgument("short", f);
+ EXPECT_EQ(-81, f);
+}
+
+// Test that trying to get an unknown argument throws an exception.
+
+TEST_F(CalloutHandleTest, ArgumentUnknownName) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Set an integer
+ int a = 42;
+ handle.setArgument("integer1", a);
+ EXPECT_EQ(42, a);
+
+ // Check we can retrieve it
+ int b = 0;
+ handle.getArgument("integer1", b);
+ EXPECT_EQ(42, b);
+
+ // Check that getting an unknown name throws an exception.
+ int c = 0;
+ EXPECT_THROW(handle.getArgument("unknown", c), NoSuchArgument);
+}
+
+// Test that trying to get an argument with an incorrect type throws an
+// exception.
+
+TEST_F(CalloutHandleTest, ArgumentIncorrectType) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Set an integer
+ int a = 42;
+ handle.setArgument("integer1", a);
+ EXPECT_EQ(42, a);
+
+ // Check we can retrieve it
+ long b = 0;
+ EXPECT_THROW(handle.getArgument("integer1", b), boost::bad_any_cast);
+}
+
+// Now try with some very complex types. The types cannot be defined within
+// the function and they should contain a copy constructor. For this reason,
+// a simple "struct" is used.
+
+struct Alpha {
+ int a;
+ int b;
+ Alpha(int first = 0, int second = 0) : a(first), b(second) {}
+};
+
+struct Beta {
+ int c;
+ int d;
+ Beta(int first = 0, int second = 0) : c(first), d(second) {}
+};
+
+TEST_F(CalloutHandleTest, ComplexTypes) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Declare two variables of different (complex) types. (Note as to the
+ // variable names: aleph and beth are the first two letters of the Hebrew
+ // alphabet.)
+ Alpha aleph(1, 2);
+ EXPECT_EQ(1, aleph.a);
+ EXPECT_EQ(2, aleph.b);
+ handle.setArgument("aleph", aleph);
+
+ Beta beth(11, 22);
+ EXPECT_EQ(11, beth.c);
+ EXPECT_EQ(22, beth.d);
+ handle.setArgument("beth", beth);
+
+ // Ensure we can extract the data correctly.
+ Alpha aleph2;
+ EXPECT_EQ(0, aleph2.a);
+ EXPECT_EQ(0, aleph2.b);
+ handle.getArgument("aleph", aleph2);
+ EXPECT_EQ(1, aleph2.a);
+ EXPECT_EQ(2, aleph2.b);
+
+ Beta beth2;
+ EXPECT_EQ(0, beth2.c);
+ EXPECT_EQ(0, beth2.d);
+ handle.getArgument("beth", beth2);
+ EXPECT_EQ(11, beth2.c);
+ EXPECT_EQ(22, beth2.d);
+
+ // Ensure that complex types also thrown an exception if we attempt to
+ // get a context element of the wrong type.
+ EXPECT_THROW(handle.getArgument("aleph", beth), boost::bad_any_cast);
+}
+
+// Check that the context can store pointers. And also check that it respects
+// that a "pointer to X" is not the same as a "pointer to const X".
+
+TEST_F(CalloutHandleTest, PointerTypes) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Declare a couple of variables, const and non-const.
+ Alpha aleph(5, 10);
+ const Beta beth(15, 20);
+
+ Alpha* pa = &aleph;
+ const Beta* pcb = &beth;
+
+ // Check pointers can be set and retrieved OK.
+ handle.setArgument("non_const_pointer", pa);
+ handle.setArgument("const_pointer", pcb);
+
+ Alpha* pa2 = 0;
+ handle.getArgument("non_const_pointer", pa2);
+ EXPECT_TRUE(pa == pa2);
+
+ const Beta* pcb2 = 0;
+ handle.getArgument("const_pointer", pcb2);
+ EXPECT_TRUE(pcb == pcb2);
+
+ // Check that the "const" is protected in the context.
+ const Alpha* pca3;
+ EXPECT_THROW(handle.getArgument("non_const_pointer", pca3),
+ boost::bad_any_cast);
+
+ Beta* pb3;
+ EXPECT_THROW(handle.getArgument("const_pointer", pb3),
+ boost::bad_any_cast);
+}
+
+// Check that we can get the names of the arguments.
+
+TEST_F(CalloutHandleTest, ContextItemNames) {
+ CalloutHandle handle(getCalloutManager());
+
+ vector<string> expected_names;
+
+ expected_names.push_back("faith");
+ handle.setArgument("faith", 42);
+ expected_names.push_back("hope");
+ handle.setArgument("hope", 43);
+ expected_names.push_back("charity");
+ handle.setArgument("charity", 44);
+
+ // Get the names and check against the expected names. We'll sort
+ // both arrays to simplify the checking.
+ vector<string> actual_names = handle.getArgumentNames();
+
+ sort(actual_names.begin(), actual_names.end());
+ sort(expected_names.begin(), expected_names.end());
+ EXPECT_TRUE(expected_names == actual_names);
+}
+
+// Test that we can delete an argument.
+
+TEST_F(CalloutHandleTest, DeleteArgument) {
+ CalloutHandle handle(getCalloutManager());
+
+ int one = 1;
+ int two = 2;
+ int three = 3;
+ int four = 4;
+ int value; // Return value
+
+ handle.setArgument("one", one);
+ handle.setArgument("two", two);
+ handle.setArgument("three", three);
+ handle.setArgument("four", four);
+
+ // Delete "one".
+ handle.getArgument("one", value);
+ EXPECT_EQ(1, value);
+ handle.deleteArgument("one");
+
+ EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
+ handle.getArgument("two", value);
+ EXPECT_EQ(2, value);
+ handle.getArgument("three", value);
+ EXPECT_EQ(3, value);
+ handle.getArgument("four", value);
+ EXPECT_EQ(4, value);
+
+ // Delete "three".
+ handle.getArgument("three", value);
+ EXPECT_EQ(3, value);
+ handle.deleteArgument("three");
+
+ EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
+ handle.getArgument("two", value);
+ EXPECT_EQ(2, value);
+ EXPECT_THROW(handle.getArgument("three", value), NoSuchArgument);
+ handle.getArgument("four", value);
+ EXPECT_EQ(4, value);
+}
+
+// Test that we can delete all arguments.
+
+TEST_F(CalloutHandleTest, DeleteAllArguments) {
+ CalloutHandle handle(getCalloutManager());
+
+ int one = 1;
+ int two = 2;
+ int three = 3;
+ int four = 4;
+ int value; // Return value
+
+ // Set the arguments. The previous test verifies that this works.
+ handle.setArgument("one", one);
+ handle.setArgument("two", two);
+ handle.setArgument("three", three);
+ handle.setArgument("four", four);
+
+ // Delete all arguments...
+ handle.deleteAllArguments();
+
+ // ... and check that none are left.
+ EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
+ EXPECT_THROW(handle.getArgument("two", value), NoSuchArgument);
+ EXPECT_THROW(handle.getArgument("three", value), NoSuchArgument);
+ EXPECT_THROW(handle.getArgument("four", value), NoSuchArgument);
+}
+
+// Test the "status" field.
+TEST_F(CalloutHandleTest, StatusField) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Should be continue on construction.
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle.getStatus());
+
+ handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, handle.getStatus());
+
+ handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, handle.getStatus());
+
+ handle.setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle.getStatus());
+}
+
+// Tests that ScopedCalloutHandleState object resets CalloutHandle state
+// during construction and destruction.
+TEST_F(CalloutHandleTest, scopedState) {
+ // Create pointer to the handle to be wrapped.
+ CalloutHandlePtr handle(new CalloutHandle(getCalloutManager()));
+
+ // Set two arguments and the non-default status.
+ int one = 1;
+ int two = 2;
+ int three = 3;
+ handle->setArgument("one", one);
+ handle->setArgument("two", two);
+ handle->setContext("three", three);
+ handle->setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+
+ int value = 0;
+ EXPECT_NO_THROW(handle->getArgument("one", value));
+ EXPECT_NO_THROW(handle->getArgument("two", value));
+ EXPECT_NO_THROW(handle->getContext("three", value));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, handle->getStatus());
+
+ {
+ // Wrap the callout handle with the scoped state object, which should
+ // reset the state of the handle.
+ ScopedCalloutHandleState scoped_state(handle);
+
+ // When state is reset, all arguments should be removed and the
+ // default status should be set.
+ EXPECT_THROW(handle->getArgument("one", value), NoSuchArgument);
+ EXPECT_THROW(handle->getArgument("two", value), NoSuchArgument);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle->getStatus());
+
+ // Context should be intact.
+ ASSERT_NO_THROW(handle->getContext("three", value));
+ EXPECT_EQ(three, value);
+
+ // Set the arguments and status again prior to the destruction of
+ // the wrapper.
+ handle->setArgument("one", one);
+ handle->setArgument("two", two);
+ handle->setStatus(CalloutHandle::NEXT_STEP_DROP);
+
+ EXPECT_NO_THROW(handle->getArgument("one", value));
+ EXPECT_NO_THROW(handle->getArgument("two", value));
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, handle->getStatus());
+ }
+
+ // Arguments should be gone again and the status should be set to
+ // a default value.
+ EXPECT_THROW(handle->getArgument("one", value), NoSuchArgument);
+ EXPECT_THROW(handle->getArgument("two", value), NoSuchArgument);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle->getStatus());
+
+ // Context should be intact.
+ ASSERT_NO_THROW(handle->getContext("three", value));
+ EXPECT_EQ(three, value);
+}
+
+// Further tests of the "skip" flag and tests of getting the name of the
+// hook to which the current callout is attached is in the "handles_unittest"
+// module.
+
+} // Anonymous namespace
diff --git a/src/lib/hooks/tests/callout_manager_unittest.cc b/src/lib/hooks/tests/callout_manager_unittest.cc
new file mode 100644
index 0000000..67ba83b
--- /dev/null
+++ b/src/lib/hooks/tests/callout_manager_unittest.cc
@@ -0,0 +1,944 @@
+// Copyright (C) 2013-2023 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/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <hooks/callout_handle.h>
+#include <hooks/callout_manager.h>
+#include <hooks/library_handle.h>
+#include <hooks/server_hooks.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <climits>
+#include <string>
+#include <vector>
+
+/// @file
+/// @brief CalloutManager and LibraryHandle tests
+///
+/// These set of tests check the CalloutManager and LibraryHandle. They are
+/// together in the same file because the LibraryHandle is little more than a
+/// restricted interface to the CalloutManager, and a lot of the support
+/// structure for the tests is common.
+
+using namespace isc;
+using namespace isc::hooks;
+using namespace std;
+
+namespace {
+
+class CalloutManagerTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ ///
+ /// Sets up a collection of three LibraryHandle objects to use in the test.
+ CalloutManagerTest() {
+
+ // Set up the server hooks. There is one singleton for all tests,
+ // so reset it and explicitly set up the hooks for the test.
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+ alpha_index_ = hooks.registerHook("alpha");
+ beta_index_ = hooks.registerHook("beta");
+ gamma_index_ = hooks.registerHook("gamma");
+ delta_index_ = hooks.registerHook("delta");
+
+ // Set up the callout manager with these hooks. Assume a maximum of
+ // four libraries.
+ callout_manager_.reset(new CalloutManager(10));
+
+ // Set up the callout handle.
+ callout_handle_.reset(new CalloutHandle(callout_manager_));
+
+ // Initialize the static variable.
+ callout_value_ = 0;
+ }
+
+ /// @brief Return the callout handle
+ CalloutHandle& getCalloutHandle() {
+ return (*callout_handle_);
+ }
+
+ /// @brief Return the callout manager
+ boost::shared_ptr<CalloutManager> getCalloutManager() {
+ return (callout_manager_);
+ }
+
+ /// Static variable used for accumulating information
+ static int callout_value_;
+
+ /// Hook indexes. These are somewhat ubiquitous, so are made public for
+ /// ease of reference instead of being accessible by a function.
+ int alpha_index_;
+ int beta_index_;
+ int gamma_index_;
+ int delta_index_;
+
+private:
+ /// Callout handle used in calls
+ boost::shared_ptr<CalloutHandle> callout_handle_;
+
+ /// Callout manager used for the test
+ boost::shared_ptr<CalloutManager> callout_manager_;
+};
+
+// Definition of the static variable.
+int CalloutManagerTest::callout_value_ = 0;
+
+// Callout definitions
+//
+// The callouts defined here are structured in such a way that it is possible
+// to determine the order in which they are called and whether they are called
+// at all. The method used is simple - after a sequence of callouts, the digits
+// in the value, reading left to right, determines the order of the callouts
+// called. For example, callout one followed by two followed by three followed
+// by two followed by one results in a value of 12321.
+//
+// Functions return a zero to indicate success.
+
+extern "C" {
+int callout_general(int number) {
+ CalloutManagerTest::callout_value_ =
+ 10 * CalloutManagerTest::callout_value_ + number;
+ return (0);
+}
+
+int callout_one(CalloutHandle&) {
+ return (callout_general(1));
+}
+
+int callout_two(CalloutHandle&) {
+ return (callout_general(2));
+}
+
+int callout_three(CalloutHandle&) {
+ return (callout_general(3));
+}
+
+int callout_four(CalloutHandle&) {
+ return (callout_general(4));
+}
+
+int callout_five(CalloutHandle&) {
+ return (callout_general(5));
+}
+
+int callout_six(CalloutHandle&) {
+ return (callout_general(6));
+}
+
+int callout_seven(CalloutHandle&) {
+ return (callout_general(7));
+}
+
+// The next functions are duplicates of some of the above, but return an error.
+int callout_one_error(CalloutHandle& handle) {
+ (void) callout_one(handle);
+ return (1);
+}
+
+int callout_two_error(CalloutHandle& handle) {
+ (void) callout_two(handle);
+ return (1);
+}
+
+int callout_three_error(CalloutHandle& handle) {
+ (void) callout_three(handle);
+ return (1);
+}
+
+int callout_four_error(CalloutHandle& handle) {
+ (void) callout_four(handle);
+ return (1);
+}
+
+// The next functions are duplicates of some of the above, but throw exceptions.
+int callout_one_exception(CalloutHandle& handle) {
+ (void) callout_one(handle);
+ throw 0;
+ return (1);
+}
+
+int callout_two_exception(CalloutHandle& handle) {
+ (void) callout_two(handle);
+ throw 0;
+ return (1);
+}
+
+int callout_three_exception(CalloutHandle& handle) {
+ (void) callout_three(handle);
+ throw 0;
+ return (1);
+}
+
+int callout_four_exception(CalloutHandle& handle) {
+ (void) callout_four(handle);
+ throw 0;
+ return (1);
+}
+
+} // extern "C"
+
+// *** Callout Tests ***
+//
+// The next set of tests check that callouts can be called.
+
+// Constructor - check that we trap bad parameters.
+TEST_F(CalloutManagerTest, BadConstructorParameters) {
+ boost::scoped_ptr<CalloutManager> cm;
+
+ // Invalid number of libraries
+ EXPECT_THROW(cm.reset(new CalloutManager(-1)), BadValue);
+}
+
+// Check the number of libraries is reported successfully.
+TEST_F(CalloutManagerTest, NumberOfLibraries) {
+ boost::scoped_ptr<CalloutManager> cm;
+
+ // Check two valid values of number of libraries to ensure that the
+ // GetNumLibraries() returns the value set.
+ EXPECT_NO_THROW(cm.reset(new CalloutManager()));
+ EXPECT_EQ(0, cm->getNumLibraries());
+
+ EXPECT_NO_THROW(cm.reset(new CalloutManager(0)));
+ EXPECT_EQ(0, cm->getNumLibraries());
+
+ EXPECT_NO_THROW(cm.reset(new CalloutManager(4)));
+ EXPECT_EQ(4, cm->getNumLibraries());
+
+ EXPECT_NO_THROW(cm.reset(new CalloutManager(42)));
+ EXPECT_EQ(42, cm->getNumLibraries());
+}
+
+// Check that we can only set the current library index to the correct values.
+TEST_F(CalloutManagerTest, CheckLibraryIndex) {
+ // Check valid indexes. As the callout manager is sized for 10 libraries,
+ // we expect:
+ //
+ // -1 to be valid as it is the standard "invalid" value.
+ // 0 to be valid for the pre-user library callouts
+ // 1-10 to be valid for the user-library callouts
+ // INT_MAX to be valid for the post-user library callouts
+ //
+ // All other values to be invalid.
+ for (int i = -1; i < 11; ++i) {
+ EXPECT_NO_THROW(getCalloutManager()->setLibraryIndex(i));
+ EXPECT_EQ(i, getCalloutManager()->getLibraryIndex());
+ }
+ EXPECT_NO_THROW(getCalloutManager()->setLibraryIndex(INT_MAX));
+ EXPECT_EQ(INT_MAX, getCalloutManager()->getLibraryIndex());
+
+ // Check invalid ones
+ EXPECT_THROW(getCalloutManager()->setLibraryIndex(-2), NoSuchLibrary);
+ EXPECT_THROW(getCalloutManager()->setLibraryIndex(11), NoSuchLibrary);
+}
+
+// Check that we can only register callouts on valid hook names.
+TEST_F(CalloutManagerTest, ValidHookNames) {
+ EXPECT_NO_THROW(getCalloutManager()->registerCallout("alpha", callout_one, 0));
+ EXPECT_THROW(getCalloutManager()->registerCallout("unknown", callout_one, 0),
+ NoSuchHook);
+}
+
+// Check we can register callouts appropriately.
+TEST_F(CalloutManagerTest, RegisterCallout) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+
+ // Set up so that hooks "alpha" and "beta" have callouts attached from a
+ // different libraries.
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected. (This is also a
+ // test of the callCallouts method.)
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1, callout_value_);
+
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(2, callout_value_);
+
+ // Register some more callouts from different libraries on hook "alpha".
+ getCalloutManager()->registerCallout("alpha", callout_three, 2);
+ getCalloutManager()->registerCallout("alpha", callout_four, 2);
+ getCalloutManager()->registerCallout("alpha", callout_five, 3);
+
+ // Check it is as expected.
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1345, callout_value_);
+
+ // ... and check the additional callouts were not registered on the "beta"
+ // hook.
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(2, callout_value_);
+
+ // Add another callout to hook "alpha" from library index 2 - this should
+ // appear at the end of the callout list for that library.
+ getCalloutManager()->registerCallout("alpha", callout_six, 2);
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(13465, callout_value_);
+
+ // Add a callout from library index 1 - this should appear between the
+ // callouts from library index 0 and library index 2.
+ getCalloutManager()->registerCallout("alpha", callout_seven, 1);
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(173465, callout_value_);
+}
+
+// Check the "calloutsPresent()" method.
+TEST_F(CalloutManagerTest, CalloutsPresent) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Set up so that hooks "alpha", "beta" and "delta" have callouts attached
+ // to them, and callout "gamma" does not. (In the statements below, the
+ // exact callouts attached to a hook are not relevant - only the fact
+ // that some callouts are). Chose the libraries for which the callouts
+ // are registered randomly.
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 1);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+ getCalloutManager()->registerCallout("alpha", callout_three, 3);
+ getCalloutManager()->registerCallout("delta", callout_four, 3);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check we fail on an invalid hook index.
+ EXPECT_THROW(getCalloutManager()->calloutsPresent(42), NoSuchHook);
+ EXPECT_THROW(getCalloutManager()->calloutsPresent(-1), NoSuchHook);
+}
+
+// Test that calling a hook with no callouts on it returns success.
+TEST_F(CalloutManagerTest, CallNoCallouts) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Call the callouts on an arbitrary hook and ensure that nothing happens.
+ callout_value_ = 475;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(475, callout_value_); // Unchanged
+}
+
+// Test that the callouts are called in the correct order (i.e. the callouts
+// from the first library in the order they were registered, then the callouts
+// from the second library in the order they were registered etc.)
+TEST_F(CalloutManagerTest, CallCalloutsSuccess) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Each library contributes one callout on hook "alpha".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one, 1);
+ getCalloutManager()->registerCallout("alpha", callout_two, 1);
+ getCalloutManager()->registerCallout("alpha", callout_three, 2);
+ getCalloutManager()->registerCallout("alpha", callout_four, 3);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ // Do a random selection of callouts on hook "beta".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("beta", callout_one, 0);
+ getCalloutManager()->registerCallout("beta", callout_three, 0);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+ getCalloutManager()->registerCallout("beta", callout_four, 3);
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(1324, callout_value_);
+
+ // Ensure that calling the callouts on a hook with no callouts works.
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(gamma_index_, getCalloutHandle());
+ EXPECT_EQ(0, callout_value_);
+}
+
+// Test that the callouts are called in order, but that callouts occurring
+// after a callout that returns an error are called.
+//
+// (Note: in this test, the callouts that return an error set the value of
+// callout_value_ before they return the error code.)
+TEST_F(CalloutManagerTest, CallCalloutsError) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Each library contributing one callout on hook "alpha". The first callout
+ // returns an error (after adding its value to the result).
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one_error, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 1);
+ getCalloutManager()->registerCallout("alpha", callout_three, 2);
+ getCalloutManager()->registerCallout("alpha", callout_four, 3);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ // Each library contributing multiple callouts on hook "beta". The last
+ // callout on the first library returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("beta", callout_one, 0);
+ getCalloutManager()->registerCallout("beta", callout_one_error, 0);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+ getCalloutManager()->registerCallout("beta", callout_three, 1);
+ getCalloutManager()->registerCallout("beta", callout_three, 1);
+ getCalloutManager()->registerCallout("beta", callout_four, 3);
+ getCalloutManager()->registerCallout("beta", callout_four, 3);
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(11223344, callout_value_);
+
+ // A callout in a random position in the callout list returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("gamma", callout_one, 0);
+ getCalloutManager()->registerCallout("gamma", callout_one, 0);
+ getCalloutManager()->registerCallout("gamma", callout_two, 1);
+ getCalloutManager()->registerCallout("gamma", callout_two, 1);
+ getCalloutManager()->registerCallout("gamma", callout_four_error, 3);
+ getCalloutManager()->registerCallout("gamma", callout_four, 3);
+ getCalloutManager()->callCallouts(gamma_index_, getCalloutHandle());
+ EXPECT_EQ(112244, callout_value_);
+
+ // The last callout on a hook returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("delta", callout_one, 0);
+ getCalloutManager()->registerCallout("delta", callout_one, 0);
+ getCalloutManager()->registerCallout("delta", callout_two, 1);
+ getCalloutManager()->registerCallout("delta", callout_two, 1);
+ getCalloutManager()->registerCallout("delta", callout_three, 2);
+ getCalloutManager()->registerCallout("delta", callout_three, 2);
+ getCalloutManager()->registerCallout("delta", callout_four, 3);
+ getCalloutManager()->registerCallout("delta", callout_four_error, 3);
+ getCalloutManager()->callCallouts(delta_index_, getCalloutHandle());
+ EXPECT_EQ(11223344, callout_value_);
+}
+
+// Test that the callouts are called in order, but that callouts occurring
+// after a callout that throws exception are called.
+//
+// (Note: in this test, the callouts that return an error set the value of
+// callout_value_ before they throw exception.)
+TEST_F(CalloutManagerTest, CallCalloutsException) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Each library contributing one callout on hook "alpha". The first callout
+ // returns an error (after adding its value to the result).
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one_exception, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 1);
+ getCalloutManager()->registerCallout("alpha", callout_three, 2);
+ getCalloutManager()->registerCallout("alpha", callout_four, 3);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+ EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP);
+
+ // Each library contributing multiple callouts on hook "beta". The last
+ // callout on the first library returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("beta", callout_one, 0);
+ getCalloutManager()->registerCallout("beta", callout_one_exception, 0);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+ getCalloutManager()->registerCallout("beta", callout_two, 1);
+ getCalloutManager()->registerCallout("beta", callout_three, 1);
+ getCalloutManager()->registerCallout("beta", callout_three, 1);
+ getCalloutManager()->registerCallout("beta", callout_four, 3);
+ getCalloutManager()->registerCallout("beta", callout_four, 3);
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(11223344, callout_value_);
+ EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP);
+
+ // A callout in a random position in the callout list returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("gamma", callout_one, 0);
+ getCalloutManager()->registerCallout("gamma", callout_one, 0);
+ getCalloutManager()->registerCallout("gamma", callout_two, 1);
+ getCalloutManager()->registerCallout("gamma", callout_two, 1);
+ getCalloutManager()->registerCallout("gamma", callout_four_exception, 3);
+ getCalloutManager()->registerCallout("gamma", callout_four, 3);
+ getCalloutManager()->callCallouts(gamma_index_, getCalloutHandle());
+ EXPECT_EQ(112244, callout_value_);
+ EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP);
+
+ // The last callout on a hook returns an error.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("delta", callout_one, 0);
+ getCalloutManager()->registerCallout("delta", callout_one, 0);
+ getCalloutManager()->registerCallout("delta", callout_two, 1);
+ getCalloutManager()->registerCallout("delta", callout_two, 1);
+ getCalloutManager()->registerCallout("delta", callout_three, 2);
+ getCalloutManager()->registerCallout("delta", callout_three, 2);
+ getCalloutManager()->registerCallout("delta", callout_four, 3);
+ getCalloutManager()->registerCallout("delta", callout_four_exception, 3);
+ getCalloutManager()->callCallouts(delta_index_, getCalloutHandle());
+ EXPECT_EQ(11223344, callout_value_);
+ EXPECT_EQ(getCalloutHandle().getStatus(), CalloutHandle::NEXT_STEP_DROP);
+}
+
+// Now test that we can deregister a single callout on a hook.
+TEST_F(CalloutManagerTest, DeregisterSingleCallout) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Add a callout to hook "alpha" and check it is added correctly.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(2, callout_value_);
+
+ // Remove it and check that the no callouts are present. We have to reset
+ // the current library index here as it was invalidated by the call
+ // to callCallouts().
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_two, 0));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+}
+
+// Now test that we can deregister a single callout on a hook that has multiple
+// callouts from the same library.
+TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Add multiple callouts to hook "alpha".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->registerCallout("alpha", callout_three, 0);
+ getCalloutManager()->registerCallout("alpha", callout_four, 0);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ // Remove the callout_two callout. We have to reset the current library
+ // index here as it was invalidated by the call to callCallouts().
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_two, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(134, callout_value_);
+
+ // Try removing it again.
+ EXPECT_FALSE(getCalloutManager()->deregisterCallout("alpha", callout_two, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(134, callout_value_);
+}
+
+// Check we can deregister multiple callouts from the same library.
+TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Each library contributes one callout on hook "alpha".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->registerCallout("alpha", callout_three, 0);
+ getCalloutManager()->registerCallout("alpha", callout_four, 0);
+ getCalloutManager()->registerCallout("alpha", callout_three, 0);
+ getCalloutManager()->registerCallout("alpha", callout_four, 0);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(12123434, callout_value_);
+
+ // Remove the callout_two callouts. We have to reset the current library
+ // index here as it was invalidated by the call to callCallouts().
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_two, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(113434, callout_value_);
+
+ // Try removing multiple callouts that includes one at the end of the
+ // list of callouts.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_four, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1133, callout_value_);
+
+ // ... and from the start.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_one, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(33, callout_value_);
+
+ // ... and the remaining callouts.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_three, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(0, callout_value_);
+
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+}
+
+// Check we can deregister multiple callouts from multiple libraries.
+TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsMultipleLibraries) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Each library contributes two callouts to hook "alpha".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->registerCallout("alpha", callout_three, 1);
+ getCalloutManager()->registerCallout("alpha", callout_four, 1);
+ getCalloutManager()->registerCallout("alpha", callout_five, 2);
+ getCalloutManager()->registerCallout("alpha", callout_two, 2);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(123452, callout_value_);
+
+ // Remove the callout_two callout from library 0. It should not affect
+ // the second callout_two callout registered by library 2.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_two, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(13452, callout_value_);
+}
+
+// Check we can deregister all callouts from a single library.
+TEST_F(CalloutManagerTest, DeregisterAllCallouts) {
+ // Ensure that no callouts are attached to hook one.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+
+ // Each library contributes two callouts to hook "alpha".
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->registerCallout("alpha", callout_three, 1);
+ getCalloutManager()->registerCallout("alpha", callout_four, 1);
+ getCalloutManager()->registerCallout("alpha", callout_five, 2);
+ getCalloutManager()->registerCallout("alpha", callout_six, 2);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(123456, callout_value_);
+
+ // Remove all callouts from library index 1.
+ EXPECT_TRUE(getCalloutManager()->deregisterAllCallouts("alpha", 1));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1256, callout_value_);
+
+ // Remove all callouts from library index 2.
+ EXPECT_TRUE(getCalloutManager()->deregisterAllCallouts("alpha", 2));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(12, callout_value_);
+}
+
+// Check that we can register/deregister callouts on different libraries
+// and different hooks, and that the callout instances are regarded as
+// unique and do not affect one another.
+TEST_F(CalloutManagerTest, MultipleCalloutsLibrariesHooks) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Register callouts on the alpha hook.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("alpha", callout_one, 0);
+ getCalloutManager()->registerCallout("alpha", callout_two, 0);
+ getCalloutManager()->registerCallout("alpha", callout_three, 1);
+ getCalloutManager()->registerCallout("alpha", callout_four, 1);
+ getCalloutManager()->registerCallout("alpha", callout_five, 2);
+ getCalloutManager()->registerCallout("alpha", callout_two, 2);
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(123452, callout_value_);
+
+ // Register the same callouts on the beta hook, and check that those
+ // on the alpha hook are not affected.
+ callout_value_ = 0;
+ getCalloutManager()->registerCallout("beta", callout_five, 0);
+ getCalloutManager()->registerCallout("beta", callout_one, 0);
+ getCalloutManager()->registerCallout("beta", callout_four, 2);
+ getCalloutManager()->registerCallout("beta", callout_three, 2);
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(5143, callout_value_);
+
+ // Check that the order of callouts on the alpha hook has not been affected.
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(123452, callout_value_);
+
+ // Remove callout four from beta and check that alpha is not affected.
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("beta", callout_four, 2));
+
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(beta_index_, getCalloutHandle());
+ EXPECT_EQ(513, callout_value_);
+
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(123452, callout_value_);
+}
+
+// Library handle tests. As by inspection the LibraryHandle can be seen to be
+// little more than shell around CalloutManager, only a basic set of tests
+// is done concerning registration and deregistration of functions.
+//
+// More extensive tests (i.e. checking that when a callout is called it can
+// only register and deregister callouts within its library) require that
+// the CalloutHandle object pass the appropriate LibraryHandle to the
+// callout. These tests are done in the handles_unittest tests.
+TEST_F(CalloutManagerTest, LibraryHandleRegistration) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+
+ // Set up so that hooks "alpha" and "beta" have callouts attached from a
+ // different libraries.
+ getCalloutManager()->setLibraryIndex(0);
+ getCalloutManager()->getLibraryHandle().registerCallout("alpha", callout_one);
+ getCalloutManager()->getLibraryHandle().registerCallout("alpha", callout_two);
+ getCalloutManager()->setLibraryIndex(1);
+ getCalloutManager()->getLibraryHandle().registerCallout("alpha", callout_three);
+ getCalloutManager()->getLibraryHandle().registerCallout("alpha", callout_four);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected. (This is also a
+ // test of the callCallouts method.)
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ // Deregister a callout on library index 0 (after we check we can't
+ // deregister it through library index 1).
+ EXPECT_FALSE(getCalloutManager()->deregisterCallout("alpha", callout_two, 1));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ EXPECT_TRUE(getCalloutManager()->deregisterCallout("alpha", callout_two, 0));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(134, callout_value_);
+
+ // Deregister all callouts on library index 1.
+ EXPECT_TRUE(getCalloutManager()->deregisterAllCallouts("alpha", 1));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1, callout_value_);
+}
+
+// A repeat of the test above, but using the alternate constructor for the
+// LibraryHandle.
+TEST_F(CalloutManagerTest, LibraryHandleAlternateConstructor) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+
+ // Set up so that hooks "alpha" and "beta" have callouts attached from a
+ // different libraries.
+ LibraryHandle lh0(*getCalloutManager().get(), 0);
+ lh0.registerCallout("alpha", callout_one);
+ lh0.registerCallout("alpha", callout_two);
+
+ LibraryHandle lh1(*getCalloutManager().get(), 1);
+ lh1.registerCallout("alpha", callout_three);
+ lh1.registerCallout("alpha", callout_four);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected. (This is also a
+ // test of the callCallouts method.)
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ // Deregister a callout on library index 0 (after we check we can't
+ // deregister it through library index 1).
+ EXPECT_FALSE(lh1.deregisterCallout("alpha", callout_two));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ EXPECT_TRUE(lh0.deregisterCallout("alpha", callout_two));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(134, callout_value_);
+
+ // Deregister all callouts on library index 1.
+ EXPECT_TRUE(lh1.deregisterAllCallouts("alpha"));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1, callout_value_);
+}
+
+// Check that the pre- and post- user callout library handles work
+// appropriately with no user libraries.
+TEST_F(CalloutManagerTest, LibraryHandlePrePostNoLibraries) {
+ // Create a local callout manager and callout handle to reflect no libraries
+ // being loaded.
+ boost::shared_ptr<CalloutManager> manager(new CalloutManager(0));
+ CalloutHandle handle(manager);
+
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(manager->calloutsPresent(alpha_index_));
+
+ // Setup the pre-and post callouts.
+ manager->getPostLibraryHandle().registerCallout("alpha", callout_four);
+ manager->getPreLibraryHandle().registerCallout("alpha", callout_one);
+ // Check all is as expected.
+ EXPECT_TRUE(manager->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(manager->calloutsPresent(beta_index_));
+ EXPECT_FALSE(manager->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(manager->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected.
+ callout_value_ = 0;
+ manager->callCallouts(alpha_index_, handle);
+ EXPECT_EQ(14, callout_value_);
+
+ // Deregister the pre- library callout.
+ EXPECT_TRUE(manager->getPreLibraryHandle().deregisterAllCallouts("alpha"));
+ callout_value_ = 0;
+ manager->callCallouts(alpha_index_, handle);
+ EXPECT_EQ(4, callout_value_);
+}
+
+// Repeat the tests with one user library.
+TEST_F(CalloutManagerTest, LibraryHandlePrePostUserLibrary) {
+
+ // Setup the pre-, library and post callouts.
+ getCalloutManager()->getPostLibraryHandle().registerCallout("alpha",
+ callout_four);
+ getCalloutManager()->getPreLibraryHandle().registerCallout("alpha",
+ callout_one);
+
+ // ... and set up a callout in between, on library number 2.
+ LibraryHandle lh1(*getCalloutManager().get(), 2);
+ lh1.registerCallout("alpha", callout_five);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected.
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(154, callout_value_);
+}
+
+// Test that control command handlers can be installed as callouts.
+TEST_F(CalloutManagerTest, LibraryHandleRegisterCommandHandler) {
+ CalloutHandle handle(getCalloutManager());
+
+ // Simulate creation of the two hook libraries. Fist library implements two
+ // handlers for the control command 'command-one'. Second library implements
+ // two control command handlers: one for the 'command-one', another one for
+ // 'command-two'. Each of the handlers for the 'command-one' must be called
+ // and they must be called in the appropriate order. Command handler for
+ // 'command-two' should also be called.
+
+ getCalloutManager()->setLibraryIndex(0);
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-one", callout_one);
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-one", callout_four);
+ getCalloutManager()->setLibraryIndex(1);
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-one", callout_two);
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-two", callout_three);
+
+ // Command handlers are installed for commands: 'command-one' and 'command-two'.
+ EXPECT_TRUE(getCalloutManager()->commandHandlersPresent("command-one"));
+ EXPECT_TRUE(getCalloutManager()->commandHandlersPresent("command-two"));
+ // There should be no handlers installed for 'command-three' and 'command-four'.
+ EXPECT_FALSE(getCalloutManager()->commandHandlersPresent("command-three"));
+ EXPECT_FALSE(getCalloutManager()->commandHandlersPresent("command-four"));
+
+ // Call handlers for 'command-one'. There should be three handlers called in
+ // the following order: 1, 4, 2.
+ callout_value_ = 0;
+ ASSERT_NO_THROW(getCalloutManager()->callCommandHandlers("command-one", handle));
+ EXPECT_EQ(142, callout_value_);
+
+ // There should be one handler invoked for the 'command-two'. This handler has
+ // index of 3.
+ callout_value_ = 0;
+ ASSERT_NO_THROW(getCalloutManager()->callCommandHandlers("command-two", handle));
+ EXPECT_EQ(3, callout_value_);
+
+ // An attempt to call handlers for the commands for which no hook points
+ // were created should result in exception.
+ EXPECT_THROW(getCalloutManager()->callCommandHandlers("command-three", handle),
+ NoSuchHook);
+ EXPECT_THROW(getCalloutManager()->callCommandHandlers("command-four", handle),
+ NoSuchHook);
+}
+
+// This test checks if the CalloutManager can adjust its own hook_vector_ size.
+TEST_F(CalloutManagerTest, VectorSize) {
+
+ size_t s = getCalloutManager()->getHookLibsVectorSize();
+
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+
+ EXPECT_NO_THROW(hooks.registerHook("a_new_one"));
+
+ // Now load a callout. Name of the hook point the new callout is installed
+ // on doesn't matter. CM should do sanity checks and adjust anyway.
+ getCalloutManager()->getPostLibraryHandle().registerCallout("alpha",
+ callout_four);
+
+ // The vector size should have been increased by one, because there's
+ // one new hook point now.
+ EXPECT_EQ(s + 1, getCalloutManager()->getHookLibsVectorSize());
+}
+
+// The setting of the hook index is checked in the handles_unittest
+// set of tests, as access restrictions mean it is not easily tested
+// on its own.
+
+} // namespace
diff --git a/src/lib/hooks/tests/callout_params_library.cc b/src/lib/hooks/tests/callout_params_library.cc
new file mode 100644
index 0000000..d35fc00
--- /dev/null
+++ b/src/lib/hooks/tests/callout_params_library.cc
@@ -0,0 +1,129 @@
+// Copyright (C) 2016-2020 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/.
+
+/// @file
+/// @brief Callout Library
+///
+/// This is the source of a test library for the DHCP parser tests that
+/// specify parameters. It will attempt to obtain its own parameters.
+
+#include <config.h>
+#include <hooks/hooks.h>
+#include <iostream>
+
+using namespace std;
+using namespace isc::hooks;
+using namespace isc::data;
+
+extern "C" {
+
+// Framework functions
+int
+version() {
+ return (KEA_HOOKS_VERSION);
+}
+
+/// @brief This method will be called when the hook library is loaded
+///
+/// While its primary usage is for unit-testing, it also doubles as an
+/// illustration referred to from Hooks Developer's Guide. As such, please
+/// keep it simple, tidy and try to avoid referencing unnecessary code.
+/// Parts of it can be used as copy-paste examples.
+///
+/// @param handle passed by the hooks framework
+/// @return 0 if load was successful, non-zero for errors
+int load(LibraryHandle& handle) {
+ ConstElementPtr elems = handle.getParameters();
+ ConstElementPtr string_elem = handle.getParameter("svalue");
+ ConstElementPtr int_elem = handle.getParameter("ivalue");
+ ConstElementPtr bool_elem = handle.getParameter("bvalue");
+ ConstElementPtr nonexistent = handle.getParameter("nonexistent");
+ vector<string> names = handle.getParameterNames();
+
+ // String handling example.
+ if (!string_elem) {
+ // Parameter was not specified at all.
+ return (1);
+ }
+
+ if (string_elem->getType() != Element::string) {
+ // Parameter is specified, but it's not a string.
+ return (2);
+ }
+
+ string str = string_elem->stringValue();
+ if (str != "string value") {
+ // Parameter is specified, is a string, but has unexpected value.
+ //
+ // This library is used for testing, so it expects exact value of the
+ // parameter. Normal library would likely use whatever value user
+ // specified.
+ return (3);
+ }
+
+ // Integer handling example
+ if (!int_elem) {
+ // Parameter was not specified at all.
+ return (4);
+ }
+
+ if (int_elem->getType() != Element::integer) {
+ // Parameter is specified, but it's not an integer.
+ return (5);
+ }
+
+ int int_value = int_elem->intValue();
+ if (int_value != 42) {
+ // Parameter specified, is an integer, but has a value different than
+ // expected.
+ return (6);
+ }
+
+ // Boolean handling example
+ if (!bool_elem) {
+ // Parameter was not specified at all.
+ return (7);
+ }
+
+ if (bool_elem->getType() != Element::boolean) {
+ // Parameter is specified, but it's not a boolean.
+ return (8);
+ }
+
+ bool flag = bool_elem->boolValue();
+ if (flag != true) {
+ // Parameter specified, is a boolean, but has a value different than
+ // expected.
+ return (9);
+ }
+
+ // Check names. As a side effect of what maps using strings are
+ // implemented names are sorted in alphabetical order.
+ if ((names.size() != 3) || (names[0] != "bvalue") ||
+ (names[1] != "ivalue") || (names[2] != "svalue")) {
+ // Expect 3 names: bvalue, ivalue, svalue.
+ return (10);
+ }
+
+ // Check elems map.
+ if (!elems) {
+ return (11);
+ }
+ string expected_str = "{ "
+ "\"bvalue\": true, "
+ "\"ivalue\": 42, "
+ "\"svalue\": \"string value\""
+ " }";
+ if (expected_str != elems->str()) {
+ return (12);
+ }
+
+ // All validation steps were successful. The library has all the parameters
+ // it needs, so we should report a success.
+ return (0);
+}
+
+}
diff --git a/src/lib/hooks/tests/common_test_class.h b/src/lib/hooks/tests/common_test_class.h
new file mode 100644
index 0000000..aa34bcf
--- /dev/null
+++ b/src/lib/hooks/tests/common_test_class.h
@@ -0,0 +1,174 @@
+// Copyright (C) 2013-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 COMMON_HOOKS_TEST_CLASS_H
+#define COMMON_HOOKS_TEST_CLASS_H
+
+#include <hooks/callout_handle.h>
+#include <hooks/callout_manager.h>
+#include <hooks/server_hooks.h>
+#include <hooks/tests/marker_file.h>
+
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+/// @brief Common hooks test class
+///
+/// This class is a shared parent of the test fixture class in the tests of the
+/// higher-level hooks classes (LibraryManager, LibraryManagerCollection and
+/// HooksManager). It
+///
+/// - sets the ServerHooks object with three hooks and stores their
+/// indexes.
+/// - executes the callouts (which are assumed to perform a calculation)
+/// and checks the results.
+
+class HooksCommonTestClass {
+public:
+ /// @brief Constructor
+ HooksCommonTestClass() {
+
+ // Set up the server hooks. ServerHooks is a singleton, so we reset it
+ // between each test.
+ isc::hooks::ServerHooks& hooks =
+ isc::hooks::ServerHooks::getServerHooks();
+ hooks.reset();
+ hookpt_one_index_ = hooks.registerHook("hookpt_one");
+ hookpt_two_index_ = hooks.registerHook("hookpt_two");
+ hookpt_three_index_ = hooks.registerHook("hookpt_three");
+ }
+
+ /// @brief Call callouts test
+ ///
+ /// All of the loaded libraries for which callouts are called register four
+ /// callouts: a context_create callout and three callouts that are attached
+ /// to hooks hookpt_one, hookpt_two and hookpt_three. These four callouts,
+ /// executed in sequence, perform a series of calculations. Data is passed
+ /// between callouts in the argument list, in a variable named "result".
+ ///
+ /// context_create initializes the calculation by setting a seed
+ /// value, called r0 here. This value is dependent on the library being
+ /// loaded. Prior to that, the argument "result" is initialized to -1,
+ /// the purpose being to avoid exceptions when running this test with no
+ /// libraries loaded.
+ ///
+ /// Callout hookpt_one is passed a value d1 and performs a simple arithmetic
+ /// operation on it and r0 yielding a result r1. Hence we can say that
+ /// @f[ r1 = hookpt_one(r0, d1) @f]
+ ///
+ /// Callout hookpt_two is passed a value d2 and performs another simple
+ /// arithmetic operation on it and d2, yielding r2, i.e.
+ /// @f[ r2 = hookpt_two(d1, d2) @f]
+ ///
+ /// hookpt_three does a similar operation giving
+ /// @f[ r3 = hookpt_three(r2, d3) @f].
+ ///
+ /// The details of the operations hookpt_one, hookpt_two and hookpt_three
+ /// depend on the library, so the results obtained not only depend on
+ /// the data, but also on the library loaded. This method is passed both
+ /// data and expected results. It executes the three callouts in sequence,
+ /// checking the intermediate and final results. Only if the expected
+ /// library has been loaded correctly and the callouts in it registered
+ /// correctly will be the results be as expected.
+ ///
+ /// It is assumed that callout_manager_ has been set up appropriately.
+ ///
+ /// @note The CalloutHandle used in the calls is declared locally here.
+ /// The advantage of this (apart from scope reduction) is that on
+ /// exit, it is destroyed. This removes any references to memory
+ /// allocated by loaded libraries while they are still loaded.
+ ///
+ /// @param manager CalloutManager to use for the test
+ /// @param r0...r3, d1..d3 Data (dN) and expected results (rN) - both
+ /// intermediate and final. The arguments are ordered so that they
+ /// appear in the argument list in the order they are used.
+ void executeCallCallouts(
+ const boost::shared_ptr<isc::hooks::CalloutManager>& manager,
+ int r0, int d1, int r1, int d2, int r2, int d3, int r3) {
+ static const char* COMMON_TEXT = " callout returned the wrong value";
+ static const char* RESULT = "result";
+
+ int result;
+
+ // Set up a callout handle for the calls.
+ isc::hooks::CalloutHandle handle(manager);
+
+ // Initialize the argument RESULT. This simplifies testing by
+ // eliminating the generation of an exception when we try the unload
+ // test. In that case, RESULT is unchanged.
+ handle.setArgument(RESULT, -1);
+
+ // Seed the calculation.
+ manager->callCallouts(isc::hooks::ServerHooks::CONTEXT_CREATE, handle);
+ handle.getArgument(RESULT, result);
+ EXPECT_EQ(r0, result) << "context_create" << COMMON_TEXT;
+
+ // Perform the first calculation.
+ handle.setArgument("data_1", d1);
+ manager->callCallouts(hookpt_one_index_, handle);
+ handle.getArgument(RESULT, result);
+ EXPECT_EQ(r1, result) << "hookpt_one" << COMMON_TEXT;
+
+ // ... the second ...
+ handle.setArgument("data_2", d2);
+ manager->callCallouts(hookpt_two_index_, handle);
+ handle.getArgument(RESULT, result);
+ EXPECT_EQ(r2, result) << "hookpt_two" << COMMON_TEXT;
+
+ // ... and the third.
+ handle.setArgument("data_3", d3);
+ manager->callCallouts(hookpt_three_index_, handle);
+ handle.getArgument(RESULT, result);
+ EXPECT_EQ(r3, result) << "hookpt_three" << COMMON_TEXT;
+ }
+
+ /// @brief Call command handlers test.
+ ///
+ /// This test is similar to @c executeCallCallouts but it uses
+ /// @ref CalloutManager::callCommandHandlers to execute the command
+ /// handlers for the following commands: 'command-one' and 'command-two'.
+ ///
+ /// @param manager CalloutManager to use for the test
+ /// @param r1..r2, d1..d2 Data (dN) and expected results (rN).
+ void executeCallCommandHandlers(
+ const boost::shared_ptr<isc::hooks::CalloutManager>& manager,
+ int d1, int r1, int d2, int r2) {
+ static const char* COMMON_TEXT = " command handler returned the wrong value";
+ static const char* RESULT = "result";
+
+ int result;
+
+ // Set up a callout handle for the calls.
+ isc::hooks::CalloutHandle handle(manager);
+
+ // Initialize the argument RESULT. This simplifies testing by
+ // eliminating the generation of an exception when we try the unload
+ // test. In that case, RESULT is unchanged.
+ handle.setArgument(RESULT, -1);
+
+ // Perform the first calculation: it should assign the data to the
+ // result.
+ handle.setArgument("data_1", d1);
+ manager->callCommandHandlers("command-one", handle);
+ handle.getArgument(RESULT, result);
+ EXPECT_EQ(r1, result) << "command-one" << COMMON_TEXT;
+
+ // Perform the second calculation: it should multiply the data by 10
+ // and return in the result.
+ handle.setArgument("data_2", d2);
+ manager->callCommandHandlers("command-two", handle);
+ handle.getArgument(RESULT, result);
+ EXPECT_EQ(r2, result) << "command-two" << COMMON_TEXT;
+ }
+
+
+ /// Hook indexes. These are are made public for ease of reference.
+ int hookpt_one_index_;
+ int hookpt_two_index_;
+ int hookpt_three_index_;
+};
+
+#endif // COMMON_HOOKS_TEST_CLASS_H
diff --git a/src/lib/hooks/tests/framework_exception_library.cc b/src/lib/hooks/tests/framework_exception_library.cc
new file mode 100644
index 0000000..c60c3f8
--- /dev/null
+++ b/src/lib/hooks/tests/framework_exception_library.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2013-2015 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/.
+
+/// @file
+/// @brief Framework exception library
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - All three framework functions are supplied (version(), load() and
+/// unload()) and all generate an exception.
+
+#include <config.h>
+
+#include <hooks/hooks.h>
+
+#include <exception>
+
+extern "C" {
+
+int
+version() {
+ throw std::exception();
+}
+
+int
+load(isc::hooks::LibraryHandle& /*handle*/) {
+ throw std::exception();
+}
+
+int
+unload() {
+ throw std::exception();
+}
+
+};
+
diff --git a/src/lib/hooks/tests/full_callout_library.cc b/src/lib/hooks/tests/full_callout_library.cc
new file mode 100644
index 0000000..58ea8c7
--- /dev/null
+++ b/src/lib/hooks/tests/full_callout_library.cc
@@ -0,0 +1,177 @@
+// Copyright (C) 2013-2020 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/.
+
+/// @file
+/// @brief Full callout library
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// The characteristics of this library are:
+///
+/// - All four framework functions are supplied (version(), load(),
+/// unload() and multi_threading_compatible()), with unload()
+/// creating a marker file. The test code checks for the presence
+/// of this file, so verifying that unload() has been run.
+///
+/// - One standard and two non-standard callouts are supplied, with the latter
+/// being registered by the load() function.
+///
+/// All callouts do trivial calculations, the result of all being called in
+/// sequence being
+///
+/// @f[ ((7 * data_1) - data_2) * data_3 @f]
+///
+/// ...where data_1, data_2 and data_3 are the values passed in arguments of
+/// the same name to the three callouts (data_1 passed to hookpt_one, data_2
+/// to hookpt_two etc.) and the result is returned in the argument "result".
+
+#include <config.h>
+
+#include <hooks/hooks.h>
+#include <hooks/tests/marker_file.h>
+
+#include <fstream>
+
+using namespace isc::hooks;
+
+extern "C" {
+
+// Callouts
+
+int
+context_create(CalloutHandle& handle) {
+ handle.setContext("result", static_cast<int>(7));
+ handle.setArgument("result", static_cast<int>(7));
+ return (0);
+}
+
+// First callout adds the passed "data_1" argument to the initialized context
+// value of 7. (Note that the value set by context_create is accessed through
+// context and not the argument, so checking that context is correctly passed
+// between callouts in the same library.)
+
+int
+hookpt_one(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_1", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result *= data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Second callout subtracts the passed value of data_2 from the current
+// running total.
+
+static int
+hook_nonstandard_two(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_2", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result -= data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Final callout multiplies the current running total by data_3.
+
+static int
+hook_nonstandard_three(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_3", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result *= data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// First command handler assigns data to a result.
+
+static int
+command_handler_one(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_1", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result = data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Second command handler multiples the result by data by 10.
+
+static int
+command_handler_two(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_2", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result *= data * 10;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Framework functions
+
+int
+version() {
+ return (KEA_HOOKS_VERSION);
+}
+
+int
+load(LibraryHandle& handle) {
+ // Initialize if the main image was statically linked
+#ifdef USE_STATIC_LINK
+ hooksStaticLinkInit();
+#endif
+ // Register the non-standard functions
+ handle.registerCallout("hookpt_two", hook_nonstandard_two);
+ handle.registerCallout("hookpt_three", hook_nonstandard_three);
+
+ // Register command_handler_one as control command handler.
+ handle.registerCommandCallout("command-one", command_handler_one);
+ handle.registerCommandCallout("command-two", command_handler_two);
+
+ return (0);
+}
+
+int
+unload() {
+ // Create the marker file.
+ std::fstream marker;
+ marker.open(MARKER_FILE, std::fstream::out);
+ marker.close();
+
+ return (0);
+}
+
+int
+multi_threading_compatible() {
+ return (1);
+}
+
+};
+
diff --git a/src/lib/hooks/tests/handles_unittest.cc b/src/lib/hooks/tests/handles_unittest.cc
new file mode 100644
index 0000000..a9292d8
--- /dev/null
+++ b/src/lib/hooks/tests/handles_unittest.cc
@@ -0,0 +1,777 @@
+// Copyright (C) 2013-2020 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/.
+
+#include <config.h>
+
+#include <hooks/callout_handle.h>
+#include <hooks/callout_manager.h>
+#include <hooks/library_handle.h>
+#include <hooks/server_hooks.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <string>
+
+/// @file
+/// CalloutHandle/LibraryHandle interaction tests
+///
+/// This file holds unit tests checking the interaction between the
+/// CalloutHandle/LibraryHandle and CalloutManager classes. In particular,
+/// they check that:
+///
+/// - A CalloutHandle's context is shared between callouts from the same
+/// library, but there is a separate context for each library.
+///
+/// - The various methods manipulating the items in the CalloutHandle's context
+/// work correctly.
+///
+/// - An active callout can only modify the registration of callouts registered
+/// by its own library.
+
+using namespace isc::hooks;
+using namespace std;
+
+namespace {
+
+class HandlesTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ ///
+ /// Sets up the various elements used in each test.
+ HandlesTest() {
+ // Set up four hooks, although through gamma
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+ alpha_index_ = hooks.registerHook("alpha");
+ beta_index_ = hooks.registerHook("beta");
+ gamma_index_ = hooks.registerHook("gamma");
+ delta_index_ = hooks.registerHook("delta");
+
+ // Set up for three libraries.
+ manager_.reset(new CalloutManager(3));
+
+ // Initialize remaining variables.
+ common_string_ = "";
+ }
+
+ /// @brief Return callout manager
+ boost::shared_ptr<CalloutManager> getCalloutManager() {
+ return (manager_);
+ }
+
+ /// Hook indexes - these are frequently accessed, so are accessed directly.
+ int alpha_index_;
+ int beta_index_;
+ int gamma_index_;
+ int delta_index_;
+
+ /// String accessible by all callouts whatever the library
+ static std::string common_string_;
+
+private:
+ /// Callout manager. Declared static so that the callout functions can
+ /// access it.
+ boost::shared_ptr<CalloutManager> manager_;
+};
+
+/// Define the common string
+std::string HandlesTest::common_string_;
+
+
+// The next set of functions define the callouts used by the tests. They
+// manipulate the data in such a way that callouts called - and the order in
+// which they were called - can be determined. The functions also check that
+// the "callout context" data areas are separate.
+//
+// Three libraries are assumed, and each supplies four callouts. All callouts
+// manipulate two context elements the CalloutHandle, the elements being called
+// "string" and "int" (which describe the type of data manipulated).
+//
+// For the string item, each callout shifts data to the left and inserts its own
+// data. The data is a string of the form "nmc", where "n" is the number of
+// the library, "m" is the callout number and "y" is the indication of what
+// callout handle was passed as an argument ("1" or "2": "0" is used when no
+// identification has been set in the callout handle).
+//
+// For simplicity, and to cut down the number of functions actually written,
+// the callout indicator ("1" or "2") ) used in the in the CalloutHandle
+// functions is passed via a CalloutArgument. The argument is named "string":
+// use of a name the same as that of one of the context elements serves as a
+// check that the argument name space and argument context space are separate.
+//
+// For integer data, the value starts at zero and an increment is added on each
+// call. This increment is equal to:
+//
+// 100 * library number + 10 * callout number + callout handle
+//
+// Although this gives less information than the string value, the reasons for
+// using it are:
+//
+// - It is a separate item in the context, so checks that the context can
+// handle multiple items.
+// - It provides an item that can be deleted by the context deletion
+// methods.
+
+
+// Values set in the CalloutHandle context. There are three libraries, so
+// there are three contexts for the callout, one for each library.
+
+std::string& resultCalloutString(int index) {
+ static std::string result_callout_string[3];
+ return (result_callout_string[index]);
+}
+
+int& resultCalloutInt(int index) {
+ static int result_callout_int[3];
+ return (result_callout_int[index]);
+}
+
+// A simple function to zero the results.
+
+static void zero_results() {
+ for (int i = 0; i < 3; ++i) {
+ resultCalloutString(i) = "";
+ resultCalloutInt(i) = 0;
+ }
+}
+
+
+// Library callouts.
+
+// Common code for setting the callout context values.
+
+int
+execute(CalloutHandle& callout_handle, int library_num, int callout_num) {
+
+ // Obtain the callout handle number
+ int handle_num = 0;
+ try {
+ callout_handle.getArgument("handle_num", handle_num);
+ } catch (const NoSuchArgument&) {
+ // handle_num argument not set: this is the case in the tests where
+ // the context_create hook check is tested.
+ handle_num = 0;
+ }
+
+ // Create the basic data to be appended to the context value.
+ int idata = 100 * library_num + 10 * callout_num + handle_num;
+ string sdata = boost::lexical_cast<string>(idata);
+
+ // Get the context data. As before, this will not exist for the first
+ // callout called. (In real life, the library should create it when the
+ // "context_create" hook gets called before any packet processing takes
+ // place.)
+ int int_value = 0;
+ try {
+ callout_handle.getContext("int", int_value);
+ } catch (const NoSuchCalloutContext&) {
+ int_value = 0;
+ }
+
+ string string_value = "";
+ try {
+ callout_handle.getContext("string", string_value);
+ } catch (const NoSuchCalloutContext&) {
+ string_value = "";
+ }
+
+ // Update the values and set them back in the callout context.
+ int_value += idata;
+ callout_handle.setContext("int", int_value);
+
+ string_value += sdata;
+ callout_handle.setContext("string", string_value);
+
+ return (0);
+}
+
+// The following functions are the actual callouts - the name is of the
+// form "callout_<library number>_<callout number>"
+
+int
+callout11(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 1, 1));
+}
+
+int
+callout12(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 1, 2));
+}
+
+int
+callout13(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 1, 3));
+}
+
+int
+callout21(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 2, 1));
+}
+
+int
+callout22(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 2, 2));
+}
+
+int
+callout23(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 2, 3));
+}
+
+int
+callout31(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 3, 1));
+}
+
+int
+callout32(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 3, 2));
+}
+
+int
+callout33(CalloutHandle& callout_handle) {
+ return (execute(callout_handle, 3, 3));
+}
+
+// Common callout code for the fourth hook (which makes the data available for
+// checking). It copies the library and callout context data to the global
+// variables.
+
+int printExecute(CalloutHandle& callout_handle, int library_num) {
+ callout_handle.getContext("string", resultCalloutString(library_num - 1));
+ callout_handle.getContext("int", resultCalloutInt(library_num - 1));
+
+ return (0);
+}
+
+// These are the actual callouts.
+
+int
+print1(CalloutHandle& callout_handle) {
+ return (printExecute(callout_handle, 1));
+}
+
+int
+print2(CalloutHandle& callout_handle) {
+ return (printExecute(callout_handle, 2));
+}
+
+int
+print3(CalloutHandle& callout_handle) {
+ return (printExecute(callout_handle, 3));
+}
+
+// This test checks the many-faced nature of the context for the CalloutContext.
+
+TEST_F(HandlesTest, ContextAccessCheck) {
+ // Register callouts for the different libraries.
+ CalloutHandle handle(getCalloutManager());
+
+ getCalloutManager()->registerCallout("alpha", callout11, 0);
+ getCalloutManager()->registerCallout("beta", callout12, 0);
+ getCalloutManager()->registerCallout("gamma", callout13, 0);
+ getCalloutManager()->registerCallout("delta", print1, 0);
+
+ getCalloutManager()->registerCallout("alpha", callout21, 1);
+ getCalloutManager()->registerCallout("beta", callout22, 1);
+ getCalloutManager()->registerCallout("gamma", callout23, 1);
+ getCalloutManager()->registerCallout("delta", print2, 1);
+
+ getCalloutManager()->registerCallout("alpha", callout31, 2);
+ getCalloutManager()->registerCallout("beta", callout32, 2);
+ getCalloutManager()->registerCallout("gamma", callout33, 2);
+ getCalloutManager()->registerCallout("delta", print3, 2);
+
+ // Create the callout handles and distinguish them by setting the
+ // "handle_num" argument.
+ CalloutHandle callout_handle_1(getCalloutManager());
+ callout_handle_1.setArgument("handle_num", static_cast<int>(1));
+
+ CalloutHandle callout_handle_2(getCalloutManager());
+ callout_handle_2.setArgument("handle_num", static_cast<int>(2));
+
+ // Now call the callouts attached to the first three hooks. Each hook is
+ // called twice (once for each callout handle) before the next hook is
+ // called.
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
+ getCalloutManager()->callCallouts(beta_index_, callout_handle_1);
+ getCalloutManager()->callCallouts(beta_index_, callout_handle_2);
+ getCalloutManager()->callCallouts(gamma_index_, callout_handle_1);
+ getCalloutManager()->callCallouts(gamma_index_, callout_handle_2);
+
+ // Get the results for each callout (the callout on hook "delta" copies
+ // the context values into a location the test can access). Explicitly
+ // zero the variables before getting the results so we are certain that
+ // the values are the results of the callouts.
+
+ zero_results();
+
+ // To explain the expected callout context results.
+ //
+ // Each callout handle maintains a separate context for each library. When
+ // the first call to callCallouts() is made, "111" gets appended to
+ // the context for library 1 maintained by the first callout handle, "211"
+ // gets appended to the context maintained for library 2, and "311" to
+ // the context maintained for library 3. In each case, the first digit
+ // corresponds to the library number, the second to the callout number and
+ // the third to the "handle_num" of the callout handle. For the first call
+ // to callCallouts, handle 1 is used, so the last digit is always 1.
+ //
+ // The next call to callCallouts() calls the same callouts but for the
+ // second callout handle. It also maintains three contexts (one for
+ // each library) and they will get "112", "212", "312" appended to
+ // them. The explanation for the digits is the same as before, except that
+ // in this case, the callout handle is number 2, so the third digit is
+ // always 2. These additions don't affect the contexts maintained by
+ // callout handle 1.
+ //
+ // The process is then repeated for hooks "beta" and "gamma" which, for
+ // callout handle 1, append "121", "221" and "321" for hook "beta" and
+ // "311", "321" and "331" for hook "gamma".
+ //
+ // The expected integer values can be found by summing up the values
+ // corresponding to the elements of the strings.
+
+ // At this point, we have only called the "print" function for callout
+ // handle "1", so the following results are checking the context values
+ // maintained in that callout handle.
+
+ getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
+ EXPECT_EQ("111121131", resultCalloutString(0));
+ EXPECT_EQ("211221231", resultCalloutString(1));
+ EXPECT_EQ("311321331", resultCalloutString(2));
+
+ EXPECT_EQ((111 + 121 + 131), resultCalloutInt(0));
+ EXPECT_EQ((211 + 221 + 231), resultCalloutInt(1));
+ EXPECT_EQ((311 + 321 + 331), resultCalloutInt(2));
+
+ // Repeat the checks for callout 2.
+
+ zero_results();
+ getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
+
+ EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0));
+ EXPECT_EQ((212 + 222 + 232), resultCalloutInt(1));
+ EXPECT_EQ((312 + 322 + 332), resultCalloutInt(2));
+
+ EXPECT_EQ("112122132", resultCalloutString(0));
+ EXPECT_EQ("212222232", resultCalloutString(1));
+ EXPECT_EQ("312322332", resultCalloutString(2));
+}
+
+// Now repeat the test, but add a deletion callout to the list. The "beta"
+// hook of library 2 will have an additional callout to delete the "int"
+// element: the same hook for library 3 will delete both elements. In
+// addition, the names of context elements for the libraries at this point
+// will be printed.
+
+// List of context item names.
+
+vector<string>&
+getItemNames(int index) {
+ static vector<string> context_items[3];
+ return (context_items[index]);
+}
+
+// Context item deletion functions.
+
+int
+deleteIntContextItem(CalloutHandle& handle) {
+ handle.deleteContext("int");
+ return (0);
+}
+
+int
+deleteAllContextItems(CalloutHandle& handle) {
+ handle.deleteAllContext();
+ return (0);
+}
+
+// Generic print function - copy names in sorted order.
+
+int
+printContextNamesExecute(CalloutHandle& handle, int library_num) {
+ const int index = library_num - 1;
+ getItemNames(index) = handle.getContextNames();
+ sort(getItemNames(index).begin(), getItemNames(index).end());
+ return (0);
+}
+
+int
+printContextNames1(CalloutHandle& handle) {
+ return (printContextNamesExecute(handle, 1));
+}
+
+int
+printContextNames2(CalloutHandle& handle) {
+ return (printContextNamesExecute(handle, 2));
+}
+
+int
+printContextNames3(CalloutHandle& handle) {
+ return (printContextNamesExecute(handle, 3));
+}
+
+// Perform the test including deletion of context items.
+
+TEST_F(HandlesTest, ContextDeletionCheck) {
+ getCalloutManager()->registerCallout("alpha", callout11, 0);
+ getCalloutManager()->registerCallout("beta", callout12, 0);
+ getCalloutManager()->registerCallout("beta", printContextNames1, 0);
+ getCalloutManager()->registerCallout("gamma", callout13, 0);
+ getCalloutManager()->registerCallout("delta", print1, 0);
+
+ getCalloutManager()->registerCallout("alpha", callout21, 1);
+ getCalloutManager()->registerCallout("beta", callout22, 1);
+ getCalloutManager()->registerCallout("beta", deleteIntContextItem, 1);
+ getCalloutManager()->registerCallout("beta", printContextNames2, 1);
+ getCalloutManager()->registerCallout("gamma", callout23, 1);
+ getCalloutManager()->registerCallout("delta", print2, 1);
+
+ getCalloutManager()->registerCallout("alpha", callout31, 2);
+ getCalloutManager()->registerCallout("beta", callout32, 2);
+ getCalloutManager()->registerCallout("beta", deleteAllContextItems, 2);
+ getCalloutManager()->registerCallout("beta", printContextNames3, 2);
+ getCalloutManager()->registerCallout("gamma", callout33, 2);
+ getCalloutManager()->registerCallout("delta", print3, 2);
+
+ // Create the callout handles and distinguish them by setting the "long"
+ // argument.
+ CalloutHandle callout_handle_1(getCalloutManager());
+ callout_handle_1.setArgument("handle_num", static_cast<int>(1));
+
+ CalloutHandle callout_handle_2(getCalloutManager());
+ callout_handle_2.setArgument("handle_num", static_cast<int>(2));
+
+ // Now call the callouts attached to the first three hooks. Each hook is
+ // called twice (once for each callout handle) before the next hook is
+ // called.
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle_1);
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle_2);
+ getCalloutManager()->callCallouts(beta_index_, callout_handle_1);
+ getCalloutManager()->callCallouts(beta_index_, callout_handle_2);
+ getCalloutManager()->callCallouts(gamma_index_, callout_handle_1);
+ getCalloutManager()->callCallouts(gamma_index_, callout_handle_2);
+
+ // Get the results for each callout. Explicitly zero the variables before
+ // getting the results so we are certain that the values are the results
+ // of the callouts.
+
+ zero_results();
+ getCalloutManager()->callCallouts(delta_index_, callout_handle_1);
+
+ // The logic by which the expected results are arrived at is described
+ // in the ContextAccessCheck test. The results here are different
+ // because context items have been modified along the way.
+
+ EXPECT_EQ((111 + 121 + 131), resultCalloutInt(0));
+ EXPECT_EQ(( 231), resultCalloutInt(1));
+ EXPECT_EQ(( 331), resultCalloutInt(2));
+
+ EXPECT_EQ("111121131", resultCalloutString(0));
+ EXPECT_EQ("211221231", resultCalloutString(1));
+ EXPECT_EQ( "331", resultCalloutString(2));
+
+ // Repeat the checks for callout handle 2.
+
+ zero_results();
+ getCalloutManager()->callCallouts(delta_index_, callout_handle_2);
+
+ EXPECT_EQ((112 + 122 + 132), resultCalloutInt(0));
+ EXPECT_EQ(( 232), resultCalloutInt(1));
+ EXPECT_EQ(( 332), resultCalloutInt(2));
+
+ EXPECT_EQ("112122132", resultCalloutString(0));
+ EXPECT_EQ("212222232", resultCalloutString(1));
+ EXPECT_EQ( "332", resultCalloutString(2));
+
+ // ... and check what the names of the context items are after the callouts
+ // for hook "beta". We know they are in sorted order.
+
+ EXPECT_EQ(2, getItemNames(0).size());
+ EXPECT_EQ(string("int"), getItemNames(0)[0]);
+ EXPECT_EQ(string("string"), getItemNames(0)[1]);
+
+ EXPECT_EQ(1, getItemNames(1).size());
+ EXPECT_EQ(string("string"), getItemNames(1)[0]);
+
+ EXPECT_EQ(0, getItemNames(2).size());
+}
+
+// Tests that the CalloutHandle's constructor and destructor call the
+// context_create and context_destroy callbacks (if registered). For
+// simplicity, we'll use the same callout functions as used above.
+
+TEST_F(HandlesTest, ConstructionDestructionCallouts) {
+
+ // Register context callouts.
+ getCalloutManager()->registerCallout("context_create", callout11, 0);
+ getCalloutManager()->registerCallout("context_create", print1, 0);
+ getCalloutManager()->registerCallout("context_destroy", callout12, 0);
+ getCalloutManager()->registerCallout("context_destroy", print1, 0);
+
+ // Create the CalloutHandle and check that the constructor callout
+ // has run.
+ zero_results();
+ boost::scoped_ptr<CalloutHandle>
+ callout_handle(new CalloutHandle(getCalloutManager()));
+ EXPECT_EQ("110", resultCalloutString(0));
+ EXPECT_EQ(110, resultCalloutInt(0));
+
+ // Check that the destructor callout runs. Note that the "print1" callout
+ // didn't destroy the library context - it only copied it to where it
+ // could be examined. As a result, the destructor callout appends its
+ // elements to the constructor's values and the result is printed.
+ zero_results();
+ callout_handle.reset();
+
+ EXPECT_EQ("110120", resultCalloutString(0));
+ EXPECT_EQ((110 + 120), resultCalloutInt(0));
+}
+
+// Testing the operation of the "skip" flag. Callouts print the value
+// they see in the flag and either leave it unchanged, set it or clear it.
+int
+calloutPrintSkip(CalloutHandle& handle) {
+ static const std::string YES("Y");
+ static const std::string NO("N");
+ static const std::string DROP("D");
+ static const std::string PARK("P");
+
+ switch (handle.getStatus()) {
+ case CalloutHandle::NEXT_STEP_CONTINUE:
+ HandlesTest::common_string_ += NO; // skip = no
+ break;
+ case CalloutHandle::NEXT_STEP_SKIP:
+ HandlesTest::common_string_ += YES; // skip = yes
+ break;
+ case CalloutHandle::NEXT_STEP_DROP:
+ HandlesTest::common_string_ += DROP; // drop
+ break;
+ case CalloutHandle::NEXT_STEP_PARK:
+ HandlesTest::common_string_ += PARK; // park
+ break;
+ }
+ return (0);
+}
+
+int
+calloutSetSkip(CalloutHandle& handle) {
+ static_cast<void>(calloutPrintSkip(handle));
+ handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ return (0);
+}
+
+int
+calloutClearSkip(CalloutHandle& handle) {
+ static_cast<void>(calloutPrintSkip(handle));
+ handle.setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+ return (0);
+}
+
+// Do a series of tests, returning with the skip flag set "true".
+
+TEST_F(HandlesTest, ReturnSkipSet) {
+ getCalloutManager()->registerCallout("alpha", calloutPrintSkip, 0);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 0);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 0);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 0);
+
+ getCalloutManager()->registerCallout("alpha", calloutPrintSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 1);
+
+ getCalloutManager()->registerCallout("alpha", calloutPrintSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 2);
+
+ CalloutHandle callout_handle(getCalloutManager());
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle);
+
+ // Check result. For ease of visual checking, the expected string is
+ // divided into sections corresponding to the blocks of callouts above.
+ EXPECT_EQ(std::string("NNYY" "NNYYN" "NNYN"), common_string_);
+
+ // ... and check that the skip flag on exit from callCallouts is set.
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, callout_handle.getStatus());
+}
+
+// Repeat the test, returning with the skip flag clear.
+TEST_F(HandlesTest, ReturnSkipClear) {
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 0);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 0);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 0);
+
+ getCalloutManager()->registerCallout("alpha", calloutPrintSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 1);
+
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutPrintSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutClearSkip, 2);
+
+ CalloutHandle callout_handle(getCalloutManager());
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle);
+
+ // Check result. For ease of visual checking, the expected string is
+ // divided into sections corresponding to the blocks of callouts above.
+ EXPECT_EQ(std::string("NYY" "NNYNYN" "NNNY"), common_string_);
+
+ // ... and check that the skip flag on exit from callCallouts is set.
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle.getStatus());
+}
+
+// Check that the skip flag is cleared when callouts are called - even if
+// there are no callouts.
+
+TEST_F(HandlesTest, NoCalloutsSkipTest) {
+ // Note - no callouts are registered on any hook.
+ CalloutHandle callout_handle(getCalloutManager());
+
+ // Clear the skip flag and call a hook with no callouts.
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle.getStatus());
+
+ // Set the skip flag and call a hook with no callouts.
+ callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle);
+ EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle.getStatus());
+}
+
+// The next set of callouts do a similar thing to the above "skip" tests,
+// but alter the value of a string argument. This is for testing that the
+// a callout is able to change an argument and return it to the caller.
+
+const char* MODIFIED_ARG = "modified_arg";
+
+int
+calloutSetArgumentCommon(CalloutHandle& handle, const char* what) {
+ std::string modified_arg = "";
+
+ handle.getArgument(MODIFIED_ARG, modified_arg);
+ modified_arg = modified_arg + std::string(what);
+ handle.setArgument(MODIFIED_ARG, modified_arg);
+ return (0);
+}
+
+int
+calloutSetArgumentSkip(CalloutHandle& handle) {
+ return (calloutSetArgumentCommon(handle, "S"));
+}
+
+int
+calloutSetArgumentContinue(CalloutHandle& handle) {
+ return (calloutSetArgumentCommon(handle, "C"));
+}
+
+int
+calloutSetArgumentDrop(CalloutHandle& handle) {
+ return (calloutSetArgumentCommon(handle, "D"));
+}
+
+int
+calloutSetArgumentPark(CalloutHandle& handle) {
+ return (calloutSetArgumentCommon(handle, "P"));
+}
+
+// ... and a callout to just copy the argument to the "common_string_" variable
+// but otherwise not alter it.
+
+int
+calloutPrintArgument(CalloutHandle& handle) {
+ handle.getArgument(MODIFIED_ARG, HandlesTest::common_string_);
+ return (0);
+}
+
+// This test verifies that the next step status is processed appropriately.
+// The test checks the following next step statuses: CONTINUE, SKIP, DROP.
+TEST_F(HandlesTest, CheckModifiedArgument) {
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentSkip, 0);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentContinue, 0);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentContinue, 0);
+
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentSkip, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentDrop, 1);
+ getCalloutManager()->registerCallout("alpha", calloutPrintArgument, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentDrop, 1);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentContinue, 1);
+
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentContinue, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentPark, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentSkip, 2);
+ getCalloutManager()->registerCallout("alpha", calloutSetArgumentPark, 2);
+
+ // Create the argument with an initial empty string value. Then call the
+ // sequence of callouts above.
+ CalloutHandle callout_handle(getCalloutManager());
+ std::string modified_arg = "";
+ callout_handle.setArgument(MODIFIED_ARG, modified_arg);
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle);
+
+ // Check the intermediate and results. For visual checking, the expected
+ // string is divided into sections corresponding to the blocks of callouts
+ // above.
+ EXPECT_EQ(std::string("SCC" "SD"), common_string_);
+
+ callout_handle.getArgument(MODIFIED_ARG, modified_arg);
+ EXPECT_EQ(std::string("SCC" "SDDC" "SCPSP"), modified_arg);
+}
+
+// Test that the CalloutHandle provides the name of the hook to which the
+// callout is attached.
+
+int
+callout_hook_name(CalloutHandle& callout_handle) {
+ HandlesTest::common_string_ = callout_handle.getHookName();
+ return (0);
+}
+
+int
+callout_hook_dummy(CalloutHandle&) {
+ return (0);
+}
+
+TEST_F(HandlesTest, HookName) {
+ getCalloutManager()->registerCallout("alpha", callout_hook_name, 0);
+ getCalloutManager()->registerCallout("beta", callout_hook_name, 0);
+
+ // Call alpha and beta callouts and check the hook to which they belong.
+ CalloutHandle callout_handle(getCalloutManager());
+
+ EXPECT_EQ(std::string(""), HandlesTest::common_string_);
+
+ getCalloutManager()->callCallouts(alpha_index_, callout_handle);
+ EXPECT_EQ(std::string("alpha"), HandlesTest::common_string_);
+
+ getCalloutManager()->callCallouts(beta_index_, callout_handle);
+ EXPECT_EQ(std::string("beta"), HandlesTest::common_string_);
+
+ // Make sure that the callout accesses the name even if it is not the
+ // only callout in the list.
+ getCalloutManager()->registerCallout("gamma", callout_hook_dummy, 1);
+ getCalloutManager()->registerCallout("gamma", callout_hook_name, 1);
+ getCalloutManager()->registerCallout("gamma", callout_hook_dummy, 1);
+
+ EXPECT_EQ(std::string("beta"), HandlesTest::common_string_);
+ getCalloutManager()->callCallouts(gamma_index_, callout_handle);
+ EXPECT_EQ(std::string("gamma"), HandlesTest::common_string_);
+}
+
+} // Anonymous namespace
+
diff --git a/src/lib/hooks/tests/hooks_manager_unittest.cc b/src/lib/hooks/tests/hooks_manager_unittest.cc
new file mode 100644
index 0000000..a36d42c
--- /dev/null
+++ b/src/lib/hooks/tests/hooks_manager_unittest.cc
@@ -0,0 +1,1081 @@
+// Copyright (C) 2013-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/.
+
+#include <config.h>
+
+#include <hooks/callout_handle.h>
+#include <hooks/hooks_manager.h>
+#include <hooks/server_hooks.h>
+
+#include <hooks/tests/common_test_class.h>
+#define TEST_ASYNC_CALLOUT
+#include <hooks/tests/test_libraries.h>
+#include <cc/data.h>
+
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <fstream>
+#include <string>
+
+#include <unistd.h>
+
+using namespace isc;
+using namespace isc::hooks;
+using namespace isc::data;
+using namespace std;
+
+namespace {
+
+/// @brief Hooks manager collection test class
+
+class HooksManagerTest : public ::testing::Test,
+ public HooksCommonTestClass {
+public:
+ /// @brief Constructor
+ ///
+ /// Reset the hooks manager. The hooks manager is a singleton, so needs
+ /// to be reset for each test.
+ HooksManagerTest() {
+ HooksManager::setTestMode(false);
+ HooksManager::prepareUnloadLibraries();
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture ctor) unloadLibraries failed" << endl;
+ }
+ // Ensure the marker file is not present at the start of a test.
+ static_cast<void>(remove(MARKER_FILE));
+ }
+
+ /// @brief Destructor
+ ///
+ /// Unload all libraries.
+ ~HooksManagerTest() {
+ static_cast<void>(remove(MARKER_FILE));
+ HooksManager::setTestMode(false);
+ HooksManager::prepareUnloadLibraries();
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture dtor) unloadLibraries failed" << endl;
+ }
+ }
+
+ /// @brief Marker file present
+ ///
+ /// Convenience function to check whether a marker file is present. It
+ /// does this by opening the file.
+ ///
+ /// @return true if the marker file is present.
+ bool markerFilePresent() const {
+
+ // Try to open it.
+ std::fstream marker;
+ marker.open(MARKER_FILE, std::fstream::in);
+
+ // Check if it is open and close it if so.
+ bool exists = marker.is_open();
+ if (exists) {
+ marker.close();
+ }
+
+ return (exists);
+ }
+
+ /// @brief Call callouts test
+ ///
+ /// See the header for HooksCommonTestClass::execute for details.
+ ///
+ /// @param r0...r3, d1..d3 Values and intermediate values expected. They
+ /// are ordered so that the variables appear in the argument list in
+ /// the order they are used.
+ void executeCallCallouts(int r0, int d1, int r1, int d2, int r2, int d3,
+ int r3) {
+ static const char* COMMON_TEXT = " callout returned the wrong value";
+ static const char* RESULT = "result";
+
+ // Get a CalloutHandle for the calculation.
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // Initialize the argument RESULT. This simplifies testing by
+ // eliminating the generation of an exception when we try the unload
+ // test. In that case, RESULT is unchanged.
+ int result = -1;
+ handle->setArgument(RESULT, result);
+
+ // Seed the calculation.
+ HooksManager::callCallouts(isc::hooks::ServerHooks::CONTEXT_CREATE,
+ *handle);
+ handle->getArgument(RESULT, result);
+ EXPECT_EQ(r0, result) << "context_create" << COMMON_TEXT;
+
+ // Perform the first calculation.
+ handle->setArgument("data_1", d1);
+ HooksManager::callCallouts(hookpt_one_index_, *handle);
+ handle->getArgument(RESULT, result);
+ EXPECT_EQ(r1, result) << "hookpt_one" << COMMON_TEXT;
+
+ // ... the second ...
+ handle->setArgument("data_2", d2);
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+ handle->getArgument(RESULT, result);
+ EXPECT_EQ(r2, result) << "hookpt_two" << COMMON_TEXT;
+
+ // ... and the third.
+ handle->setArgument("data_3", d3);
+ HooksManager::callCallouts(hookpt_three_index_, *handle);
+ handle->getArgument(RESULT, result);
+ EXPECT_EQ(r3, result) << "hookpt_three" << COMMON_TEXT;
+ }
+
+ /// @brief Call command handlers test.
+ ///
+ /// This test is similar to @c executeCallCallouts but it uses
+ /// @ref HooksManager::callCommandHandlers to execute the command
+ /// handlers for the following commands: 'command-one' and 'command-two'.
+ ///
+ /// @param r1..r2, d1..d2 Data (dN) and expected results (rN).
+ void executeCallCommandHandlers(int d1, int r1, int d2, int r2) {
+ static const char* COMMON_TEXT = " command handler returned the wrong value";
+ static const char* RESULT = "result";
+
+ int result;
+
+ // Set up a callout handle for the calls.
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // Initialize the argument RESULT. This simplifies testing by
+ // eliminating the generation of an exception when we try the unload
+ // test. In that case, RESULT is unchanged.
+ handle->setArgument(RESULT, -1);
+
+ // Perform the first calculation: it should assign the data to the
+ // result.
+ handle->setArgument("data_1", d1);
+ HooksManager::callCommandHandlers("command-one", *handle);
+ handle->getArgument(RESULT, result);
+ EXPECT_EQ(r1, result) << "command-one" << COMMON_TEXT;
+
+ // Perform the second calculation: it should multiply the data by 10
+ // and return in the result.
+ handle->setArgument("data_2", d2);
+ HooksManager::callCommandHandlers("command-two", *handle);
+ handle->getArgument(RESULT, result);
+ EXPECT_EQ(r2, result) << "command-two" << COMMON_TEXT;
+ }
+
+private:
+ /// To avoid unused variable errors
+ std::string dummy(int i) {
+ if (i == 0) {
+ return (LOAD_CALLOUT_LIBRARY);
+ } else {
+ return (LOAD_ERROR_CALLOUT_LIBRARY);
+ }
+ }
+};
+
+// This is effectively the same test as for LibraryManager, but using the
+// HooksManager object.
+
+TEST_F(HooksManagerTest, LoadLibraries) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. The first library implements the calculation.
+ //
+ // r3 = (7 * d1 - d2) * d3
+ //
+ // The last-loaded library implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ //
+ // Putting the processing for each library together in the appropriate
+ // order, we get:
+ //
+ // r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
+ {
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+
+ // r2 = 5 * 7 * 10
+ {
+ SCOPED_TRACE("Calculation using command handlers");
+ executeCallCommandHandlers(5, 5, 7, 350);
+ }
+
+ // Try unloading the libraries.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+
+ // Re-execute the calculation - callouts can be called but as nothing
+ // happens, the result should always be -1.
+ {
+ SCOPED_TRACE("Calculation with libraries not loaded");
+ executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
+ }
+}
+
+// This is effectively the same test as above, but with a library generating
+// an error when loaded. It is expected that the failing library will not be
+// loaded, but others will be.
+
+TEST_F(HooksManagerTest, LoadLibrariesWithError) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(INCORRECT_VERSION_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries. We expect a failure return because one of the
+ // libraries fails to load.
+ EXPECT_FALSE(HooksManager::loadLibraries(library_names));
+}
+
+// Test that we can unload a set of libraries while we have a CalloutHandle
+// created on them in existence, and can delete the handle afterwards.
+
+TEST_F(HooksManagerTest, CalloutHandleUnloadLibrary) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. This library implements:
+ //
+ // r3 = (7 * d1 - d2) * d3
+ {
+ SCOPED_TRACE("Calculation with full callout library loaded");
+ executeCallCallouts(7, 4, 28, 8, 20, 2, 40);
+ }
+
+ // Get an outstanding callout handle on this library.
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // Execute once of the callouts again to ensure that the handle contains
+ // memory allocated by the library.
+ HooksManager::callCallouts(ServerHooks::CONTEXT_CREATE, *handle);
+
+ // Unload the libraries.
+ HooksManager::prepareUnloadLibraries();
+ EXPECT_FALSE(HooksManager::unloadLibraries());
+
+ // Deleting the callout handle should not cause a segmentation fault.
+ handle.reset();
+
+ // And allows unload.
+ EXPECT_TRUE(HooksManager::unloadLibraries());
+}
+
+// Test that we can load a new set of libraries while we have a CalloutHandle
+// created on them in existence, and can delete the handle afterwards.
+
+TEST_F(HooksManagerTest, CalloutHandleLoadLibrary) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. This library implements:
+ //
+ // r3 = (7 * d1 - d2) * d3
+ {
+ SCOPED_TRACE("Calculation with full callout library loaded");
+ executeCallCallouts(7, 4, 28, 8, 20, 2, 40);
+ }
+
+ // Get an outstanding callout handle on this library and execute one of
+ // the callouts again to ensure that the handle contains memory allocated
+ // by the library.
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ HooksManager::callCallouts(ServerHooks::CONTEXT_CREATE, *handle);
+
+ // Load a new library that implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ HookLibsCollection new_library_names;
+ new_library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries.
+ EXPECT_THROW(HooksManager::loadLibraries(new_library_names),
+ LibrariesStillOpened);
+
+ // Deleting the old callout handle should not cause a segmentation fault.
+ handle.reset();
+
+ // But it allows the load of the new library.
+ EXPECT_TRUE(HooksManager::loadLibraries(new_library_names));
+
+ // Execute the calculation.
+ {
+ SCOPED_TRACE("Calculation with basic callout library loaded");
+ executeCallCallouts(10, 7, 17, 3, 51, 16, 35);
+ }
+}
+
+// This is effectively the same test as the LoadLibraries test.
+
+TEST_F(HooksManagerTest, ReloadSameLibraries) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. See the LoadLibraries test for an explanation of
+ // the calculation.
+ {
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+
+ // Try reloading the libraries and re-execute the calculation - we should
+ // get the same results.
+ EXPECT_NO_THROW(HooksManager::loadLibraries(library_names));
+ {
+ SCOPED_TRACE("Calculation with libraries reloaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+}
+
+TEST_F(HooksManagerTest, ReloadLibrariesReverseOrder) {
+
+ // Set up the list of libraries to be loaded and load them.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. The first library implements the calculation.
+ //
+ // r3 = (7 * d1 - d2) * d3
+ //
+ // The last-loaded library implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ //
+ // Putting the processing for each library together in the given order
+ // gives.
+ //
+ // r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
+ {
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+
+ // Reload the libraries in the reverse order.
+ std::reverse(library_names.begin(), library_names.end());
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // The calculation in the reverse order gives:
+ //
+ // r3 = ((((7 + d1) * d1) * d2 - d2) - d3) * d3
+ {
+ SCOPED_TRACE("Calculation with libraries loaded in reverse order");
+ executeCallCallouts(7, 3, 30, 3, 87, 7, 560);
+ }
+}
+
+// Local callouts for the test of server-registered callouts.
+
+namespace {
+
+ int
+testPreCallout(CalloutHandle& handle) {
+ handle.setArgument("result", static_cast<int>(1027));
+ return (0);
+}
+
+int
+testPostCallout(CalloutHandle& handle) {
+ int result;
+ handle.getArgument("result", result);
+ result *= 2;
+ handle.setArgument("result", result);
+ return (0);
+}
+
+}
+
+// The next test registers the pre and post- callouts above for hook hookpt_two,
+// and checks they are called.
+
+TEST_F(HooksManagerTest, PrePostCalloutTest) {
+
+ // Load a single library.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Load the pre- and post- callouts.
+ HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPreCallout);
+ HooksManager::postCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPostCallout);
+
+ // Execute the callouts. hookpt_two implements the calculation:
+ //
+ // "result - data_2"
+ //
+ // With the pre- and post- callouts above, the result expected is
+ //
+ // (1027 - data_2) * 2
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ int result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(2024, result);
+
+ // Reset the handle to allow a reload.
+ handle.reset();
+
+ // ... and check that the pre- and post- callout functions don't survive a
+ // reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+ handle = HooksManager::createCalloutHandle();
+
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(-15, result);
+}
+
+// Test with test mode enabled and the pre- and post- callout functions survive
+// a reload
+
+TEST_F(HooksManagerTest, TestModeEnabledPrePostSurviveLoad) {
+
+ // Load a single library.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the pre- and post- callouts.
+ HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPreCallout);
+ HooksManager::postCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPostCallout);
+
+ HooksManager::setTestMode(true);
+
+ // With the pre- and post- callouts above, the result expected is
+ //
+ // 1027 * 2
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ int result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(2054, result);
+
+ // Reset the handle to allow a reload.
+ handle.reset();
+
+ // ... and check that the pre- and post- callout functions survive a
+ // reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+ handle = HooksManager::createCalloutHandle();
+
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ // Expect same value i.e. 1027 * 2
+ result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(2054, result);
+}
+
+// Test with test mode disabled and the pre- and post- callout functions do not
+// survive a reload
+
+TEST_F(HooksManagerTest, TestModeDisabledPrePostDoNotSurviveLoad) {
+
+ // Load a single library.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the pre- and post- callouts.
+ HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPreCallout);
+ HooksManager::postCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPostCallout);
+
+ HooksManager::setTestMode(false);
+
+ // With the pre- and post- callouts above, the result expected is
+ //
+ // 1027 * 2
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ int result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(2054, result);
+
+ // Reset the handle to allow a reload.
+ handle.reset();
+
+ // ... and check that the pre- and post- callout functions don't survive a
+ // reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+ handle = HooksManager::createCalloutHandle();
+
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(-15, result);
+}
+
+// Test with test mode enabled and the pre- and post- callout functions do not
+// survive a reload if the test mode is set too late.
+
+TEST_F(HooksManagerTest, TestModeEnabledTooLatePrePostDoNotSurvive) {
+
+ // Load a single library.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the pre- and post- callouts.
+ HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPreCallout);
+ HooksManager::postCalloutsLibraryHandle().registerCallout("hookpt_two",
+ testPostCallout);
+
+ // With the pre- and post- callouts above, the result expected is
+ //
+ // 1027 * 2
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ int result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(2054, result);
+
+ // Reset the handle to allow a reload.
+ handle.reset();
+
+ // ... and check that the pre- and post- callout functions don't survive a
+ // reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+ handle = HooksManager::createCalloutHandle();
+
+ HooksManager::setTestMode(true);
+
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(hookpt_two_index_, *handle);
+
+ result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(-15, result);
+}
+
+// Check that everything works even with no libraries loaded. First that
+// calloutsPresent() always returns false.
+
+TEST_F(HooksManagerTest, NoLibrariesCalloutsPresent) {
+ // No callouts should be present on any hooks.
+ EXPECT_FALSE(HooksManager::calloutsPresent(hookpt_one_index_));
+ EXPECT_FALSE(HooksManager::calloutsPresent(hookpt_two_index_));
+ EXPECT_FALSE(HooksManager::calloutsPresent(hookpt_three_index_));
+ EXPECT_FALSE(HooksManager::commandHandlersPresent("command-one"));
+ EXPECT_FALSE(HooksManager::commandHandlersPresent("command-two"));
+}
+
+TEST_F(HooksManagerTest, NoLibrariesCallCallouts) {
+ executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
+}
+
+// Test the encapsulation of the ServerHooks::registerHook() method.
+
+TEST_F(HooksManagerTest, RegisterHooks) {
+ ServerHooks::getServerHooks().reset();
+ EXPECT_EQ(2, ServerHooks::getServerHooks().getCount());
+
+ // Check that the hook indexes are as expected. (Use temporary variables
+ // as it appears that Google test can't access the constants.)
+ int sh_cc = ServerHooks::CONTEXT_CREATE;
+ int hm_cc = HooksManager::CONTEXT_CREATE;
+ EXPECT_EQ(sh_cc, hm_cc);
+
+ int sh_cd = ServerHooks::CONTEXT_DESTROY;
+ int hm_cd = HooksManager::CONTEXT_DESTROY;
+ EXPECT_EQ(sh_cd, hm_cd);
+
+ // Register a few hooks and check we have the indexes as expected.
+ EXPECT_EQ(2, HooksManager::registerHook(string("alpha")));
+ EXPECT_EQ(3, HooksManager::registerHook(string("beta")));
+ EXPECT_EQ(4, HooksManager::registerHook(string("gamma")));
+
+
+ // The code used to throw, but it now allows to register the same
+ // hook several times. It simply returns existing index.
+ //EXPECT_THROW(static_cast<void>(HooksManager::registerHook(string("alpha"))),
+ // DuplicateHook);
+ EXPECT_EQ(2, HooksManager::registerHook(string("alpha")));
+
+ // ... an check the hooks are as we expect.
+ EXPECT_EQ(5, ServerHooks::getServerHooks().getCount());
+ vector<string> names = ServerHooks::getServerHooks().getHookNames();
+ sort(names.begin(), names.end());
+
+ EXPECT_EQ(string("alpha"), names[0]);
+ EXPECT_EQ(string("beta"), names[1]);
+ EXPECT_EQ(string("context_create"), names[2]);
+ EXPECT_EQ(string("context_destroy"), names[3]);
+ EXPECT_EQ(string("gamma"), names[4]);
+}
+
+// Check that we can get the names of the libraries.
+
+TEST_F(HooksManagerTest, LibraryNames) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Check the names before the libraries are loaded.
+ std::vector<std::string> loaded_names = HooksManager::getLibraryNames();
+ EXPECT_TRUE(loaded_names.empty());
+
+ // Load the libraries and check the names again.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+ loaded_names = HooksManager::getLibraryNames();
+ EXPECT_TRUE(extractNames(library_names) == loaded_names);
+
+ // Unload the libraries and check again.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+ loaded_names = HooksManager::getLibraryNames();
+ EXPECT_TRUE(loaded_names.empty());
+}
+
+// Test the library validation function.
+
+TEST_F(HooksManagerTest, validateLibraries) {
+ // Vector of libraries that failed validation
+ std::vector<std::string> failed;
+
+ // Test different vectors of libraries.
+
+ // No libraries should return a success.
+ std::vector<std::string> libraries;
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed.empty());
+
+ // Single valid library should validate.
+ libraries.clear();
+ libraries.push_back(BASIC_CALLOUT_LIBRARY);
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed.empty());
+
+ // Multiple valid libraries should succeed.
+ libraries.clear();
+ libraries.push_back(BASIC_CALLOUT_LIBRARY);
+ libraries.push_back(FULL_CALLOUT_LIBRARY);
+ libraries.push_back(UNLOAD_CALLOUT_LIBRARY);
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed.empty());
+
+ // Single invalid library should fail.
+ libraries.clear();
+ libraries.push_back(NOT_PRESENT_LIBRARY);
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed == libraries);
+
+ // Multiple invalid libraries should fail.
+ libraries.clear();
+ libraries.push_back(INCORRECT_VERSION_LIBRARY);
+ libraries.push_back(NO_VERSION_LIBRARY);
+ libraries.push_back(FRAMEWORK_EXCEPTION_LIBRARY);
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed == libraries);
+
+ // Combination of valid and invalid (first one valid) should fail.
+ libraries.clear();
+ libraries.push_back(FULL_CALLOUT_LIBRARY);
+ libraries.push_back(INCORRECT_VERSION_LIBRARY);
+ libraries.push_back(NO_VERSION_LIBRARY);
+
+ std::vector<std::string> expected_failures;
+ expected_failures.push_back(INCORRECT_VERSION_LIBRARY);
+ expected_failures.push_back(NO_VERSION_LIBRARY);
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed == expected_failures);
+
+ // Combination of valid and invalid (first one invalid) should fail.
+ libraries.clear();
+ libraries.push_back(NO_VERSION_LIBRARY);
+ libraries.push_back(FULL_CALLOUT_LIBRARY);
+ libraries.push_back(INCORRECT_VERSION_LIBRARY);
+
+ expected_failures.clear();
+ expected_failures.push_back(NO_VERSION_LIBRARY);
+ expected_failures.push_back(INCORRECT_VERSION_LIBRARY);
+
+ failed = HooksManager::validateLibraries(libraries);
+ EXPECT_TRUE(failed == expected_failures);
+}
+
+// This test verifies that unload is called by the prepare method.
+TEST_F(HooksManagerTest, prepareUnload) {
+
+ // Set up the list of libraries to be loaded and load them.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(UNLOAD_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Check that the marker file is not present.
+ EXPECT_FALSE(markerFilePresent());
+
+ // Prepare unload libraries runs unload functions.
+ HooksManager::prepareUnloadLibraries();
+
+ // Now the marker file is present.
+ EXPECT_TRUE(markerFilePresent());
+}
+
+// This test verifies that the specified parameters are accessed properly.
+TEST_F(HooksManagerTest, LibraryParameters) {
+
+ // Prepare parameters for the callout parameters library.
+ ElementPtr params = Element::createMap();
+ params->set("svalue", Element::create("string value"));
+ params->set("ivalue", Element::create(42));
+ params->set("bvalue", Element::create(true));
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(CALLOUT_PARAMS_LIBRARY),
+ params));
+
+ // Load the libraries. Note that callout params library checks if
+ // all mandatory parameters are there, so if anything is missing, its
+ // load() function will return error, thus causing the library to not
+ // load.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Try unloading the libraries.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+}
+
+// This test verifies that an object can be parked in two different
+// callouts and that it is unparked when the last callout calls the
+// unpark function.
+TEST_F(HooksManagerTest, Parking) {
+ // Load the same library twice. Both installed callouts will trigger
+ // asynchronous operation.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // We could be parked any object. Typically it will be a pointer to the
+ // packet. In this case, however, it is simpler to just use a string.
+ std::string parked_object = "foo";
+ handle->setArgument("parked_object", parked_object);
+
+ // This boolean value will be set to true when the packet gets unparked.
+ bool unparked = false;
+
+ // The callouts instruct us to park the object. We associated the callback
+ // function with the parked object, which sets "unparked" flag to true. We
+ // can later test the value of this flag to verify when exactly the packet
+ // got unparked.
+ ASSERT_NO_THROW(
+ HooksManager::park<std::string>("hookpt_one", "foo",
+ [&unparked] {
+ unparked = true;
+ })
+ );
+
+ // Call both installed callouts.
+ HooksManager::callCallouts(hookpt_one_index_, *handle);
+
+ // We have two callouts which should have returned pointers to the
+ // functions which we can call to simulate completion of asynchronous
+ // tasks.
+ std::function<void()> unpark_trigger_func1;
+ handle->getArgument("unpark_trigger1", unpark_trigger_func1);
+ // Call the first function. It should cause the hook library to call the
+ // "unpark" function. However, the object should not be unparked yet,
+ // because the other callout hasn't completed its scheduled asynchronous
+ // operation (keeps a reference on the parked object).
+ unpark_trigger_func1();
+ EXPECT_FALSE(unparked);
+
+ // Call the second function. This should decrease the reference count to
+ // 0 and the packet should be unparked.
+ std::function<void()> unpark_trigger_func2;
+ handle->getArgument("unpark_trigger2", unpark_trigger_func2);
+ unpark_trigger_func2();
+ EXPECT_TRUE(unparked);
+
+ // Resetting the handle makes return from test body to crash.
+
+ // Try unloading the libraries.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ // Handle is still active.
+ EXPECT_FALSE(status);
+}
+
+// This test verifies that the server can also unpark the packet.
+TEST_F(HooksManagerTest, ServerUnpark) {
+ // Load the same library twice. Both installed callouts will trigger
+ // asynchronous operation.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ // Load libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // We could be parked any object. Typically it will be a pointer to the
+ // packet. In this case, however, it is simpler to just use a string.
+ std::string parked_object = "foo";
+ handle->setArgument("parked_object", parked_object);
+
+ // This boolean value will be set to true when the packet gets unparked.
+ bool unparked = false;
+
+ // The callouts instruct us to park the object. We associated the callback
+ // function with the parked object, which sets "unparked" flag to true. We
+ // can later test the value of this flag to verify when exactly the packet
+ // got unparked.
+ HooksManager::park<std::string>("hookpt_one", "foo",
+ [&unparked] {
+ unparked = true;
+ });
+
+ // It should be possible for the server to increase reference counter.
+ ASSERT_NO_THROW(HooksManager::reference<std::string>("hookpt_one", "foo"));
+
+ // Call installed callout.
+ HooksManager::callCallouts(hookpt_one_index_, *handle);
+
+ // Server can force unparking the object.
+ EXPECT_TRUE(HooksManager::unpark<std::string>("hookpt_one", "foo"));
+
+ EXPECT_TRUE(unparked);
+
+ // Reset the handle to allow unload.
+ handle.reset();
+
+ // Try unloading the libraries.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+}
+
+// This test verifies that the server can drop parked packet.
+TEST_F(HooksManagerTest, ServerDropParked) {
+ // Load library.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // We could be parked any object. Typically it will be a pointer to the
+ // packet. In this case, however, it is simpler to just use a string.
+ std::string parked_object = "foo";
+ handle->setArgument("parked_object", parked_object);
+
+ // This boolean value will be set to true when the packet gets unparked.
+ bool unparked = false;
+
+ // The callouts instruct us to park the object. We associated the callback
+ // function with the parked object, which sets "unparked" flag to true. We
+ // can later test the value of this flag to verify when exactly the packet
+ // got unparked.
+ HooksManager::park<std::string>("hookpt_one", "foo",
+ [&unparked] {
+ unparked = true;
+ });
+
+ // It should be possible for the server to increase reference counter.
+ ASSERT_NO_THROW(HooksManager::reference<std::string>("hookpt_one", "foo"));
+
+ // Call installed callout.
+ HooksManager::callCallouts(hookpt_one_index_, *handle);
+
+ // Drop the parked packet. The callback should not be called.
+ EXPECT_TRUE(HooksManager::drop<std::string>("hookpt_one", "foo"));
+
+ EXPECT_FALSE(unparked);
+
+ // An attempt to unpark the packet should return false, as this packet
+ // is not parked anymore.
+ EXPECT_FALSE(HooksManager::unpark<std::string>("hookpt_one", "foo"));
+
+ // Reset the handle to allow unload.
+ handle.reset();
+
+ // Try unloading the libraries.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+}
+
+// This test verifies that parked objects are removed when libraries are
+// unloaded.
+TEST_F(HooksManagerTest, UnloadBeforeUnpark) {
+ // Load the same library twice. Both installed callouts will trigger
+ // asynchronous operation.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(ASYNC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ // Load libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // We could be parked any object. Typically it will be a pointer to the
+ // packet. In this case, however, it is simpler to just use a string.
+ std::string parked_object = "foo";
+ handle->setArgument("parked_object", parked_object);
+
+ // This boolean value will be set to true when the packet gets unparked.
+ bool unparked = false;
+
+ // The callouts instruct us to park the object. We associated the callback
+ // function with the parked object, which sets "unparked" flag to true. We
+ // can later test the value of this flag to verify when exactly the packet
+ // got unparked.
+ HooksManager::park<std::string>("hookpt_one", "foo",
+ [&unparked] {
+ unparked = true;
+ });
+
+ // Call installed callout.
+ HooksManager::callCallouts(hookpt_one_index_, *handle);
+
+ // Reset the handle to allow a reload.
+ handle.reset();
+
+ // Try reloading the libraries.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Parked object should have been removed.
+ EXPECT_FALSE(HooksManager::unpark<std::string>("hookpt_one", "foo"));
+
+ // Callback should not be called.
+ EXPECT_FALSE(unparked);
+}
+
+
+} // Anonymous namespace
diff --git a/src/lib/hooks/tests/incorrect_version_library.cc b/src/lib/hooks/tests/incorrect_version_library.cc
new file mode 100644
index 0000000..f4d7850
--- /dev/null
+++ b/src/lib/hooks/tests/incorrect_version_library.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2013-2015 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/.
+
+/// @file
+/// @brief Incorrect version function test
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - It contains the version() framework function only, which returns an
+/// incorrect version number.
+
+#include <config.h>
+#include <hooks/hooks.h>
+
+extern "C" {
+
+int version() {
+ return (KEA_HOOKS_VERSION + 1);
+}
+
+};
diff --git a/src/lib/hooks/tests/library_manager_collection_unittest.cc b/src/lib/hooks/tests/library_manager_collection_unittest.cc
new file mode 100644
index 0000000..9b30cb3
--- /dev/null
+++ b/src/lib/hooks/tests/library_manager_collection_unittest.cc
@@ -0,0 +1,314 @@
+// Copyright (C) 2013-2020 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/.
+
+#include <config.h>
+
+#include <hooks/callout_handle.h>
+#include <hooks/callout_manager.h>
+#include <hooks/library_manager.h>
+#include <hooks/library_manager_collection.h>
+#include <hooks/libinfo.h>
+
+#include <hooks/tests/common_test_class.h>
+#include <hooks/tests/test_libraries.h>
+
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <string>
+
+
+using namespace isc;
+using namespace isc::hooks;
+using namespace std;
+
+namespace {
+
+/// @brief Library manager collection test class
+
+class LibraryManagerCollectionTest : public ::testing::Test,
+ public HooksCommonTestClass {
+private:
+
+ /// To avoid unused variable errors
+ std::string dummy(int i) {
+ if (i == 0) {
+ return (MARKER_FILE);
+ } else if (i > 0) {
+ return (LOAD_CALLOUT_LIBRARY);
+ } else {
+ return (LOAD_ERROR_CALLOUT_LIBRARY);
+ }
+ }
+};
+
+} // namespace
+
+namespace isc {
+namespace hooks {
+/// @brief Public library manager collection class
+///
+/// This is an instance of the LibraryManagerCollection class but with the
+/// protected methods made public for test purposes.
+
+class PublicLibraryManagerCollection : public LibraryManagerCollection {
+public:
+ /// @brief Constructor
+ ///
+ /// @param List of libraries that this collection will manage. The order
+ /// of the libraries is important.
+ PublicLibraryManagerCollection(const HookLibsCollection& libraries)
+ : LibraryManagerCollection(libraries) {
+ }
+
+ /// Public methods that call protected methods on the superclass.
+ using LibraryManagerCollection::unloadLibraries;
+};
+
+} // namespace hooks
+} // namespace isc
+
+namespace {
+// This is effectively the same test as for LibraryManager, but using the
+// LibraryManagerCollection object.
+
+TEST_F(LibraryManagerCollectionTest, LoadLibraries) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Set up the library manager collection and get the callout manager we'll
+ // be using.
+ PublicLibraryManagerCollection lm_collection(library_names);
+
+ // Load the libraries.
+ EXPECT_TRUE(lm_collection.loadLibraries());
+ EXPECT_EQ(2, lm_collection.getLoadedLibraryCount());
+
+ // Execute the callouts. The first library implements the calculation.
+ //
+ // r3 = (7 * d1 - d2) * d3
+ //
+ // The last-loaded library implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ //
+ // Putting the processing for each library together in the appropriate
+ // order, we get:
+ //
+ // r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
+ boost::shared_ptr<CalloutManager> manager =
+ lm_collection.getCalloutManager();
+ {
+ SCOPED_TRACE("Doing calculation with libraries loaded");
+ executeCallCallouts(manager, 10, 3, 33, 2, 62, 3, 183);
+ }
+
+ // Try unloading the libraries.
+ EXPECT_NO_THROW(lm_collection.unloadLibraries());
+ EXPECT_EQ(0, lm_collection.getLoadedLibraryCount());
+
+ // Re-execute the calculation - callouts can be called but as nothing
+ // happens, the result should always be -1.
+ {
+ SCOPED_TRACE("Doing calculation with libraries not loaded");
+ executeCallCallouts(manager, -1, 3, -1, 22, -1, 83, -1);
+ }
+}
+
+// This is effectively the same test as above, but with a library generating
+// an error when loaded. It is expected that no libraries will be loaded.
+
+TEST_F(LibraryManagerCollectionTest, LoadLibrariesWithError) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+ library_names.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(INCORRECT_VERSION_LIBRARY),
+ data::ConstElementPtr()));
+ library_names.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Set up the library manager collection and get the callout manager we'll
+ // be using.
+ PublicLibraryManagerCollection lm_collection(library_names);
+
+ // Load the libraries. We expect a failure status to be returned as
+ // one of the libraries failed to load.
+ EXPECT_FALSE(lm_collection.loadLibraries());
+
+ // Expect no libraries were loaded.
+ EXPECT_EQ(0, lm_collection.getLoadedLibraryCount());
+}
+
+// Check that everything works even with no libraries loaded.
+
+TEST_F(LibraryManagerCollectionTest, NoLibrariesLoaded) {
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection library_names;
+
+ // Set up the library manager collection and get the callout manager we'll
+ // be using.
+ LibraryManagerCollection lm_collection(library_names);
+ EXPECT_TRUE(lm_collection.loadLibraries());
+ EXPECT_EQ(0, lm_collection.getLoadedLibraryCount());
+ boost::shared_ptr<CalloutManager> manager =
+ lm_collection.getCalloutManager();
+
+ // Execute the calculation - callouts can be called but as nothing
+ // happens, the result should always be -1.
+ executeCallCallouts(manager, -1, 3, -1, 22, -1, 83, -1);
+}
+
+// Check that we can get the names of the libraries.
+
+TEST_F(LibraryManagerCollectionTest, LibraryNames) {
+
+ // Set up the list of libraries to be loaded.
+ HookLibsCollection libraries;
+ libraries.push_back(make_pair(std::string(FULL_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+ libraries.push_back(make_pair(std::string(BASIC_CALLOUT_LIBRARY),
+ data::ConstElementPtr()));
+
+ // Set up the library manager collection and get the callout manager we'll
+ // be using.
+ PublicLibraryManagerCollection lm_collection(libraries);
+
+ // Check the names before the libraries are loaded.
+ std::vector<std::string> collection_names = lm_collection.getLibraryNames();
+ EXPECT_TRUE(extractNames(libraries) == collection_names);
+
+ // Load the libraries and check the names again.
+ EXPECT_TRUE(lm_collection.loadLibraries());
+ EXPECT_EQ(2, lm_collection.getLoadedLibraryCount());
+ collection_names = lm_collection.getLibraryNames();
+ EXPECT_TRUE(extractNames(libraries) == collection_names);
+}
+
+// Test the library validation function.
+
+TEST_F(LibraryManagerCollectionTest, validateLibraries) {
+ // Vector of libraries that failed validation
+ std::vector<std::string> failed;
+
+ // Test different vectors of libraries.
+
+ // No libraries should return a success.
+ std::vector<std::string> libraries;
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed.empty());
+
+ // Single valid library should validate.
+ libraries.clear();
+ libraries.push_back(BASIC_CALLOUT_LIBRARY);
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed.empty());
+
+ // Multiple valid libraries should succeed.
+ libraries.clear();
+ libraries.push_back(BASIC_CALLOUT_LIBRARY);
+ libraries.push_back(FULL_CALLOUT_LIBRARY);
+ libraries.push_back(UNLOAD_CALLOUT_LIBRARY);
+ libraries.push_back(CALLOUT_PARAMS_LIBRARY);
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed.empty());
+
+ // Single invalid library should fail.
+ libraries.clear();
+ libraries.push_back(NOT_PRESENT_LIBRARY);
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed == libraries);
+
+ // Multiple invalid libraries should fail.
+ libraries.clear();
+ libraries.push_back(INCORRECT_VERSION_LIBRARY);
+ libraries.push_back(NO_VERSION_LIBRARY);
+ libraries.push_back(FRAMEWORK_EXCEPTION_LIBRARY);
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed == libraries);
+
+ // Combination of valid and invalid (first one valid) should fail.
+ libraries.clear();
+ libraries.push_back(FULL_CALLOUT_LIBRARY);
+ libraries.push_back(INCORRECT_VERSION_LIBRARY);
+ libraries.push_back(NO_VERSION_LIBRARY);
+
+ std::vector<std::string> expected_failures;
+ expected_failures.push_back(INCORRECT_VERSION_LIBRARY);
+ expected_failures.push_back(NO_VERSION_LIBRARY);
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed == expected_failures);
+
+ // Combination of valid and invalid (first one invalid) should fail.
+ libraries.clear();
+ libraries.push_back(NO_VERSION_LIBRARY);
+ libraries.push_back(FULL_CALLOUT_LIBRARY);
+ libraries.push_back(INCORRECT_VERSION_LIBRARY);
+
+ expected_failures.clear();
+ expected_failures.push_back(NO_VERSION_LIBRARY);
+ expected_failures.push_back(INCORRECT_VERSION_LIBRARY);
+
+ failed = LibraryManagerCollection::validateLibraries(libraries);
+ EXPECT_TRUE(failed == expected_failures);
+}
+
+// This test verifies if getLibraryNames and getLibraryInfo are returning
+// expected values if there are no libraries configured.
+TEST_F(LibraryManagerCollectionTest, libraryGetEmpty) {
+
+ HookLibsCollection empty;
+ boost::shared_ptr<LibraryManagerCollection> mgr;
+
+ // Instantiate library manager collection with no libraries
+ EXPECT_NO_THROW(mgr.reset(new LibraryManagerCollection(empty)));
+
+ // Check that getLibraryInfo returns empty list properly.
+ HookLibsCollection returned = mgr->getLibraryInfo();
+ EXPECT_TRUE(returned.empty());
+
+ // Check that getLibraryNames return empty list, too.
+ vector<string> names(3, "rubbish"); // just put something in it.
+ EXPECT_NO_THROW(names = mgr->getLibraryNames());
+ EXPECT_TRUE(names.empty());
+}
+
+// This test verifies if getLibraryNames and getLibraryInfo are returning
+// expected values when there are libraries configured.
+TEST_F(LibraryManagerCollectionTest, libraryGet) {
+ using namespace data;
+
+ HookLibsCollection libs;
+ ElementPtr param1(Element::fromJSON("{ \"param1\": \"foo\" }"));
+ ElementPtr param2(Element::fromJSON("{ \"param2\": \"bar\" }"));
+ libs.push_back(make_pair("libone", param1));
+ libs.push_back(make_pair("libtwo", param2));
+
+ boost::shared_ptr<LibraryManagerCollection> mgr;
+ EXPECT_NO_THROW(mgr.reset(new LibraryManagerCollection(libs)));
+ EXPECT_TRUE(libs == mgr->getLibraryInfo());
+
+ vector<string> exp_names;
+ exp_names.push_back("libone");
+ exp_names.push_back("libtwo");
+
+ EXPECT_TRUE(exp_names == mgr->getLibraryNames());
+}
+
+} // Anonymous namespace
diff --git a/src/lib/hooks/tests/library_manager_unittest.cc b/src/lib/hooks/tests/library_manager_unittest.cc
new file mode 100644
index 0000000..52dea20
--- /dev/null
+++ b/src/lib/hooks/tests/library_manager_unittest.cc
@@ -0,0 +1,735 @@
+// Copyright (C) 2013-2023 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/.
+
+#include <config.h>
+
+#include <hooks/callout_handle.h>
+#include <hooks/callout_manager.h>
+#include <hooks/library_manager.h>
+#include <hooks/server_hooks.h>
+
+#include <hooks/tests/common_test_class.h>
+#include <hooks/tests/marker_file.h>
+#include <hooks/tests/test_libraries.h>
+
+#include <log/message_dictionary.h>
+#include <log/message_initializer.h>
+
+#include <util/multi_threading_mgr.h>
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <fstream>
+#include <string>
+
+#include <unistd.h>
+
+
+using namespace isc;
+using namespace isc::hooks;
+using namespace isc::log;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief Library manager test class
+
+class LibraryManagerTest : public ::testing::Test,
+ public HooksCommonTestClass {
+public:
+ /// @brief Constructor
+ ///
+ /// Initializes the CalloutManager object used in the tests. It sets it
+ /// up with the hooks initialized in the HooksCommonTestClass object and
+ /// with four libraries.
+ LibraryManagerTest() {
+ callout_manager_.reset(new CalloutManager(4));
+
+ // Ensure the marker file is not present at the start of a test.
+ static_cast<void>(remove(MARKER_FILE));
+
+ // Disable multi-threading.
+ MultiThreadingMgr::instance().setMode(false);
+ }
+
+ /// @brief Destructor
+ ///
+ /// Ensures a marker file is removed after each test.
+ ~LibraryManagerTest() {
+ static_cast<void>(remove(MARKER_FILE));
+
+ // Disable multi-threading.
+ MultiThreadingMgr::instance().setMode(false);
+ }
+
+ /// @brief Marker file present
+ ///
+ /// Convenience function to check whether a marker file is present. It
+ /// does this by opening the file.
+ ///
+ /// @return true if the marker file is present.
+ bool markerFilePresent() const {
+
+ // Try to open it.
+ std::fstream marker;
+ marker.open(MARKER_FILE, std::fstream::in);
+
+ // Check if it is open and close it if so.
+ bool exists = marker.is_open();
+ if (exists) {
+ marker.close();
+ }
+
+ return (exists);
+ }
+
+ /// @brief Call callouts test
+ ///
+ /// A wrapper around the method of the same name in the HooksCommonTestClass
+ /// object, this passes this class's CalloutManager to that method.
+ ///
+ /// @param r0...r3, d1..d3 Values and intermediate values expected. They
+ /// are ordered so that the variables appear in the argument list in
+ /// the order they are used. See HooksCommonTestClass::execute for
+ /// a full description. (rN is used to indicate an expected result,
+ /// dN is data to be passed to the calculation.)
+ void executeCallCallouts(int r0, int d1, int r1, int d2, int r2, int d3,
+ int r3) {
+ HooksCommonTestClass::executeCallCallouts(callout_manager_, r0, d1,
+ r1, d2, r2, d3, r3);
+ }
+
+ /// @brief Call command handlers test.
+ ///
+ /// A wrapper around the method of the same name in the HooksCommonTestClass
+ /// object, this passes this class's CalloutManager to that method.
+ ///
+ /// @param r1..r2, d1..d2 Values and intermediate values expected.
+ void executeCallCommandHandlers(int d1, int r1, int d2, int r2) {
+ HooksCommonTestClass::executeCallCommandHandlers(callout_manager_,
+ d1, r1, d2, r2);
+ }
+
+ /// Callout manager used for the test.
+ boost::shared_ptr<CalloutManager> callout_manager_;
+};
+
+/// @brief Library manager class
+///
+/// This is an instance of the LibraryManager class but with the protected
+/// methods made public for test purposes.
+
+class PublicLibraryManager : public isc::hooks::LibraryManager {
+public:
+ /// @brief Constructor
+ ///
+ /// Stores the library name. The actual loading is done in loadLibrary().
+ ///
+ /// @param name Name of the library to load. This should be an absolute
+ /// path name.
+ /// @param index Index of this library. For all these tests, it will be
+ /// zero, as we are only using one library.
+ /// @param manager CalloutManager object
+ PublicLibraryManager(const std::string& name, int index,
+ const boost::shared_ptr<CalloutManager>& manager)
+ : LibraryManager(name, index, manager)
+ {}
+
+ /// Public methods that call protected methods on the superclass.
+ using LibraryManager::unloadLibrary;
+ using LibraryManager::openLibrary;
+ using LibraryManager::closeLibrary;
+ using LibraryManager::checkVersion;
+ using LibraryManager::checkMultiThreadingCompatible;
+ using LibraryManager::registerStandardCallouts;
+ using LibraryManager::runLoad;
+ using LibraryManager::prepareUnloadLibrary;
+};
+
+
+// Check that LibraryManager constructor requires a not null manager
+
+TEST_F(LibraryManagerTest, NullManager) {
+ boost::shared_ptr<CalloutManager> null_manager;
+ EXPECT_THROW(PublicLibraryManager(std::string("foo"), 0, null_manager),
+ NoCalloutManager);
+}
+
+// Check that openLibrary() reports an error when it can't find the specified
+// library.
+
+TEST_F(LibraryManagerTest, NoLibrary) {
+ PublicLibraryManager lib_manager(std::string(NOT_PRESENT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_FALSE(lib_manager.openLibrary());
+}
+
+// Check that the openLibrary() and closeLibrary() methods work.
+
+TEST_F(LibraryManagerTest, OpenClose) {
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open and close the library
+ EXPECT_TRUE(lib_manager.openLibrary());
+ EXPECT_TRUE(lib_manager.closeLibrary());
+
+ // Check that a second close on an already closed library does not report
+ // an error.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Check that the code handles the case of a library with no version function.
+
+TEST_F(LibraryManagerTest, NoVersion) {
+ PublicLibraryManager lib_manager(std::string(NO_VERSION_LIBRARY),
+ 0, callout_manager_);
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Version check should fail.
+ EXPECT_FALSE(lib_manager.checkVersion());
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Check that the code handles the case of a library with a version function
+// that returns an incorrect version number.
+
+TEST_F(LibraryManagerTest, WrongVersion) {
+ PublicLibraryManager lib_manager(std::string(INCORRECT_VERSION_LIBRARY),
+ 0, callout_manager_);
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Version check should fail.
+ EXPECT_FALSE(lib_manager.checkVersion());
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Check that the code handles the case of a library where the version function
+// throws an exception.
+
+TEST_F(LibraryManagerTest, VersionException) {
+ PublicLibraryManager lib_manager(std::string(FRAMEWORK_EXCEPTION_LIBRARY),
+ 0, callout_manager_);
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Version check should fail.
+ EXPECT_FALSE(lib_manager.checkVersion());
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Tests that checkVersion() function succeeds in the case of a library with a
+// version function that returns the correct version number.
+
+TEST_F(LibraryManagerTest, CorrectVersionReturned) {
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Version check should succeed.
+ EXPECT_TRUE(lib_manager.checkVersion());
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with no
+// multi_threading_compatible function.
+
+TEST_F(LibraryManagerTest, NoMultiThreadingCompatible) {
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Not multi-threading compatible: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible(false));
+
+ // Not multi-threading compatible: does matter with MT.
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible(true));
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with a
+// multi_threading_compatible function returning 0 (not compatible).
+
+TEST_F(LibraryManagerTest, multiThreadingNotCompatible) {
+ PublicLibraryManager lib_manager(std::string(LOAD_ERROR_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Not multi-threading compatible: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible(false));
+
+ // Not multi-threading compatible: does matter with MT.
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible(true));
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with a
+// multi_threading_compatible function returning 1 (compatible)
+
+TEST_F(LibraryManagerTest, multiThreadingCompatible) {
+ PublicLibraryManager lib_manager(std::string(FULL_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Multi-threading compatible: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible(false));
+
+ // Multi-threading compatible: does matter with MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible(true));
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with a
+// multi_threading_compatible function returning 1 (compatible)
+
+TEST_F(LibraryManagerTest, multiThreadingCompatibleException) {
+ PublicLibraryManager lib_manager(std::string(FRAMEWORK_EXCEPTION_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Throw exception: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible(false));
+
+ // Throw exception: does matter with MT.
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible(true));
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks the registration of standard callouts.
+
+TEST_F(LibraryManagerTest, RegisterStandardCallouts) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check the version of the library.
+ EXPECT_TRUE(lib_manager.checkVersion());
+
+ // Load the standard callouts
+ EXPECT_NO_THROW(lib_manager.registerStandardCallouts());
+
+ // Now execute the callouts in the order expected. The library performs
+ // the calculation:
+ //
+ // r3 = (10 + d1) * d2 - d3
+ executeCallCallouts(10, 5, 15, 7, 105, 17, 88);
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Test that the "load" function is called correctly.
+
+TEST_F(LibraryManagerTest, CheckLoadCalled) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(LOAD_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check the version of the library.
+ EXPECT_TRUE(lib_manager.checkVersion());
+
+ // Load the standard callouts
+ EXPECT_NO_THROW(lib_manager.registerStandardCallouts());
+
+ // Check that only context_create and hookpt_one have callouts registered.
+ EXPECT_TRUE(callout_manager_->calloutsPresent(
+ ServerHooks::CONTEXT_CREATE));
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_three_index_));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-one"));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-two"));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(
+ ServerHooks::CONTEXT_DESTROY));
+
+ // Call the runLoad() method to run the load() function.
+ EXPECT_TRUE(lib_manager.runLoad());
+ EXPECT_TRUE(callout_manager_->calloutsPresent(
+ ServerHooks::CONTEXT_CREATE));
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_three_index_));
+ EXPECT_TRUE(callout_manager_->commandHandlersPresent("command-one"));
+ EXPECT_TRUE(callout_manager_->commandHandlersPresent("command-two"));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(
+ ServerHooks::CONTEXT_DESTROY));
+
+ // Now execute the callouts in the order expected. The library performs
+ // the calculation:
+ //
+ // r3 = (5 * d1 + d2) * d3
+ executeCallCallouts(5, 5, 25, 7, 32, 10, 320);
+
+ // Execute command handlers for 'command-one' and 'command-two'.
+ //
+ // r2 = d1 * d2 * 10;
+ executeCallCommandHandlers(5, 5, 7, 350);
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Check handling of a "load" function that throws an exception
+
+TEST_F(LibraryManagerTest, CheckLoadException) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(FRAMEWORK_EXCEPTION_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Running the load function should fail.
+ EXPECT_FALSE(lib_manager.runLoad());
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Check handling of a "load" function that returns an error.
+
+TEST_F(LibraryManagerTest, CheckLoadError) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(LOAD_ERROR_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check that we catch a load error
+ EXPECT_FALSE(lib_manager.runLoad());
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// No unload function
+
+TEST_F(LibraryManagerTest, CheckNoUnload) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check that no unload function returns true.
+ EXPECT_TRUE(lib_manager.prepareUnloadLibrary());
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Unload function returns an error
+
+TEST_F(LibraryManagerTest, CheckUnloadError) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(LOAD_ERROR_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check that unload function returning an error returns false.
+ EXPECT_FALSE(lib_manager.prepareUnloadLibrary());
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Unload function throws an exception.
+
+TEST_F(LibraryManagerTest, CheckUnloadException) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(FRAMEWORK_EXCEPTION_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check that we detect that the unload function throws an exception.
+ EXPECT_FALSE(lib_manager.prepareUnloadLibrary());
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Check that the case of the library's unload() function returning a
+// success is handled correctly.
+
+TEST_F(LibraryManagerTest, CheckUnload) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(UNLOAD_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+
+ // Check that the marker file is not present (at least that the file
+ // open fails).
+ EXPECT_FALSE(markerFilePresent());
+
+ // Check that unload function runs and returns a success
+ EXPECT_TRUE(lib_manager.prepareUnloadLibrary());
+
+ // Check that the marker file was created.
+ EXPECT_TRUE(markerFilePresent());
+
+ // Tidy up
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Test the operation of unloadLibrary(). We load a library with a set
+// of callouts then unload it. We need to check that the callouts have been
+// removed. We'll also check that the library's unload() function was called
+// as well.
+
+TEST_F(LibraryManagerTest, LibUnload) {
+
+ // Load the only library, specifying the index of 0 as it's the only
+ // library. This should load all callouts.
+ PublicLibraryManager lib_manager(std::string(LOAD_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Check the version of the library.
+ EXPECT_TRUE(lib_manager.checkVersion());
+
+ // No callouts should be registered at the moment.
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_three_index_));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-one"));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-two"));
+
+ // Load the single standard callout and check it is registered correctly.
+ EXPECT_NO_THROW(lib_manager.registerStandardCallouts());
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_three_index_));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-one"));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-two"));
+
+ // Call the load function to load the other callouts.
+ EXPECT_TRUE(lib_manager.runLoad());
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_TRUE(callout_manager_->calloutsPresent(hookpt_three_index_));
+ EXPECT_TRUE(callout_manager_->commandHandlersPresent("command-one"));
+ EXPECT_TRUE(callout_manager_->commandHandlersPresent("command-two"));
+
+ // Unload the library and check that the callouts have been removed from
+ // the CalloutManager.
+ lib_manager.unloadLibrary();
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_three_index_));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-one"));
+ EXPECT_FALSE(callout_manager_->commandHandlersPresent("command-two"));
+}
+
+// Now come the loadLibrary() tests that make use of all the methods tested
+// above. These tests are really to make sure that the methods have been
+// tied together correctly.
+
+// First test the basic error cases - no library, no version function, version
+// function returning an error.
+
+TEST_F(LibraryManagerTest, LoadLibraryNoLibrary) {
+ LibraryManager lib_manager(std::string(NOT_PRESENT_LIBRARY), 0,
+ callout_manager_);
+ EXPECT_FALSE(lib_manager.loadLibrary());
+}
+
+// Check that the code handles the case of a library with no version function.
+
+TEST_F(LibraryManagerTest, LoadLibraryNoVersion) {
+ LibraryManager lib_manager(std::string(NO_VERSION_LIBRARY), 0,
+ callout_manager_);
+ EXPECT_FALSE(lib_manager.loadLibrary());
+}
+
+// Check that the code handles the case of a library with a version function
+// that returns an incorrect version number.
+
+TEST_F(LibraryManagerTest, LoadLibraryWrongVersion) {
+ LibraryManager lib_manager(std::string(INCORRECT_VERSION_LIBRARY), 0,
+ callout_manager_);
+ EXPECT_FALSE(lib_manager.loadLibrary());
+}
+
+// Check that the full loadLibrary call works.
+
+TEST_F(LibraryManagerTest, LoadLibrary) {
+ PublicLibraryManager lib_manager(std::string(FULL_CALLOUT_LIBRARY), 0,
+ callout_manager_);
+ EXPECT_TRUE(lib_manager.loadLibrary());
+
+ // Now execute the callouts in the order expected. The library performs
+ // the calculation:
+ //
+ // r3 = (7 * d1 - d2) * d3
+ executeCallCallouts(7, 5, 35, 9, 26, 3, 78);
+
+ EXPECT_TRUE(lib_manager.unloadLibrary());
+
+ // Check that the callouts have been removed from the callout manager.
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_one_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_two_index_));
+ EXPECT_FALSE(callout_manager_->calloutsPresent(hookpt_three_index_));
+}
+
+// Now test for multiple libraries. We'll load the full callout library
+// first, then load some of the libraries with missing framework functions.
+// This will check that when searching for framework functions, only the
+// specified library is checked, not other loaded libraries. We will
+// load a second library with suitable callouts and check that the callouts
+// are added correctly. Finally, we'll unload one of the libraries and
+// check that only the callouts belonging to that library were removed.
+
+TEST_F(LibraryManagerTest, LoadMultipleLibraries) {
+ // Load a library with all framework functions.
+ PublicLibraryManager lib_manager_1(std::string(FULL_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager_1.loadLibrary());
+
+ // Attempt to load a library with no version() function. We should detect
+ // this and not end up calling the function from the already loaded
+ // library.
+ PublicLibraryManager lib_manager_2(std::string(NO_VERSION_LIBRARY),
+ 1, callout_manager_);
+ EXPECT_FALSE(lib_manager_2.loadLibrary());
+
+ // Attempt to load the library with an incorrect version. This should
+ // be detected.
+ PublicLibraryManager lib_manager_3(std::string(INCORRECT_VERSION_LIBRARY),
+ 1, callout_manager_);
+ EXPECT_FALSE(lib_manager_3.loadLibrary());
+
+ // Load the basic callout library. This only has standard callouts so,
+ // if the first library's load() function gets called, some callouts
+ // will be registered twice and lead to incorrect results.
+ PublicLibraryManager lib_manager_4(std::string(BASIC_CALLOUT_LIBRARY),
+ 1, callout_manager_);
+ EXPECT_TRUE(lib_manager_4.loadLibrary());
+
+ // Execute the callouts. The first library implements the calculation.
+ //
+ // r3 = (7 * d1 - d2) * d3
+ //
+ // The last-loaded library implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ //
+ // Putting the processing for each library together in the appropriate
+ // order, we get:
+ //
+ // r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+
+ // All done, so unload the first library.
+ EXPECT_TRUE(lib_manager_1.unloadLibrary());
+
+ // Now execute the callouts again and check that the results are as
+ // expected for the new calculation.
+ executeCallCallouts(10, 5, 15, 7, 105, 17, 88);
+
+ // ... and tidy up.
+ EXPECT_TRUE(lib_manager_4.unloadLibrary());
+}
+
+// Check that libraries can be validated.
+
+TEST_F(LibraryManagerTest, validateLibraries) {
+ EXPECT_TRUE(LibraryManager::validateLibrary(BASIC_CALLOUT_LIBRARY));
+ EXPECT_TRUE(LibraryManager::validateLibrary(FULL_CALLOUT_LIBRARY));
+ EXPECT_FALSE(LibraryManager::validateLibrary(FRAMEWORK_EXCEPTION_LIBRARY));
+ EXPECT_FALSE(LibraryManager::validateLibrary(INCORRECT_VERSION_LIBRARY));
+ EXPECT_TRUE(LibraryManager::validateLibrary(LOAD_CALLOUT_LIBRARY));
+ EXPECT_TRUE(LibraryManager::validateLibrary(LOAD_ERROR_CALLOUT_LIBRARY));
+ EXPECT_FALSE(LibraryManager::validateLibrary(NOT_PRESENT_LIBRARY));
+ EXPECT_FALSE(LibraryManager::validateLibrary(NO_VERSION_LIBRARY));
+ EXPECT_TRUE(LibraryManager::validateLibrary(UNLOAD_CALLOUT_LIBRARY));
+ EXPECT_TRUE(LibraryManager::validateLibrary(CALLOUT_PARAMS_LIBRARY));
+
+ EXPECT_FALSE(LibraryManager::validateLibrary(BASIC_CALLOUT_LIBRARY, true));
+ EXPECT_TRUE(LibraryManager::validateLibrary(FULL_CALLOUT_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(FRAMEWORK_EXCEPTION_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(INCORRECT_VERSION_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(LOAD_CALLOUT_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(LOAD_ERROR_CALLOUT_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(NOT_PRESENT_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(NO_VERSION_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(UNLOAD_CALLOUT_LIBRARY, true));
+ EXPECT_FALSE(LibraryManager::validateLibrary(CALLOUT_PARAMS_LIBRARY, true));
+}
+
+// Check that log messages are properly registered and unregistered.
+
+TEST_F(LibraryManagerTest, libraryLoggerSetup) {
+ // Load a library with all framework functions.
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+ EXPECT_TRUE(lib_manager.loadLibrary());
+
+ // After loading the library, the global logging dictionary should
+ // contain log messages registered for this library.
+ const MessageDictionaryPtr& dict = MessageDictionary::globalDictionary();
+ EXPECT_EQ("basic callout load %1", dict->getText("BCL_LOAD_START"));
+ EXPECT_EQ("basic callout load end", dict->getText("BCL_LOAD_END"));
+ // Some of the messages defined by the hook library are duplicates. But,
+ // the loadLibrary function should have logged the duplicates and clear
+ // the duplicates list. By checking that the list of duplicates is empty
+ // we test that the LibraryManager handles the duplicates (logs and
+ // clears them).
+ EXPECT_TRUE(MessageInitializer::getDuplicates().empty());
+
+ // After unloading the library, the messages should be unregistered.
+ EXPECT_TRUE(lib_manager.unloadLibrary());
+ // The musl libc does not implement dlclose
+#ifndef LIBC_MUSL
+ EXPECT_TRUE(dict->getText("BCL_LOAD_START").empty());
+ EXPECT_TRUE(dict->getText("BCL_LOAD_END").empty());
+#endif
+}
+
+} // Anonymous namespace
diff --git a/src/lib/hooks/tests/load_callout_library.cc b/src/lib/hooks/tests/load_callout_library.cc
new file mode 100644
index 0000000..613ec2c
--- /dev/null
+++ b/src/lib/hooks/tests/load_callout_library.cc
@@ -0,0 +1,152 @@
+// Copyright (C) 2013-2017 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/.
+
+/// @file
+/// @brief Basic library with load() function
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - The "version" and "load" framework functions are supplied. One "standard"
+/// callout is supplied ("hookpt_one") and two non-standard ones which are
+/// registered during the call to "load" on the hooks "hookpt_two" and
+/// "hookpt_three".
+///
+/// All callouts do trivial calculations, the result of all being called in
+/// sequence being
+///
+/// @f[ ((5 * data_1) + data_2) * data_3 @f]
+///
+/// ...where data_1, data_2 and data_3 are the values passed in arguments of
+/// the same name to the three callouts (data_1 passed to hookpt_one, data_2
+/// to hookpt_two etc.) and the result is returned in the argument "result".
+
+#include <config.h>
+#include <hooks/hooks.h>
+
+using namespace isc::hooks;
+
+extern "C" {
+
+// Callouts
+
+int
+context_create(CalloutHandle& handle) {
+ handle.setContext("result", static_cast<int>(5));
+ handle.setArgument("result", static_cast<int>(5));
+ return (0);
+}
+
+// First callout adds the passed "data_1" argument to the initialized context
+// value of 5. (Note that the value set by context_create is accessed through
+// context and not the argument, so checking that context is correctly passed
+// between callouts in the same library.)
+
+int
+hookpt_one(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_1", data);
+
+ int result;
+ handle.getContext("result", result);
+
+ result *= data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Second callout multiplies the current context value by the "data_2"
+// argument.
+
+static int
+hook_nonstandard_two(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_2", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result += data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Third callout adds "data_3" to the result.
+
+static int
+hook_nonstandard_three(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_3", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result *= data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// First command handler assigns data to a result.
+
+static int
+command_handler_one(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_1", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result = data;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Second command handler multiples the result by data by 10.
+
+static int
+command_handler_two(CalloutHandle& handle) {
+ int data;
+ handle.getArgument("data_2", data);
+
+ int result;
+ handle.getArgument("result", result);
+
+ result *= data * 10;
+ handle.setArgument("result", result);
+
+ return (0);
+}
+
+// Framework functions
+
+int
+version() {
+ return (KEA_HOOKS_VERSION);
+}
+
+int load(LibraryHandle& handle) {
+ // Initialize the user library if the main image was statically linked
+#ifdef USE_STATIC_LINK
+ hooksStaticLinkInit();
+#endif
+ // Register the non-standard functions
+ handle.registerCallout("hookpt_two", hook_nonstandard_two);
+ handle.registerCallout("hookpt_three", hook_nonstandard_three);
+
+ // Register command_handler_one as control command handler.
+ handle.registerCommandCallout("command-one", command_handler_one);
+ handle.registerCommandCallout("command-two", command_handler_two);
+
+ return (0);
+}
+
+};
+
diff --git a/src/lib/hooks/tests/load_error_callout_library.cc b/src/lib/hooks/tests/load_error_callout_library.cc
new file mode 100644
index 0000000..66b1359
--- /dev/null
+++ b/src/lib/hooks/tests/load_error_callout_library.cc
@@ -0,0 +1,47 @@
+// Copyright (C) 2013-2020 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/.
+
+/// @file
+/// @brief Error load library
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - All framework functions are supplied. "version" returns the correct
+/// value, but "load" and unload return an error.
+
+#include <config.h>
+#include <hooks/hooks.h>
+
+using namespace isc::hooks;
+
+extern "C" {
+
+// Framework functions
+
+int
+version() {
+ return (KEA_HOOKS_VERSION);
+}
+
+int
+load(LibraryHandle&) {
+ return (1);
+}
+
+int
+unload() {
+ return (1);
+}
+
+int
+multi_threading_compatible() {
+ return (0);
+}
+
+};
+
diff --git a/src/lib/hooks/tests/marker_file.h.in b/src/lib/hooks/tests/marker_file.h.in
new file mode 100644
index 0000000..368ad37
--- /dev/null
+++ b/src/lib/hooks/tests/marker_file.h.in
@@ -0,0 +1,19 @@
+// Copyright (C) 2013-2015 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 MARKER_FILE_H
+#define MARKER_FILE_H
+
+/// @file
+/// Define a marker file that is used in tests to prove that an "unload"
+/// function has been called.
+
+namespace {
+const char* MARKER_FILE = "@abs_builddir@/marker_file.dat";
+}
+
+#endif // MARKER_FILE_H
+
diff --git a/src/lib/hooks/tests/no_version_library.cc b/src/lib/hooks/tests/no_version_library.cc
new file mode 100644
index 0000000..a4c4bb5
--- /dev/null
+++ b/src/lib/hooks/tests/no_version_library.cc
@@ -0,0 +1,24 @@
+// Copyright (C) 2013-2020 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/.
+
+#include <config.h>
+
+/// @file
+/// @brief No version function library
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - No version() function is present.
+
+extern "C" {
+
+int no_version() {
+ return (0);
+}
+
+};
diff --git a/src/lib/hooks/tests/parking_lots_unittest.cc b/src/lib/hooks/tests/parking_lots_unittest.cc
new file mode 100644
index 0000000..96f8814
--- /dev/null
+++ b/src/lib/hooks/tests/parking_lots_unittest.cc
@@ -0,0 +1,339 @@
+// Copyright (C) 2018-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/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <hooks/parking_lots.h>
+#include <boost/weak_ptr.hpp>
+#include <testutils/gtest_utils.h>
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace isc;
+using namespace isc::hooks;
+
+namespace {
+
+// Defines a pointer to a string. The tests use shared pointers
+// as parked objects to ensure key matching works correctly with
+// them. We're doing this because real-world use parked objects
+// are typically pointers to packets.
+typedef boost::shared_ptr<std::string> StringPtr;
+
+// Test that it is possible to create and retrieve parking lots for
+// specified hook points.
+TEST(ParkingLotsTest, createGetParkingLot) {
+ ParkingLots parking_lots;
+
+ ParkingLotPtr parking_lot0 = parking_lots.getParkingLotPtr(1);
+ ParkingLotPtr parking_lot1 = parking_lots.getParkingLotPtr(2);
+ ParkingLotPtr parking_lot2 = parking_lots.getParkingLotPtr(1);
+
+ ASSERT_TRUE(parking_lot0);
+ ASSERT_TRUE(parking_lot1);
+ ASSERT_TRUE(parking_lot2);
+
+ EXPECT_EQ(0, parking_lot0->size());
+ EXPECT_EQ(0, parking_lot1->size());
+ EXPECT_EQ(0, parking_lot2->size());
+
+ EXPECT_FALSE(parking_lot0 == parking_lot1);
+ EXPECT_TRUE(parking_lot0 == parking_lot2);
+
+ ASSERT_NO_THROW(parking_lots.clear());
+
+ ParkingLotPtr parking_lot3 = parking_lots.getParkingLotPtr(1);
+ ASSERT_TRUE(parking_lot3);
+
+ EXPECT_FALSE(parking_lot3 == parking_lot0);
+}
+
+// Verify that an object can be parked.
+TEST(ParkingLotsTest, park) {
+ ParkingLot parking_lot;
+
+ // Create object to park.
+ StringPtr parked_object(new std::string("foo"));
+
+ // Verify that we can park an object that has not been parked.
+ ASSERT_NO_THROW(parking_lot.park(parked_object, [] {}));
+
+ EXPECT_EQ(1, parking_lot.size());
+
+ // Verify that we cannot park an object that has been parked
+ EXPECT_THROW(parking_lot.park(parked_object, [] {}),
+ InvalidOperation);
+}
+
+// Verify that an object can be referenced.
+TEST(ParkingLotsTest, reference) {
+ ParkingLotPtr parking_lot = boost::make_shared<ParkingLot>();
+ ParkingLotHandlePtr parking_lot_handle =
+ boost::make_shared<ParkingLotHandle>(parking_lot);
+
+ // Create an object.
+ StringPtr parked_object(new std::string("foo"));
+
+ // Cannot reference an object that has not been parked.
+ ASSERT_THROW(parking_lot_handle->reference(parked_object),
+ InvalidOperation);
+
+ // Park the object.
+ ASSERT_NO_THROW(parking_lot->park(parked_object, [] {}));
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Reference the object. Reference count should one.
+ int ref_count = 0;
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->reference(parked_object));
+ ASSERT_EQ(1, ref_count);
+
+ // Reference the object again. Reference count should two.
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->reference(parked_object));
+ ASSERT_EQ(2, ref_count);
+
+ EXPECT_EQ(1, parking_lot->size());
+}
+
+// Test that object can be parked and then unparked.
+TEST(ParkingLotsTest, unpark) {
+ ParkingLotPtr parking_lot = boost::make_shared<ParkingLot>();
+ ParkingLotHandlePtr parking_lot_handle =
+ boost::make_shared<ParkingLotHandle>(parking_lot);
+
+ StringPtr parked_object(new std::string("foo"));
+
+ // Unparking should return false if the object isn't parked.
+ EXPECT_FALSE(parking_lot->unpark(parked_object));
+
+ EXPECT_EQ(0, parking_lot->size());
+
+ // This flag will indicate if the callback has been called.
+ bool unparked = false;
+
+ ASSERT_NO_THROW(parking_lot->park(parked_object, [&unparked] {
+ unparked = true;
+ }));
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Reference the parked object twice because we're going to test that
+ // reference counting works fine.
+ ASSERT_NO_THROW(parking_lot_handle->reference(parked_object));
+ ASSERT_NO_THROW(parking_lot_handle->reference(parked_object));
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Try to unpark the object. It should decrease the reference count, but not
+ // unpark the packet yet.
+ EXPECT_TRUE(parking_lot_handle->unpark(parked_object));
+ EXPECT_FALSE(unparked);
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Try to unpark the object. This time it should be successful, because the
+ // reference count goes to 0.
+ EXPECT_TRUE(parking_lot_handle->unpark(parked_object));
+ EXPECT_TRUE(unparked);
+
+ EXPECT_EQ(0, parking_lot->size());
+
+ // Calling unpark again should return false to indicate that the object is
+ // not parked.
+ EXPECT_FALSE(parking_lot_handle->unpark(parked_object));
+
+ EXPECT_EQ(0, parking_lot->size());
+}
+
+// Test that parked object can be dropped.
+TEST(ParkingLotsTest, drop) {
+ ParkingLotPtr parking_lot = boost::make_shared<ParkingLot>();
+ ParkingLotHandlePtr parking_lot_handle =
+ boost::make_shared<ParkingLotHandle>(parking_lot);
+
+ StringPtr parked_object(new std::string("foo"));
+
+ // This flag will indicate if the callback has been called.
+ bool unparked = false;
+ ASSERT_NO_THROW(parking_lot->park(parked_object, [&unparked] {
+ unparked = true;
+ }));
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Reference object twice to test that dropping the packet ignores
+ // reference counting.
+ ASSERT_NO_THROW(parking_lot_handle->reference(parked_object));
+ ASSERT_NO_THROW(parking_lot_handle->reference(parked_object));
+
+ // Drop parked object. The callback should not be invoked.
+ EXPECT_TRUE(parking_lot_handle->drop(parked_object));
+ EXPECT_FALSE(unparked);
+
+ EXPECT_EQ(0, parking_lot->size());
+
+ // Expect that an attempt to unpark return false, as the object
+ // has been dropped.
+ EXPECT_FALSE(parking_lot_handle->unpark(parked_object));
+}
+
+// Test that parked lots can be cleared.
+TEST(ParkingLotsTest, clear) {
+ ParkingLotsPtr parking_lots = boost::make_shared<ParkingLots>();
+ ParkingLotPtr parking_lot = parking_lots->getParkingLotPtr(1234);
+ ASSERT_TRUE(parking_lot);
+ ParkingLotHandlePtr parking_lot_handle =
+ boost::make_shared<ParkingLotHandle>(parking_lot);
+
+ boost::shared_ptr<std::string> parked_object =
+ boost::make_shared<std::string>("foo");
+ boost::weak_ptr<std::string> weak_parked_object(parked_object);
+
+ // This flag will indicate if the callback has been called.
+ bool unparked = false;
+ ASSERT_NO_THROW(parking_lot->park(parked_object, [&unparked] {
+ unparked = true;
+ }));
+
+ // Reference object twice to test that clearing the parking lots
+ // ignores reference counting.
+ ASSERT_NO_THROW(parking_lot_handle->reference(parked_object));
+ ASSERT_NO_THROW(parking_lot_handle->reference(parked_object));
+
+ // Drop reference on objects.
+ parking_lot.reset();
+ parking_lot_handle.reset();
+ parked_object.reset();
+
+ // The parked object is still alive.
+ EXPECT_FALSE(weak_parked_object.expired());
+
+ // Clear the parking lots.
+ ASSERT_NO_THROW(parking_lots->clear());
+
+ // The callback should not be invoked.
+ EXPECT_FALSE(unparked);
+
+ // The parked object was destroyed.
+ EXPECT_TRUE(weak_parked_object.expired());
+}
+
+// Verify that an object can be dereferenced.
+TEST(ParkingLotsTest, dereference) {
+ ParkingLotPtr parking_lot = boost::make_shared<ParkingLot>();
+ ParkingLotHandlePtr parking_lot_handle =
+ boost::make_shared<ParkingLotHandle>(parking_lot);
+
+ // Create an object.
+ StringPtr parked_object(new std::string("foo"));
+
+ // Verify that an object that hasn't been parked, cannot be
+ // dereferenced.
+ ASSERT_THROW(parking_lot_handle->dereference(parked_object),
+ InvalidOperation);
+
+ // Park the object.
+ // This flag will indicate if the callback has been called.
+ bool unparked = false;
+ ASSERT_NO_THROW(parking_lot->park(parked_object, [&unparked] {
+ unparked = true;
+ }));
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Reference the parked object twice.
+ int ref_count = 0;
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->reference(parked_object));
+ ASSERT_EQ(1, ref_count);
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->reference(parked_object));
+ ASSERT_EQ(2, ref_count);
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Try to dereference the object. It should decrease the reference count,
+ // but not unpark the packet or invoke the callback.
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->dereference(parked_object));
+ ASSERT_EQ(1, ref_count);
+ EXPECT_FALSE(unparked);
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Try to dereference the object. It should decrease the reference count,
+ // but not unpark the packet or invoke the callback.
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->dereference(parked_object));
+ ASSERT_EQ(0, ref_count);
+ EXPECT_FALSE(unparked);
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Try to dereference the object. It should decrement to -1
+ // but not unpark the packet or invoke the callback.
+ ASSERT_NO_THROW(ref_count = parking_lot_handle->dereference(parked_object));
+ EXPECT_EQ(-1, ref_count);
+ EXPECT_FALSE(unparked);
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Calling unpark should invoke the callback.
+ ASSERT_TRUE(parking_lot_handle->unpark(parked_object));
+ EXPECT_TRUE(unparked);
+
+ EXPECT_EQ(0, parking_lot->size());
+}
+
+// Verify that parked objects are correctly distinguished from
+// one another.
+TEST(ParkingLotsTest, multipleObjects) {
+ ParkingLotPtr parking_lot = boost::make_shared<ParkingLot>();
+ ParkingLotHandlePtr parking_lot_handle =
+ boost::make_shared<ParkingLotHandle>(parking_lot);
+
+ // Create an object and park it.
+ StringPtr object_one(new std::string("one"));
+ int unparked_one = 0;
+ ASSERT_NO_THROW(parking_lot->park(object_one, [&unparked_one] {
+ ++unparked_one;
+ }));
+
+ // Create a second object and park it.
+ StringPtr object_two(new std::string("two"));
+ int unparked_two = 0;
+ ASSERT_NO_THROW(parking_lot->park(object_two, [&unparked_two] {
+ ++unparked_two;
+ }));
+
+ EXPECT_EQ(2, parking_lot->size());
+
+ // Create a third object but don't park it.
+ StringPtr object_three(new std::string("three"));
+
+ // Try to unpark object_three. It should fail, and no callbacks
+ // should get invoked.
+ EXPECT_FALSE(parking_lot_handle->unpark(object_three));
+ EXPECT_EQ(unparked_one, 0);
+ EXPECT_EQ(unparked_two, 0);
+
+ EXPECT_EQ(2, parking_lot->size());
+
+ // Unpark object one. It should succeed and its callback should
+ // get invoked.
+ EXPECT_TRUE(parking_lot_handle->unpark(object_one));
+ EXPECT_EQ(unparked_one, 1);
+ EXPECT_EQ(unparked_two, 0);
+
+ EXPECT_EQ(1, parking_lot->size());
+
+ // Unpark object two. It should succeed and its callback should
+ // get invoked.
+ EXPECT_TRUE(parking_lot_handle->unpark(object_two));
+ EXPECT_EQ(unparked_one, 1);
+ EXPECT_EQ(unparked_two, 1);
+
+ EXPECT_EQ(0, parking_lot->size());
+}
+
+}
diff --git a/src/lib/hooks/tests/run_unittests.cc b/src/lib/hooks/tests/run_unittests.cc
new file mode 100644
index 0000000..cd6fc2b
--- /dev/null
+++ b/src/lib/hooks/tests/run_unittests.cc
@@ -0,0 +1,19 @@
+// Copyright (C) 2009-2015 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/.
+
+#include <config.h>
+
+#include <log/logger_support.h>
+#include <util/unittests/run_all.h>
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+ return (isc::util::unittests::run_all());
+}
diff --git a/src/lib/hooks/tests/server_hooks_unittest.cc b/src/lib/hooks/tests/server_hooks_unittest.cc
new file mode 100644
index 0000000..f9b20cb
--- /dev/null
+++ b/src/lib/hooks/tests/server_hooks_unittest.cc
@@ -0,0 +1,232 @@
+// Copyright (C) 2013-2018 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/.
+
+#include <config.h>
+
+#include <hooks/server_hooks.h>
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+using namespace isc;
+using namespace isc::hooks;
+using namespace std;
+
+namespace {
+
+// Checks the registration of hooks and the interrogation methods. As the
+// constructor registers two hooks, this is also a test of the constructor.
+
+TEST(ServerHooksTest, RegisterHooks) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ // There should be two hooks already registered, with indexes 0 and 1.
+ EXPECT_EQ(2, hooks.getCount());
+ EXPECT_EQ(0, hooks.getIndex("context_create"));
+ EXPECT_EQ(0, hooks.findIndex("context_create"));
+ EXPECT_EQ(1, hooks.getIndex("context_destroy"));
+ EXPECT_EQ(1, hooks.findIndex("context_destroy"));
+
+ // Check that the constants are as expected. (The intermediate variables
+ // are used because of problems with g++ 4.6.1/Ubuntu 11.10 when resolving
+ // the value of the ServerHooks constants when they appeared within the
+ // gtest macro.)
+ const int create_value = ServerHooks::CONTEXT_CREATE;
+ const int destroy_value = ServerHooks::CONTEXT_DESTROY;
+ EXPECT_EQ(0, create_value);
+ EXPECT_EQ(1, destroy_value);
+
+ // Register another couple of hooks. The test on returned index is based
+ // on knowledge that the hook indexes are assigned in ascending order.
+ int alpha = hooks.registerHook("alpha");
+ EXPECT_EQ(2, alpha);
+ EXPECT_EQ(2, hooks.getIndex("alpha"));
+
+ int beta = hooks.registerHook("beta");
+ EXPECT_EQ(3, beta);
+ EXPECT_EQ(3, hooks.getIndex("beta"));
+
+ // Should be four hooks now
+ EXPECT_EQ(4, hooks.getCount());
+}
+
+// Check that duplicate names cannot be registered.
+// This test has been updated. See #5251 for details. The old
+// code is retained in case we decide to get back to it.
+TEST(ServerHooksTest, DISABLED_OldDuplicateHooks) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ // Ensure we can't duplicate one of the existing names.
+ EXPECT_THROW(hooks.registerHook("context_create"), DuplicateHook);
+
+ // Check we can't duplicate a newly registered hook.
+ int gamma = hooks.registerHook("gamma");
+ EXPECT_EQ(2, gamma);
+ EXPECT_THROW(hooks.registerHook("gamma"), DuplicateHook);
+}
+
+// Check that duplicate names are handled properly. The code used to throw,
+// but it now returns the existing index. See #5251 for details.
+TEST(ServerHooksTest, NewDuplicateHooks) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ int index = hooks.getIndex("context_create");
+
+ // Ensure we can duplicate one of the existing names.
+ // Instead of throwing, we just check that a reasonable
+ // index has been returned.
+ EXPECT_EQ(index, hooks.registerHook("context_create"));
+
+ // Check that mutiple attempts to register the same hook will return
+ // existing index.
+ int gamma = hooks.registerHook("gamma");
+ EXPECT_EQ(2, gamma);
+ EXPECT_EQ(gamma, hooks.registerHook("gamma"));
+ EXPECT_EQ(gamma, hooks.registerHook("gamma"));
+ EXPECT_EQ(gamma, hooks.registerHook("gamma"));
+ EXPECT_EQ(gamma, hooks.registerHook("gamma"));
+}
+
+// Checks that we can get the name of the hooks.
+
+TEST(ServerHooksTest, GetHookNames) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+ vector<string> expected_names;
+
+ // Add names into the hooks object and to the set of expected names.
+ expected_names.push_back("alpha");
+ expected_names.push_back("beta");
+ expected_names.push_back("gamma");
+ expected_names.push_back("delta");
+ for (size_t i = 0; i < expected_names.size(); ++i) {
+ hooks.registerHook(expected_names[i].c_str());
+ };
+
+ // Update the expected names to include the pre-defined hook names.
+ expected_names.push_back("context_create");
+ expected_names.push_back("context_destroy");
+
+ // Get the actual hook names
+ vector<string> actual_names = hooks.getHookNames();
+
+ // For comparison, sort the names into alphabetical order and do a straight
+ // vector comparison.
+ sort(expected_names.begin(), expected_names.end());
+ sort(actual_names.begin(), actual_names.end());
+
+ EXPECT_TRUE(expected_names == actual_names);
+}
+
+// Test the inverse hooks functionality (i.e. given an index, get the name).
+
+TEST(ServerHooksTest, GetHookIndexes) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ int alpha = hooks.registerHook("alpha");
+ int beta = hooks.registerHook("beta");
+ int gamma = hooks.registerHook("gamma");
+
+ EXPECT_EQ(std::string("context_create"),
+ hooks.getName(ServerHooks::CONTEXT_CREATE));
+ EXPECT_EQ(std::string("context_destroy"),
+ hooks.getName(ServerHooks::CONTEXT_DESTROY));
+ EXPECT_EQ(std::string("alpha"), hooks.getName(alpha));
+ EXPECT_EQ(std::string("beta"), hooks.getName(beta));
+ EXPECT_EQ(std::string("gamma"), hooks.getName(gamma));
+
+ // Check for an invalid index
+ EXPECT_THROW(hooks.getName(-1), NoSuchHook);
+ EXPECT_THROW(hooks.getName(42), NoSuchHook);
+}
+
+// Test the reset functionality.
+
+TEST(ServerHooksTest, Reset) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ int alpha = hooks.registerHook("alpha");
+ int beta = hooks.registerHook("beta");
+ int gamma = hooks.registerHook("gamma");
+
+ EXPECT_EQ(std::string("alpha"), hooks.getName(alpha));
+ EXPECT_EQ(std::string("beta"), hooks.getName(beta));
+ EXPECT_EQ(std::string("gamma"), hooks.getName(gamma));
+
+ // Check the counts before and after a reset.
+ EXPECT_EQ(5, hooks.getCount());
+ hooks.reset();
+ EXPECT_EQ(2, hooks.getCount());
+
+ // ... and check that the hooks are as expected.
+ EXPECT_EQ(0, hooks.getIndex("context_create"));
+ EXPECT_EQ(1, hooks.getIndex("context_destroy"));
+}
+
+// Check that getting an unknown name throws an exception.
+
+TEST(ServerHooksTest, UnknownHookName) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ EXPECT_THROW(static_cast<void>(hooks.getIndex("unknown")), NoSuchHook);
+ EXPECT_EQ(-1, hooks.findIndex("unknown"));
+}
+
+// Check that the count of hooks is correct.
+
+TEST(ServerHooksTest, HookCount) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+
+ // Insert the names into the hooks object
+ hooks.registerHook("alpha");
+ hooks.registerHook("beta");
+ hooks.registerHook("gamma");
+ hooks.registerHook("delta");
+
+ // Should be two more hooks that the number we have registered.
+ EXPECT_EQ(6, hooks.getCount());
+}
+
+// Check that the hook name is correctly generated for a control command name
+// and vice versa.
+
+TEST(ServerHooksTest, CommandToHookName) {
+ EXPECT_EQ("$x_y_z", ServerHooks::commandToHookName("x-y-z"));
+ EXPECT_EQ("$foo_bar_foo", ServerHooks::commandToHookName("foo-bar_foo"));
+ EXPECT_EQ("$", ServerHooks::commandToHookName(""));
+}
+
+TEST(ServerHooksTest, HookToCommandName) {
+ // Underscores replaced by hyphens.
+ EXPECT_EQ("x-y-z", ServerHooks::hookToCommandName("$x_y_z"));
+ EXPECT_EQ("foo-bar-foo", ServerHooks::hookToCommandName("$foo_bar-foo"));
+ // Single dollar is converted to empty string.
+ EXPECT_TRUE(ServerHooks::hookToCommandName("$").empty());
+ // If no dollar, it is not a hook name. Return empty string.
+ EXPECT_TRUE(ServerHooks::hookToCommandName("abc").empty());
+}
+
+TEST(ServerHooksTest, getParkingLots) {
+ ServerHooks& hooks = ServerHooks::getServerHooks();
+ hooks.reset();
+ int alpha_hook = hooks.registerHook("alpha");
+
+ ASSERT_TRUE(hooks.getParkingLotsPtr());
+ ASSERT_TRUE(hooks.getParkingLotPtr(alpha_hook));
+ ASSERT_TRUE(hooks.getParkingLotPtr("alpha"));
+}
+
+} // Anonymous namespace
diff --git a/src/lib/hooks/tests/test_libraries.h.in b/src/lib/hooks/tests/test_libraries.h.in
new file mode 100644
index 0000000..afad62f
--- /dev/null
+++ b/src/lib/hooks/tests/test_libraries.h.in
@@ -0,0 +1,61 @@
+// Copyright (C) 2013-2018 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 TEST_LIBRARIES_H
+#define TEST_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.
+
+// Basic library with context_create and three "standard" callouts.
+static const char* BASIC_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libbcl.so";
+
+// Library with context_create and three "standard" callouts, as well as
+// load() and unload() functions.
+static const char* FULL_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libfcl.so";
+
+// Library where the all framework functions throw an exception
+static const char* FRAMEWORK_EXCEPTION_LIBRARY = "@abs_builddir@/.libs/libfxl.so";
+
+// Library where the version() function returns an incorrect result.
+static const char* INCORRECT_VERSION_LIBRARY = "@abs_builddir@/.libs/libivl.so";
+
+// Library where some of the callout registration is done with the load()
+// function.
+static const char* LOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/liblcl.so";
+
+// Library where the load() function returns an error.
+static const char* LOAD_ERROR_CALLOUT_LIBRARY =
+ "@abs_builddir@/.libs/liblecl.so";
+
+// Name of a library which is not present.
+static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
+
+// Library that does not include a version function.
+static const char* NO_VERSION_LIBRARY = "@abs_builddir@/.libs/libnvl.so";
+
+// Library where there is an unload() function.
+static const char* UNLOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libucl.so";
+
+// Library where parameters are checked.
+static const char* CALLOUT_PARAMS_LIBRARY = "@abs_builddir@/.libs/libpcl.so";
+
+// Library which tests objects parking.
+// Used only by hooks_manager_unittest.cc.
+#ifdef TEST_ASYNC_CALLOUT
+static const char* ASYNC_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libacl.so";
+#endif
+
+} // anonymous namespace
+
+
+#endif // TEST_LIBRARIES_H
diff --git a/src/lib/hooks/tests/unload_callout_library.cc b/src/lib/hooks/tests/unload_callout_library.cc
new file mode 100644
index 0000000..a15b870
--- /dev/null
+++ b/src/lib/hooks/tests/unload_callout_library.cc
@@ -0,0 +1,46 @@
+// Copyright (C) 2013-2015 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/.
+
+/// @file
+/// @brief Basic unload library
+///
+/// This is source of a test library for various test (LibraryManager and
+/// HooksManager). The characteristics of the library produced from this
+/// file are:
+///
+/// - The "version" and "unload" framework functions are supplied. "version"
+/// returns a valid value and "unload" creates a marker file and returns
+/// success.
+
+#include <config.h>
+
+#include <hooks/hooks.h>
+#include <hooks/tests/marker_file.h>
+
+#include <fstream>
+
+using namespace isc::hooks;
+
+extern "C" {
+
+// Framework functions
+
+int
+version() {
+ return (KEA_HOOKS_VERSION);
+}
+
+int
+unload() {
+ // Create the marker file.
+ std::fstream marker;
+ marker.open(MARKER_FILE, std::fstream::out);
+ marker.close();
+
+ return (0);
+}
+
+};