summaryrefslogtreecommitdiffstats
path: root/src/lib/process/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/process/tests')
-rw-r--r--src/lib/process/tests/Makefile.am56
-rw-r--r--src/lib/process/tests/Makefile.in1184
-rw-r--r--src/lib/process/tests/cb_ctl_base_unittests.cc718
-rw-r--r--src/lib/process/tests/config_base_unittests.cc230
-rw-r--r--src/lib/process/tests/config_ctl_info_unittests.cc180
-rw-r--r--src/lib/process/tests/config_ctl_parser_unittests.cc102
-rw-r--r--src/lib/process/tests/d_cfg_mgr_unittests.cc375
-rw-r--r--src/lib/process/tests/d_controller_unittests.cc470
-rw-r--r--src/lib/process/tests/daemon_unittest.cc324
-rw-r--r--src/lib/process/tests/log_parser_unittests.cc530
-rw-r--r--src/lib/process/tests/logging_info_unittests.cc208
-rw-r--r--src/lib/process/tests/run_unittests.cc24
12 files changed, 4401 insertions, 0 deletions
diff --git a/src/lib/process/tests/Makefile.am b/src/lib/process/tests/Makefile.am
new file mode 100644
index 0000000..f556c76
--- /dev/null
+++ b/src/lib/process/tests/Makefile.am
@@ -0,0 +1,56 @@
+SUBDIRS = .
+dhcp_data_dir = @runstatedir@/@PACKAGE@
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/process/tests\"
+AM_CPPFLAGS += -DDATA_DIR="\"$(dhcp_data_dir)\""
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+TESTS += libprocess_unittests
+
+libprocess_unittests_SOURCES = d_cfg_mgr_unittests.cc
+libprocess_unittests_SOURCES += cb_ctl_base_unittests.cc
+libprocess_unittests_SOURCES += config_base_unittests.cc
+libprocess_unittests_SOURCES += config_ctl_info_unittests.cc
+libprocess_unittests_SOURCES += config_ctl_parser_unittests.cc
+libprocess_unittests_SOURCES += d_controller_unittests.cc
+libprocess_unittests_SOURCES += daemon_unittest.cc
+libprocess_unittests_SOURCES += log_parser_unittests.cc
+libprocess_unittests_SOURCES += logging_info_unittests.cc
+libprocess_unittests_SOURCES += run_unittests.cc
+
+libprocess_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+
+libprocess_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+
+libprocess_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+libprocess_unittests_LDADD = $(top_builddir)/src/lib/process/testutils/libprocesstest.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
+libprocess_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+libprocess_unittests_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS)
+libprocess_unittests_LDADD += $(BOOST_LIBS) $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/process/tests/Makefile.in b/src/lib/process/tests/Makefile.in
new file mode 100644
index 0000000..29101f1
--- /dev/null
+++ b/src/lib/process/tests/Makefile.in
@@ -0,0 +1,1184 @@
+# 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 = libprocess_unittests
+noinst_PROGRAMS = $(am__EXEEXT_2)
+subdir = src/lib/process/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 =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_GTEST_TRUE@am__EXEEXT_1 = libprocess_unittests$(EXEEXT)
+am__EXEEXT_2 = $(am__EXEEXT_1)
+PROGRAMS = $(noinst_PROGRAMS)
+am__libprocess_unittests_SOURCES_DIST = d_cfg_mgr_unittests.cc \
+ cb_ctl_base_unittests.cc config_base_unittests.cc \
+ config_ctl_info_unittests.cc config_ctl_parser_unittests.cc \
+ d_controller_unittests.cc daemon_unittest.cc \
+ log_parser_unittests.cc logging_info_unittests.cc \
+ run_unittests.cc
+@HAVE_GTEST_TRUE@am_libprocess_unittests_OBJECTS = libprocess_unittests-d_cfg_mgr_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-cb_ctl_base_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-config_base_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-config_ctl_info_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-config_ctl_parser_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-d_controller_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-daemon_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-log_parser_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-logging_info_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ libprocess_unittests-run_unittests.$(OBJEXT)
+libprocess_unittests_OBJECTS = $(am_libprocess_unittests_OBJECTS)
+am__DEPENDENCIES_1 =
+@HAVE_GTEST_TRUE@libprocess_unittests_DEPENDENCIES = $(top_builddir)/src/lib/process/testutils/libprocesstest.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/testutils/libkea-testutils.la \
+@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/log/libkea-log.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+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 =
+libprocess_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) \
+ $(libprocess_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)/libprocess_unittests-cb_ctl_base_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-config_base_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-d_controller_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-daemon_unittest.Po \
+ ./$(DEPDIR)/libprocess_unittests-log_parser_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-logging_info_unittests.Po \
+ ./$(DEPDIR)/libprocess_unittests-run_unittests.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 =
+SOURCES = $(libprocess_unittests_SOURCES)
+DIST_SOURCES = $(am__libprocess_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 $(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 = .
+dhcp_data_dir = @runstatedir@/@PACKAGE@
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \
+ $(BOOST_INCLUDES) \
+ -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/process/tests\" \
+ -DDATA_DIR="\"$(dhcp_data_dir)\"" \
+ -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static
+CLEANFILES = *.gcno *.gcda
+TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+@HAVE_GTEST_TRUE@libprocess_unittests_SOURCES = \
+@HAVE_GTEST_TRUE@ d_cfg_mgr_unittests.cc \
+@HAVE_GTEST_TRUE@ cb_ctl_base_unittests.cc \
+@HAVE_GTEST_TRUE@ config_base_unittests.cc \
+@HAVE_GTEST_TRUE@ config_ctl_info_unittests.cc \
+@HAVE_GTEST_TRUE@ config_ctl_parser_unittests.cc \
+@HAVE_GTEST_TRUE@ d_controller_unittests.cc daemon_unittest.cc \
+@HAVE_GTEST_TRUE@ log_parser_unittests.cc \
+@HAVE_GTEST_TRUE@ logging_info_unittests.cc run_unittests.cc
+@HAVE_GTEST_TRUE@libprocess_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+@HAVE_GTEST_TRUE@libprocess_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+@HAVE_GTEST_TRUE@libprocess_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+@HAVE_GTEST_TRUE@libprocess_unittests_LDADD = $(top_builddir)/src/lib/process/testutils/libprocesstest.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/config/libkea-cfgclient.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/http/libkea-http.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/testutils/libkea-testutils.la \
+@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/log/libkea-log.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) \
+@HAVE_GTEST_TRUE@ $(BOOST_LIBS) $(GTEST_LDADD)
+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/process/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib/process/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):
+
+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
+
+libprocess_unittests$(EXEEXT): $(libprocess_unittests_OBJECTS) $(libprocess_unittests_DEPENDENCIES) $(EXTRA_libprocess_unittests_DEPENDENCIES)
+ @rm -f libprocess_unittests$(EXEEXT)
+ $(AM_V_CXXLD)$(libprocess_unittests_LINK) $(libprocess_unittests_OBJECTS) $(libprocess_unittests_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-config_base_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-d_controller_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-daemon_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-log_parser_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-logging_info_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprocess_unittests-run_unittests.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 $@ $<
+
+libprocess_unittests-d_cfg_mgr_unittests.o: d_cfg_mgr_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-d_cfg_mgr_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Tpo -c -o libprocess_unittests-d_cfg_mgr_unittests.o `test -f 'd_cfg_mgr_unittests.cc' || echo '$(srcdir)/'`d_cfg_mgr_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Tpo $(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='d_cfg_mgr_unittests.cc' object='libprocess_unittests-d_cfg_mgr_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-d_cfg_mgr_unittests.o `test -f 'd_cfg_mgr_unittests.cc' || echo '$(srcdir)/'`d_cfg_mgr_unittests.cc
+
+libprocess_unittests-d_cfg_mgr_unittests.obj: d_cfg_mgr_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-d_cfg_mgr_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Tpo -c -o libprocess_unittests-d_cfg_mgr_unittests.obj `if test -f 'd_cfg_mgr_unittests.cc'; then $(CYGPATH_W) 'd_cfg_mgr_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/d_cfg_mgr_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Tpo $(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='d_cfg_mgr_unittests.cc' object='libprocess_unittests-d_cfg_mgr_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-d_cfg_mgr_unittests.obj `if test -f 'd_cfg_mgr_unittests.cc'; then $(CYGPATH_W) 'd_cfg_mgr_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/d_cfg_mgr_unittests.cc'; fi`
+
+libprocess_unittests-cb_ctl_base_unittests.o: cb_ctl_base_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-cb_ctl_base_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Tpo -c -o libprocess_unittests-cb_ctl_base_unittests.o `test -f 'cb_ctl_base_unittests.cc' || echo '$(srcdir)/'`cb_ctl_base_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Tpo $(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cb_ctl_base_unittests.cc' object='libprocess_unittests-cb_ctl_base_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-cb_ctl_base_unittests.o `test -f 'cb_ctl_base_unittests.cc' || echo '$(srcdir)/'`cb_ctl_base_unittests.cc
+
+libprocess_unittests-cb_ctl_base_unittests.obj: cb_ctl_base_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-cb_ctl_base_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Tpo -c -o libprocess_unittests-cb_ctl_base_unittests.obj `if test -f 'cb_ctl_base_unittests.cc'; then $(CYGPATH_W) 'cb_ctl_base_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/cb_ctl_base_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Tpo $(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cb_ctl_base_unittests.cc' object='libprocess_unittests-cb_ctl_base_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-cb_ctl_base_unittests.obj `if test -f 'cb_ctl_base_unittests.cc'; then $(CYGPATH_W) 'cb_ctl_base_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/cb_ctl_base_unittests.cc'; fi`
+
+libprocess_unittests-config_base_unittests.o: config_base_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-config_base_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-config_base_unittests.Tpo -c -o libprocess_unittests-config_base_unittests.o `test -f 'config_base_unittests.cc' || echo '$(srcdir)/'`config_base_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-config_base_unittests.Tpo $(DEPDIR)/libprocess_unittests-config_base_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_base_unittests.cc' object='libprocess_unittests-config_base_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-config_base_unittests.o `test -f 'config_base_unittests.cc' || echo '$(srcdir)/'`config_base_unittests.cc
+
+libprocess_unittests-config_base_unittests.obj: config_base_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-config_base_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-config_base_unittests.Tpo -c -o libprocess_unittests-config_base_unittests.obj `if test -f 'config_base_unittests.cc'; then $(CYGPATH_W) 'config_base_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_base_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-config_base_unittests.Tpo $(DEPDIR)/libprocess_unittests-config_base_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_base_unittests.cc' object='libprocess_unittests-config_base_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-config_base_unittests.obj `if test -f 'config_base_unittests.cc'; then $(CYGPATH_W) 'config_base_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_base_unittests.cc'; fi`
+
+libprocess_unittests-config_ctl_info_unittests.o: config_ctl_info_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-config_ctl_info_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Tpo -c -o libprocess_unittests-config_ctl_info_unittests.o `test -f 'config_ctl_info_unittests.cc' || echo '$(srcdir)/'`config_ctl_info_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Tpo $(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_ctl_info_unittests.cc' object='libprocess_unittests-config_ctl_info_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-config_ctl_info_unittests.o `test -f 'config_ctl_info_unittests.cc' || echo '$(srcdir)/'`config_ctl_info_unittests.cc
+
+libprocess_unittests-config_ctl_info_unittests.obj: config_ctl_info_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-config_ctl_info_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Tpo -c -o libprocess_unittests-config_ctl_info_unittests.obj `if test -f 'config_ctl_info_unittests.cc'; then $(CYGPATH_W) 'config_ctl_info_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_ctl_info_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Tpo $(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_ctl_info_unittests.cc' object='libprocess_unittests-config_ctl_info_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-config_ctl_info_unittests.obj `if test -f 'config_ctl_info_unittests.cc'; then $(CYGPATH_W) 'config_ctl_info_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_ctl_info_unittests.cc'; fi`
+
+libprocess_unittests-config_ctl_parser_unittests.o: config_ctl_parser_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-config_ctl_parser_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Tpo -c -o libprocess_unittests-config_ctl_parser_unittests.o `test -f 'config_ctl_parser_unittests.cc' || echo '$(srcdir)/'`config_ctl_parser_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Tpo $(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_ctl_parser_unittests.cc' object='libprocess_unittests-config_ctl_parser_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-config_ctl_parser_unittests.o `test -f 'config_ctl_parser_unittests.cc' || echo '$(srcdir)/'`config_ctl_parser_unittests.cc
+
+libprocess_unittests-config_ctl_parser_unittests.obj: config_ctl_parser_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-config_ctl_parser_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Tpo -c -o libprocess_unittests-config_ctl_parser_unittests.obj `if test -f 'config_ctl_parser_unittests.cc'; then $(CYGPATH_W) 'config_ctl_parser_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_ctl_parser_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Tpo $(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='config_ctl_parser_unittests.cc' object='libprocess_unittests-config_ctl_parser_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-config_ctl_parser_unittests.obj `if test -f 'config_ctl_parser_unittests.cc'; then $(CYGPATH_W) 'config_ctl_parser_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/config_ctl_parser_unittests.cc'; fi`
+
+libprocess_unittests-d_controller_unittests.o: d_controller_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-d_controller_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-d_controller_unittests.Tpo -c -o libprocess_unittests-d_controller_unittests.o `test -f 'd_controller_unittests.cc' || echo '$(srcdir)/'`d_controller_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-d_controller_unittests.Tpo $(DEPDIR)/libprocess_unittests-d_controller_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='d_controller_unittests.cc' object='libprocess_unittests-d_controller_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-d_controller_unittests.o `test -f 'd_controller_unittests.cc' || echo '$(srcdir)/'`d_controller_unittests.cc
+
+libprocess_unittests-d_controller_unittests.obj: d_controller_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-d_controller_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-d_controller_unittests.Tpo -c -o libprocess_unittests-d_controller_unittests.obj `if test -f 'd_controller_unittests.cc'; then $(CYGPATH_W) 'd_controller_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/d_controller_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-d_controller_unittests.Tpo $(DEPDIR)/libprocess_unittests-d_controller_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='d_controller_unittests.cc' object='libprocess_unittests-d_controller_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-d_controller_unittests.obj `if test -f 'd_controller_unittests.cc'; then $(CYGPATH_W) 'd_controller_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/d_controller_unittests.cc'; fi`
+
+libprocess_unittests-daemon_unittest.o: daemon_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-daemon_unittest.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-daemon_unittest.Tpo -c -o libprocess_unittests-daemon_unittest.o `test -f 'daemon_unittest.cc' || echo '$(srcdir)/'`daemon_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-daemon_unittest.Tpo $(DEPDIR)/libprocess_unittests-daemon_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='daemon_unittest.cc' object='libprocess_unittests-daemon_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-daemon_unittest.o `test -f 'daemon_unittest.cc' || echo '$(srcdir)/'`daemon_unittest.cc
+
+libprocess_unittests-daemon_unittest.obj: daemon_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-daemon_unittest.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-daemon_unittest.Tpo -c -o libprocess_unittests-daemon_unittest.obj `if test -f 'daemon_unittest.cc'; then $(CYGPATH_W) 'daemon_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/daemon_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-daemon_unittest.Tpo $(DEPDIR)/libprocess_unittests-daemon_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='daemon_unittest.cc' object='libprocess_unittests-daemon_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-daemon_unittest.obj `if test -f 'daemon_unittest.cc'; then $(CYGPATH_W) 'daemon_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/daemon_unittest.cc'; fi`
+
+libprocess_unittests-log_parser_unittests.o: log_parser_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-log_parser_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-log_parser_unittests.Tpo -c -o libprocess_unittests-log_parser_unittests.o `test -f 'log_parser_unittests.cc' || echo '$(srcdir)/'`log_parser_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-log_parser_unittests.Tpo $(DEPDIR)/libprocess_unittests-log_parser_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='log_parser_unittests.cc' object='libprocess_unittests-log_parser_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-log_parser_unittests.o `test -f 'log_parser_unittests.cc' || echo '$(srcdir)/'`log_parser_unittests.cc
+
+libprocess_unittests-log_parser_unittests.obj: log_parser_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-log_parser_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-log_parser_unittests.Tpo -c -o libprocess_unittests-log_parser_unittests.obj `if test -f 'log_parser_unittests.cc'; then $(CYGPATH_W) 'log_parser_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/log_parser_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-log_parser_unittests.Tpo $(DEPDIR)/libprocess_unittests-log_parser_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='log_parser_unittests.cc' object='libprocess_unittests-log_parser_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-log_parser_unittests.obj `if test -f 'log_parser_unittests.cc'; then $(CYGPATH_W) 'log_parser_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/log_parser_unittests.cc'; fi`
+
+libprocess_unittests-logging_info_unittests.o: logging_info_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-logging_info_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-logging_info_unittests.Tpo -c -o libprocess_unittests-logging_info_unittests.o `test -f 'logging_info_unittests.cc' || echo '$(srcdir)/'`logging_info_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-logging_info_unittests.Tpo $(DEPDIR)/libprocess_unittests-logging_info_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='logging_info_unittests.cc' object='libprocess_unittests-logging_info_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-logging_info_unittests.o `test -f 'logging_info_unittests.cc' || echo '$(srcdir)/'`logging_info_unittests.cc
+
+libprocess_unittests-logging_info_unittests.obj: logging_info_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-logging_info_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-logging_info_unittests.Tpo -c -o libprocess_unittests-logging_info_unittests.obj `if test -f 'logging_info_unittests.cc'; then $(CYGPATH_W) 'logging_info_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/logging_info_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-logging_info_unittests.Tpo $(DEPDIR)/libprocess_unittests-logging_info_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='logging_info_unittests.cc' object='libprocess_unittests-logging_info_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-logging_info_unittests.obj `if test -f 'logging_info_unittests.cc'; then $(CYGPATH_W) 'logging_info_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/logging_info_unittests.cc'; fi`
+
+libprocess_unittests-run_unittests.o: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/libprocess_unittests-run_unittests.Tpo -c -o libprocess_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libprocess_unittests-run_unittests.Tpo $(DEPDIR)/libprocess_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='libprocess_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+
+libprocess_unittests-run_unittests.obj: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -MT libprocess_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/libprocess_unittests-run_unittests.Tpo -c -o libprocess_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)/libprocess_unittests-run_unittests.Tpo $(DEPDIR)/libprocess_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='libprocess_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) $(libprocess_unittests_CPPFLAGS) $(CPPFLAGS) $(libprocess_unittests_CXXFLAGS) $(CXXFLAGS) -c -o libprocess_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.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)
+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)
+
+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-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/libprocess_unittests-cb_ctl_base_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-config_base_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-d_controller_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-daemon_unittest.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-log_parser_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-logging_info_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-run_unittests.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)/libprocess_unittests-cb_ctl_base_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-config_base_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-config_ctl_info_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-config_ctl_parser_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-d_cfg_mgr_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-d_controller_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-daemon_unittest.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-log_parser_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-logging_info_unittests.Po
+ -rm -f ./$(DEPDIR)/libprocess_unittests-run_unittests.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-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/process/tests/cb_ctl_base_unittests.cc b/src/lib/process/tests/cb_ctl_base_unittests.cc
new file mode 100644
index 0000000..58d0aa0
--- /dev/null
+++ b/src/lib/process/tests/cb_ctl_base_unittests.cc
@@ -0,0 +1,718 @@
+// Copyright (C) 2019-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 <config_backend/base_config_backend_mgr.h>
+#include <config_backend/base_config_backend_pool.h>
+#include <process/cb_ctl_base.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+#include <map>
+#include <string>
+
+using namespace isc;
+using namespace isc::cb;
+using namespace isc::db;
+using namespace isc::process;
+
+namespace {
+
+/// @brief Implementation of the config backend for testing the
+/// @c CBControlBase template class.
+///
+/// This simple class allows for adding, retrieving and clearing audit
+/// entries. The @c CBControlBase unit tests use it to control the
+/// behavior of the @c CBControlBase class under test.
+class CBControlBackend : BaseConfigBackend {
+public:
+
+ /// @brief Constructor.
+ CBControlBackend(const db::DatabaseConnection::ParameterMap&) {
+ }
+
+ /// @brief Retrieves the audit entries later than specified time.
+ ///
+ /// @param modification_time The lower bound time for which audit
+ /// entries should be returned.
+ /// @param modification_id The lower bound id for which audit
+ /// entries should be returned.
+ ///
+ /// @return Collection of audit entries later than specified time.
+ virtual db::AuditEntryCollection
+ getRecentAuditEntries(const db::ServerSelector&,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t modification_id) const {
+ db::AuditEntryCollection filtered_entries;
+
+ // Use the index which orders the audit entries by timestamps.
+ const auto& index = audit_entries_.get<AuditEntryModificationTimeIdTag>();
+
+ // Locate the first audit entry after the last one having the
+ // specified modification time and id.
+ auto modification = boost::make_tuple(modification_time, modification_id);
+ auto first_entry = index.upper_bound(modification);
+
+ // If there are any entries found return them.
+ if (first_entry != index.end()) {
+ filtered_entries.insert(first_entry, index.end());
+ }
+
+ return (filtered_entries);
+ }
+
+ /// @brief Add audit entry to the backend.
+ ///
+ /// @param object_type Object type to be stored in the audit entry.
+ /// @param object_id Object id to be stored in the audit entry.
+ /// @param modification_time Audit entry modification time to be set.
+ /// @param modification_id Audit entry modification id to be set.
+ void addAuditEntry(const ServerSelector&,
+ const std::string& object_type,
+ const uint64_t object_id,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t modification_id) {
+ // Create new audit entry from the specified parameters.
+ AuditEntryPtr audit_entry(new AuditEntry(object_type,
+ object_id,
+ AuditEntry::ModificationType::CREATE,
+ modification_time,
+ modification_id,
+ "added audit entry"));
+
+ // The audit entries are held in the static variable so as they
+ // don't disappear when we diconnect from the backend. The
+ // audit entries are explicitly cleared during the unit tests
+ // setup.
+ audit_entries_.insert(audit_entry);
+ }
+
+ /// @brief Returns backend type in the textual format.
+ ///
+ /// @return Name of the storage for configurations, e.g. "mysql",
+ /// "pgsql" and so forth.
+ virtual std::string getType() const {
+ return ("memfile");
+ }
+
+ /// @brief Returns backend host
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return host on which the database is located.
+ virtual std::string getHost() const {
+ return ("");
+ }
+
+ /// @brief Returns backend port number.
+ ///
+ /// This is used by the @c BaseConfigBackendPool to select backend
+ /// when @c BackendSelector is specified.
+ ///
+ /// @return Port number on which database service is available.
+ virtual uint16_t getPort() const {
+ return (0);
+ }
+
+ /// @brief Removes audit entries.
+ static void clearAuditEntries() {
+ audit_entries_.clear();
+ }
+
+private:
+
+ /// @brief Static collection of audit entries.
+ ///
+ /// Thanks to storing them in the static member they are preserved
+ /// when the unit tests "disconnect" from the backend.
+ static AuditEntryCollection audit_entries_;
+};
+
+/// @brief Pointer to the @c CBControlBackend object.
+typedef boost::shared_ptr<CBControlBackend> CBControlBackendPtr;
+
+AuditEntryCollection CBControlBackend::audit_entries_;
+
+/// @brief Implementation of the backends pool used in the
+/// @c CBControlBase template class unit tests.
+class CBControlBackendPool : public BaseConfigBackendPool<CBControlBackend> {
+public:
+
+ /// @brief Add audit entry to the backend.
+ ///
+ /// @param backend_selector Backend selector.
+ /// @param server_selector Server selector.
+ /// @param object_type Object type to be stored in the audit entry.
+ /// @param object_id Object id to be stored in the audit entry.
+ /// @param modification_time Audit entry modification time to be set.
+ /// @param modification_id Audit entry modification id to be set.
+ void addAuditEntry(const BackendSelector& backend_selector,
+ const ServerSelector& server_selector,
+ const std::string& object_type,
+ const uint64_t object_id,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t modification_id) {
+ createUpdateDeleteProperty<void, const std::string&, uint64_t,
+ const boost::posix_time::ptime&, uint64_t>
+ (&CBControlBackend::addAuditEntry, backend_selector, server_selector,
+ object_type, object_id, modification_time, modification_id);
+ }
+
+ /// @brief Retrieves the audit entries later than specified time.
+ ///
+ /// @param backend_selector Backend selector.
+ /// @param server_selector Server selector.
+ /// @param modification_time The lower bound time for which audit
+ /// entries should be returned.
+ /// @param modification_id The lower bound id for which audit
+ /// entries should be returned.
+ ///
+ /// @return Collection of audit entries later than specified time.
+ virtual db::AuditEntryCollection
+ getRecentAuditEntries(const BackendSelector& backend_selector,
+ const ServerSelector& server_selector,
+ const boost::posix_time::ptime& modification_time,
+ const uint64_t modification_id) const {
+ AuditEntryCollection audit_entries;
+ getMultiplePropertiesConst<AuditEntryCollection, const boost::posix_time::ptime&>
+ (&CBControlBackend::getRecentAuditEntries, backend_selector,
+ server_selector, audit_entries, modification_time,
+ modification_id);
+ return (audit_entries);
+ }
+};
+
+/// @brief Implementation of the config backends manager used
+/// in the @c CBControlBase template class unit tests.
+class CBControlBackendMgr : public BaseConfigBackendMgr<CBControlBackendPool> {
+public:
+
+ /// @brief Constructor.
+ CBControlBackendMgr()
+ : instance_id_(0) {
+ }
+
+ /// @brief Returns instance of the @c CBControlBackendMgr.
+ ///
+ /// @return Reference to the instance of the @c CBControlBackendMgr.
+ static CBControlBackendMgr& instance() {
+ static CBControlBackendMgr mgr;
+ return (mgr);
+ }
+
+ /// @brief Returns instance id.
+ ///
+ /// This value is used in tests which verify that the @c CBControlBase::getMgr
+ /// returns the right instance of the CB manager.
+ ///
+ /// @return Instance id.
+ uint32_t getInstanceId() const {
+ return (instance_id_);
+ }
+
+ /// @brief Sets new instance id.
+ ///
+ /// @param instance_id New instance id.
+ void setInstanceId(const uint32_t instance_id) {
+ instance_id_ = instance_id;
+ }
+
+ /// @brief Instance id.
+ uint32_t instance_id_;
+};
+
+/// @brief Implementation of the @c CBControlBase class used in
+/// the unit tests.
+///
+/// It makes some of the protected methods public. It also provides
+/// means to test the behavior of the @c CBControlBase template.
+class CBControl : public CBControlBase<CBControlBackendMgr> {
+public:
+
+ using CBControlBase<CBControlBackendMgr>::fetchConfigElement;
+ using CBControlBase<CBControlBackendMgr>::getMgr;
+ using CBControlBase<CBControlBackendMgr>::getInitialAuditRevisionTime;
+
+ /// @brief Constructor.
+ CBControl()
+ : CBControlBase<CBControlBackendMgr>(),
+ merges_num_(0),
+ backend_selector_(BackendSelector::Type::MYSQL),
+ server_selector_(ServerSelector::UNASSIGNED()),
+ audit_entries_num_(-1),
+ enable_throw_(false) {
+ }
+
+ /// @brief Implementation of the method called to fetch and apply
+ /// configuration from the database into the local configuration.
+ ///
+ /// This stub implementation doesn't attempt to merge any configurations
+ /// but merely records the values of the parameters called.
+ ///
+ /// @param backend_selector Backend selector.
+ /// @param server_selector Server selector.
+ /// @param audit_entries Collection of audit entries.
+ virtual void databaseConfigApply(const BackendSelector& backend_selector,
+ const ServerSelector& server_selector,
+ const boost::posix_time::ptime&,
+ const AuditEntryCollection& audit_entries) {
+ ++merges_num_;
+ backend_selector_ = backend_selector;
+ server_selector_ = server_selector;
+ audit_entries_num_ = static_cast<int>(audit_entries.size());
+
+ if (enable_throw_) {
+ isc_throw(Unexpected, "throwing from databaseConfigApply");
+ }
+ }
+
+ /// @brief Returns the number of times the @c databaseConfigApply was called.
+ size_t getMergesNum() const {
+ return (merges_num_);
+ }
+
+ /// @brief Returns backend selector used as an argument in a call to
+ /// @c databaseConfigApply.
+ const BackendSelector& getBackendSelector() const {
+ return (backend_selector_);
+ }
+
+ /// @brief Returns server selector used as an argument in a call to
+ /// @c databaseConfigApply.
+ const ServerSelector& getServerSelector() const {
+ return (server_selector_);
+ }
+
+ /// @brief Returns the number of audit entries in the collection passed
+ /// to @c databaseConfigApply
+ int getAuditEntriesNum() const {
+ return (audit_entries_num_);
+ }
+
+ /// @brief Returns the recorded time of last audit entry.
+ boost::posix_time::ptime getLastAuditRevisionTime() const {
+ return (last_audit_revision_time_);
+ }
+
+ /// @brief Returns the recorded id of last audit entry.
+ uint64_t getLastAuditRevisionId() const {
+ return (last_audit_revision_id_);
+ }
+
+ /// @brief Overwrites the last audit entry time.
+ ///
+ /// @param last_audit_revision_time New time to be set.
+ void setLastAuditRevisionTime(const boost::posix_time::ptime& last_audit_revision_time) {
+ last_audit_revision_time_ = last_audit_revision_time;
+ }
+
+ /// @brief Overwrites the last audit revision id.
+ ///
+ /// @param last_audit_revision_id New id to be set.
+ void setLastAuditRevisionId(const uint64_t& last_audit_revision_id) {
+ last_audit_revision_id_ = last_audit_revision_id;
+ }
+
+ /// @brief Enables the @c databaseConfigApply function to throw.
+ ///
+ /// This is useful to test scenarios when configuration merge fails.
+ void enableThrow() {
+ enable_throw_ = true;
+ }
+
+private:
+
+ /// @brief Recorded number of calls to @c databaseConfigApply.
+ size_t merges_num_;
+
+ /// @brief Recorded backend selector value.
+ BackendSelector backend_selector_;
+
+ /// @brief Recorded server selector value.
+ ServerSelector server_selector_;
+
+ /// @brief Recorded number of audit entries.
+ int audit_entries_num_;
+
+ /// @brief Boolean value indicating if the @c databaseConfigApply should throw.
+ bool enable_throw_;
+};
+
+/// @brief Out of the blue instance id used in tests.
+constexpr uint32_t TEST_INSTANCE_ID = 123;
+
+/// @brief Test fixture class for @c CBControlBase template class.
+class CBControlBaseTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor.
+ CBControlBaseTest()
+ : cb_ctl_(), mgr_(CBControlBackendMgr::instance()),
+ timestamps_() {
+ mgr_.registerBackendFactory("db1",
+ [](const DatabaseConnection::ParameterMap& params)
+ -> CBControlBackendPtr {
+ return (CBControlBackendPtr(new CBControlBackend(params)));
+ });
+ mgr_.setInstanceId(TEST_INSTANCE_ID);
+ initTimestamps();
+ CBControlBackend::clearAuditEntries();
+ }
+
+ /// @brief Destructor.
+ ///
+ /// Removes audit entries created in the test.
+ ~CBControlBaseTest() {
+ CBControlBackend::clearAuditEntries();
+ }
+
+ /// @brief Initialize posix time values used in tests.
+ void initTimestamps() {
+ // Current time minus 1 hour to make sure it is in the past.
+ timestamps_["today"] = boost::posix_time::second_clock::local_time()
+ - boost::posix_time::hours(1);
+ // Yesterday.
+ timestamps_["yesterday"] = timestamps_["today"] - boost::posix_time::hours(24);
+ // Two days ago.
+ timestamps_["two days ago"] = timestamps_["today"] - boost::posix_time::hours(48);
+ // Tomorrow.
+ timestamps_["tomorrow"] = timestamps_["today"] + boost::posix_time::hours(24);
+ }
+
+ /// @brief Creates an instance of the configuration object.
+ ///
+ /// @param db1_access Database access string to be used to connect to
+ /// the test configuration backend. It doesn't connect if the string
+ /// is empty.
+ ConfigPtr makeConfigBase(const std::string& db1_access = "") const {
+ ConfigControlInfoPtr config_ctl_info(new ConfigControlInfo());
+
+ if (!db1_access.empty()) {
+ config_ctl_info->addConfigDatabase(db1_access);
+ }
+
+ ConfigPtr config_base(new ConfigBase());
+
+ config_base->setConfigControlInfo(config_ctl_info);
+ return (config_base);
+ }
+
+ /// @brief Instance of the @c CBControl used in tests.
+ CBControl cb_ctl_;
+
+ /// @brief Instance of the Config Backend Manager.
+ CBControlBackendMgr& mgr_;
+
+ /// @brief Holds timestamp values used in tests.
+ std::map<std::string, boost::posix_time::ptime> timestamps_;
+};
+
+// This test verifies that the same instance of the Config
+// Backend Manager is returned all the time.
+TEST_F(CBControlBaseTest, getMgr) {
+ auto mgr = cb_ctl_.getMgr();
+ EXPECT_EQ(TEST_INSTANCE_ID, mgr.getInstanceId());
+}
+
+// This test verifies that the initial audit revision time is set to
+// local time of 2000-01-01.
+TEST_F(CBControlBaseTest, getInitialAuditRevisionTime) {
+ auto initial_time = cb_ctl_.getInitialAuditRevisionTime();
+ ASSERT_FALSE(initial_time.is_not_a_date_time());
+ auto tm = boost::posix_time::to_tm(initial_time);
+ EXPECT_EQ(100, tm.tm_year);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_sec);
+}
+
+// This test verifies that last audit entry time is reset upon the
+// call to CBControlBase::reset().
+TEST_F(CBControlBaseTest, reset) {
+ cb_ctl_.setLastAuditRevisionTime(timestamps_["tomorrow"]);
+ cb_ctl_.reset();
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(0, cb_ctl_.getLastAuditRevisionId());
+}
+
+// This test verifies that it is correctly determined what entries the
+// server should fetch for the particular configuration element.
+TEST_F(CBControlBaseTest, fetchConfigElement) {
+ db::AuditEntryCollection audit_entries;
+ db::AuditEntryCollection updated;
+ // When audit entries collection is empty any subset is empty too.
+ updated = cb_ctl_.fetchConfigElement(audit_entries, "my_object_type");
+ EXPECT_TRUE(updated.empty());
+
+ // Now test the case that there is a DELETE audit entry. In this case
+ // our function should indicate that the configuration should not be
+ // fetched for the given object type. Note that when the configuration
+ // element is deleted, it no longer exists in database so there is
+ // no reason to fetch the data from the database.
+ AuditEntryPtr audit_entry(new AuditEntry("dhcp4_subnet", 1234 ,
+ AuditEntry::ModificationType::DELETE,
+ 2345, "added audit entry"));
+ audit_entries.insert(audit_entry);
+ updated = cb_ctl_.fetchConfigElement(audit_entries, "my_object_type");
+ EXPECT_TRUE(updated.empty());
+ EXPECT_TRUE(hasObjectId(audit_entries, 1234));
+ EXPECT_FALSE(hasObjectId(audit_entries, 5678));
+ EXPECT_FALSE(hasObjectId(updated, 1234));
+
+ // Add another audit entry which indicates creation of the configuration element.
+ // This time we should get it.
+ audit_entry.reset(new AuditEntry("my_object_type", 5678,
+ AuditEntry::ModificationType::CREATE,
+ 6789, "added audit entry"));
+ audit_entries.insert(audit_entry);
+ updated = cb_ctl_.fetchConfigElement(audit_entries, "my_object_type");
+ ASSERT_EQ(1, updated.size());
+ AuditEntryPtr updated_entry = (*updated.begin());
+ ASSERT_TRUE(updated_entry);
+ EXPECT_EQ("my_object_type", updated_entry->getObjectType());
+ EXPECT_EQ(5678, updated_entry->getObjectId());
+ EXPECT_EQ(AuditEntry::ModificationType::CREATE, updated_entry->getModificationType());
+ EXPECT_TRUE(hasObjectId(audit_entries, 5678));
+ EXPECT_TRUE(hasObjectId(updated, 5678));
+ EXPECT_FALSE(hasObjectId(updated, 1234));
+
+ // Also we should get 'true' for the UPDATE case.
+ audit_entry.reset(new AuditEntry("my_object_type",
+ 5678, AuditEntry::ModificationType::UPDATE,
+ 6790, "added audit entry"));
+ audit_entries.insert(audit_entry);
+ updated = cb_ctl_.fetchConfigElement(audit_entries, "my_object_type");
+ EXPECT_EQ(2, updated.size());
+ bool saw_create = false;
+ bool saw_update = false;
+ for (auto entry : updated) {
+ EXPECT_EQ("my_object_type", entry->getObjectType());
+ EXPECT_EQ(5678, entry->getObjectId());
+ if (AuditEntry::ModificationType::CREATE == entry->getModificationType()) {
+ EXPECT_FALSE(saw_create);
+ saw_create = true;
+ } else if (AuditEntry::ModificationType::UPDATE == entry->getModificationType()) {
+ EXPECT_FALSE(saw_update);
+ saw_update = true;
+ }
+ }
+ EXPECT_TRUE(saw_create);
+ EXPECT_TRUE(saw_update);
+ EXPECT_TRUE(hasObjectId(updated, 5678));
+ EXPECT_FALSE(hasObjectId(updated, 1234));
+}
+
+// This test verifies that true is return when the server successfully
+// connects to the backend and false if there are no backends to connect
+// to.
+TEST_F(CBControlBaseTest, connect) {
+ EXPECT_TRUE(cb_ctl_.databaseConfigConnect(makeConfigBase("type=db1")));
+ EXPECT_FALSE(cb_ctl_.databaseConfigConnect(makeConfigBase()));
+}
+
+// This test verifies the scenario when the server fetches the entire
+// configuration from the database upon startup.
+TEST_F(CBControlBaseTest, fetchAll) {
+ auto config_base = makeConfigBase("type=db1");
+
+ // Add two audit entries to the database. The server should load
+ // the entire configuration from the database regardless of the
+ // existing audit entries. However, the last audit entry timestamp
+ // should be set to the most recent audit entry in the
+ // @c CBControlBase.
+ ASSERT_TRUE(cb_ctl_.databaseConfigConnect(config_base));
+
+ cb_ctl_.getMgr().getPool()->addAuditEntry(BackendSelector::UNSPEC(),
+ ServerSelector::ALL(),
+ "sql_table_2",
+ 1234,
+ timestamps_["yesterday"],
+ 2345);
+
+ cb_ctl_.getMgr().getPool()->addAuditEntry(BackendSelector::UNSPEC(),
+ ServerSelector::ALL(),
+ "sql_table_1",
+ 3456,
+ timestamps_["today"],
+ 4567);
+
+ // Disconnect from the database in order to check that the
+ // databaseConfigFetch reconnects.
+ ASSERT_NO_THROW(cb_ctl_.databaseConfigDisconnect());
+
+ // Verify that various indicators are set to their initial values.
+ ASSERT_EQ(0, cb_ctl_.getMergesNum());
+ ASSERT_EQ(BackendSelector::Type::MYSQL, cb_ctl_.getBackendSelector().getBackendType());
+ ASSERT_EQ(ServerSelector::Type::UNASSIGNED, cb_ctl_.getServerSelector().getType());
+ ASSERT_EQ(-1, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(0, cb_ctl_.getLastAuditRevisionId());
+
+ // Connect to the database and fetch the configuration.
+ ASSERT_NO_THROW(cb_ctl_.databaseConfigFetch(config_base));
+
+ // There should be one invocation of the databaseConfigApply.
+ ASSERT_EQ(1, cb_ctl_.getMergesNum());
+ // Since this is full reconfiguration the audit entry collection
+ // passed to the databaseConfigApply should be empty.
+ EXPECT_EQ(0, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(BackendSelector::Type::UNSPEC, cb_ctl_.getBackendSelector().getBackendType());
+ EXPECT_EQ(ServerSelector::Type::ALL, cb_ctl_.getServerSelector().getType());
+ // Make sure that the internal timestamp is set to the most recent
+ // audit entry, so as the server will only later fetch config
+ // updates after this timestamp.
+ EXPECT_EQ(timestamps_["today"], cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(4567, cb_ctl_.getLastAuditRevisionId());
+}
+
+// This test verifies that the configuration can be fetched for a
+// specified server tag.
+TEST_F(CBControlBaseTest, fetchFromServer) {
+ auto config_base = makeConfigBase("type=db1");
+ // Set a server tag.
+ config_base->setServerTag("a-tag");
+
+ // Verify that various indicators are set to their initial values.
+ ASSERT_EQ(0, cb_ctl_.getMergesNum());
+ ASSERT_EQ(BackendSelector::Type::MYSQL, cb_ctl_.getBackendSelector().getBackendType());
+ ASSERT_EQ(ServerSelector::Type::UNASSIGNED, cb_ctl_.getServerSelector().getType());
+ ASSERT_EQ(-1, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(0, cb_ctl_.getLastAuditRevisionId());
+
+ ASSERT_NO_THROW(cb_ctl_.databaseConfigFetch(config_base));
+
+ ASSERT_EQ(1, cb_ctl_.getMergesNum());
+ EXPECT_EQ(0, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(BackendSelector::Type::UNSPEC, cb_ctl_.getBackendSelector().getBackendType());
+ // An explicit server selector should have been used this time.
+ ASSERT_EQ(ServerSelector::Type::SUBSET, cb_ctl_.getServerSelector().getType());
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+
+ // Make sure that the server selector used in databaseConfigFetch is
+ // correct.
+ auto tags = cb_ctl_.getServerSelector().getTags();
+ ASSERT_EQ(1, tags.size());
+ EXPECT_EQ("a-tag", tags.begin()->get());
+}
+
+// This test verifies that incremental configuration changes can be
+// fetched.
+TEST_F(CBControlBaseTest, fetchUpdates) {
+ auto config_base = makeConfigBase("type=db1");
+
+ // Connect to the database and store an audit entry. Do not close
+ // the database connection to simulate the case when the server
+ // uses existing connection to fetch configuration updates.
+ ASSERT_TRUE(cb_ctl_.databaseConfigConnect(config_base));
+ cb_ctl_.getMgr().getPool()->addAuditEntry(BackendSelector::UNSPEC(),
+ ServerSelector::ALL(),
+ "sql_table_1",
+ 3456,
+ timestamps_["today"],
+ 4567);
+
+ // Verify that various indicators are set to their initial values.
+ ASSERT_EQ(0, cb_ctl_.getMergesNum());
+ ASSERT_EQ(BackendSelector::Type::MYSQL, cb_ctl_.getBackendSelector().getBackendType());
+ ASSERT_EQ(ServerSelector::Type::UNASSIGNED, cb_ctl_.getServerSelector().getType());
+ ASSERT_EQ(-1, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(0, cb_ctl_.getLastAuditRevisionId());
+
+ ASSERT_NO_THROW(cb_ctl_.databaseConfigFetch(config_base,
+ CBControl::FetchMode::FETCH_UPDATE));
+
+ // There should be one invocation to databaseConfigApply recorded.
+ ASSERT_EQ(1, cb_ctl_.getMergesNum());
+ // The number of audit entries passed to this function should be 1.
+ EXPECT_EQ(1, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(BackendSelector::Type::UNSPEC, cb_ctl_.getBackendSelector().getBackendType());
+ EXPECT_EQ(ServerSelector::Type::ALL, cb_ctl_.getServerSelector().getType());
+ // The last audit entry time should be set to the latest audit entry.
+ EXPECT_EQ(timestamps_["today"], cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(4567, cb_ctl_.getLastAuditRevisionId());
+}
+
+// Check that the databaseConfigApply function is not called when there
+// are no more unprocessed audit entries.
+TEST_F(CBControlBaseTest, fetchNoUpdates) {
+ auto config_base = makeConfigBase("type=db1");
+
+ // Set last audit entry time to the timestamp of the audit
+ // entry we are going to add. That means that there will be
+ // no new audit entries to fetch.
+ cb_ctl_.setLastAuditRevisionTime(timestamps_["yesterday"]);
+ cb_ctl_.setLastAuditRevisionId(4567);
+
+ ASSERT_TRUE(cb_ctl_.databaseConfigConnect(config_base));
+
+ cb_ctl_.getMgr().getPool()->addAuditEntry(BackendSelector::UNSPEC(),
+ ServerSelector::ALL(),
+ "sql_table_1",
+ 3456,
+ timestamps_["yesterday"],
+ 4567);
+
+ ASSERT_EQ(0, cb_ctl_.getMergesNum());
+
+ ASSERT_NO_THROW(cb_ctl_.databaseConfigFetch(config_base,
+ CBControl::FetchMode::FETCH_UPDATE));
+
+ // The databaseConfigApply should not be called because there are
+ // no new audit entires to process.
+ ASSERT_EQ(0, cb_ctl_.getMergesNum());
+}
+
+// This test verifies that database config fetch failures are handled
+// gracefully.
+TEST_F(CBControlBaseTest, fetchFailure) {
+ auto config_base = makeConfigBase("type=db1");
+
+ // Connect to the database and store an audit entry. Do not close
+ // the database connection to simulate the case when the server
+ // uses existing connection to fetch configuration updates.
+ ASSERT_TRUE(cb_ctl_.databaseConfigConnect(config_base));
+ cb_ctl_.getMgr().getPool()->addAuditEntry(BackendSelector::UNSPEC(),
+ ServerSelector::ALL(),
+ "sql_table_1",
+ 3456,
+ timestamps_["today"],
+ 4567);
+
+ // Configure the CBControl to always throw simulating the failure
+ // during configuration merge.
+ cb_ctl_.enableThrow();
+
+ // Verify that various indicators are set to their initial values.
+ ASSERT_EQ(0, cb_ctl_.getMergesNum());
+ ASSERT_EQ(BackendSelector::Type::MYSQL, cb_ctl_.getBackendSelector().getBackendType());
+ ASSERT_EQ(ServerSelector::Type::UNASSIGNED, cb_ctl_.getServerSelector().getType());
+ ASSERT_EQ(-1, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(0, cb_ctl_.getLastAuditRevisionId());
+
+ ASSERT_THROW(cb_ctl_.databaseConfigFetch(config_base, CBControl::FetchMode::FETCH_UPDATE),
+ isc::Unexpected);
+
+ // There should be one invocation to databaseConfigApply recorded.
+ ASSERT_EQ(1, cb_ctl_.getMergesNum());
+ // The number of audit entries passed to this function should be 1.
+ EXPECT_EQ(1, cb_ctl_.getAuditEntriesNum());
+ EXPECT_EQ(BackendSelector::Type::UNSPEC, cb_ctl_.getBackendSelector().getBackendType());
+ EXPECT_EQ(ServerSelector::Type::ALL, cb_ctl_.getServerSelector().getType());
+ // The last audit entry time should not be modified because there was a merge
+ // error.
+ EXPECT_EQ(cb_ctl_.getInitialAuditRevisionTime(), cb_ctl_.getLastAuditRevisionTime());
+ EXPECT_EQ(0, cb_ctl_.getLastAuditRevisionId());
+}
+
+}
diff --git a/src/lib/process/tests/config_base_unittests.cc b/src/lib/process/tests/config_base_unittests.cc
new file mode 100644
index 0000000..cec4582
--- /dev/null
+++ b/src/lib/process/tests/config_base_unittests.cc
@@ -0,0 +1,230 @@
+// Copyright (C) 2018-2019 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 <process/config_base.h>
+#include <util/optional.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::process;
+using namespace isc::util;
+
+/// @brief Derived ConfigBase class
+/// We use this derivation to test the
+/// copy and equality functions.
+class ConfigBaseImpl : public ConfigBase {
+public:
+ void
+ copy(ConfigBaseImpl& other) const {
+ ConfigBase::copy(other);
+ }
+};
+
+// Verifies construction, copy, and equality of
+// ConfigBase with respect to ConfigControInfo.
+TEST(ConfigBase, configControlInfoTests) {
+
+ // Create a control info instance
+ ConfigControlInfoPtr ctl_info1(new ConfigControlInfo());
+ ctl_info1->addConfigDatabase("type=mysql host=example.com");
+ ctl_info1->addConfigDatabase("type=mysql host=example2.com");
+
+ // Create a ConfigBase
+ ConfigBaseImpl base1;
+ base1.setConfigControlInfo(ctl_info1);
+
+ // Clone the ConfigBase
+ ConfigBaseImpl base2;
+ base1.copy(base2);
+
+ // They should be equal.
+ EXPECT_TRUE(base1.equals(base2));
+
+ // Reset control info for one of them.
+ base1.setConfigControlInfo(ConfigControlInfoPtr());
+
+ // They should not be equal.
+ EXPECT_FALSE(base1.equals(base2));
+
+ // Reset control info for the other one.
+ base2.setConfigControlInfo(ConfigControlInfoPtr());
+
+ // They should be equal again.
+ EXPECT_TRUE(base1.equals(base2));
+}
+
+// Verifies that logging information can be merged to another.
+TEST(ConfigBase, mergeLoggingInfo) {
+ // Create first logging info.
+ LoggingInfo log_info1;
+ log_info1.name_ = "foo";
+
+ // Create second logging info.
+ LoggingInfo log_info2;
+ log_info2.name_ = "bar";
+
+ // Create first config base instance.
+ ConfigBaseImpl base1;
+ base1.addLoggingInfo(log_info1);
+
+ // Copy the first instance to keep it as reference.
+ ConfigBaseImpl base1_copy;
+ base1_copy.copy(base1);
+
+ // Create second config base instance.
+ ConfigBaseImpl base2;
+ ASSERT_NO_THROW(base1.merge(base2));
+ EXPECT_TRUE(base1.equals(base1_copy));
+
+ // Set some data for the second config.
+ base2.addLoggingInfo(log_info2);
+
+ // This time the merge should replace the original config.
+ ASSERT_NO_THROW(base1.merge(base2));
+ EXPECT_TRUE(base1.equals(base2));
+}
+
+// Verifies that config control can be merged to another.
+TEST(ConfigBase, mergeConfigControl) {
+ // Create first config control info.
+ ConfigControlInfoPtr ctl_info1(new ConfigControlInfo());
+ ctl_info1->addConfigDatabase("type=mysql host=example.com");
+ ctl_info1->addConfigDatabase("type=mysql host=example2.com");
+
+ // Create second config control info.
+ ConfigControlInfoPtr ctl_info2(new ConfigControlInfo());
+ ctl_info2->addConfigDatabase("type=pgsql host=example.com");
+ ctl_info2->addConfigDatabase("type=pgsql host=example2.com");
+
+ // Create first config base instance.
+ ConfigBaseImpl base1;
+ base1.setConfigControlInfo(ctl_info1);
+
+ // Copy the first instance to keep it as reference.
+ ConfigBaseImpl base1_copy;
+ base1_copy.copy(base1);
+
+ // Create second config base instance.
+ ConfigBaseImpl base2;
+
+ // Merged base is empty, so the original should be preserved.
+ ASSERT_NO_THROW(base1.merge(base2));
+ EXPECT_TRUE(base1.equals(base1_copy));
+
+ // Set some data for the second config.
+ base2.setConfigControlInfo(ctl_info2);
+
+ // This time the merge should replace the original config.
+ ASSERT_NO_THROW(base1.merge(base2));
+ EXPECT_TRUE(base1.equals(base2));
+}
+
+// Verifies that server-tag may be configured.
+TEST(ConfigBase, serverTag) {
+ ConfigBaseImpl conf;
+
+ // Check that the default is an unspecified and empty string.
+ EXPECT_TRUE(conf.getServerTag().unspecified());
+ EXPECT_TRUE(conf.getServerTag().empty());
+
+ // Check that it can be modified.
+ conf.setServerTag("boo");
+ EXPECT_FALSE(conf.getServerTag().unspecified());
+ EXPECT_EQ("boo", conf.getServerTag().get());
+}
+
+// Verifies that server tag can be merged to another config.
+TEST(ConfigBase, mergeServerTag) {
+ ConfigBaseImpl base1;
+ ConfigBaseImpl base2;
+
+ // Initially the server tags in both config should be
+ // unspecified.
+ EXPECT_TRUE(base1.getServerTag().unspecified());
+ EXPECT_TRUE(base2.getServerTag().unspecified());
+
+ // Merging the config with unspecified server tag should
+ // not modify the target config.
+ ASSERT_NO_THROW(base1.merge(base2));
+ EXPECT_TRUE(base1.getServerTag().unspecified());
+ EXPECT_TRUE(base2.getServerTag().unspecified());
+
+ // Set server tag for base2 and merge it.
+ base2.setServerTag(std::string("base2"));
+ ASSERT_NO_THROW(base1.merge(base2));
+
+ // The server tag should be copied into the base1. Both
+ // should now be unspecified.
+ EXPECT_FALSE(base1.getServerTag().unspecified());
+ EXPECT_FALSE(base2.getServerTag().unspecified());
+
+ // They should also hold the same value.
+ EXPECT_EQ("base2", base1.getServerTag().get());
+ EXPECT_EQ("base2", base2.getServerTag().get());
+
+ // Reset the server tag to unspecified.
+ base2.setServerTag(Optional<std::string>());
+ EXPECT_FALSE(base1.getServerTag().unspecified());
+ EXPECT_TRUE(base2.getServerTag().unspecified());
+
+ // Merging the config with unspecified server tag should
+ // result in no change in the target config.
+ ASSERT_NO_THROW(base1.merge(base2));
+ EXPECT_FALSE(base1.getServerTag().unspecified());
+ EXPECT_TRUE(base2.getServerTag().unspecified());
+
+ // The server tag should remain the same.
+ EXPECT_EQ("base2", base1.getServerTag().get());
+
+ // Set the explicit server tag in the source config.
+ base2.setServerTag("new-base2");
+
+ // Merge again.
+ ASSERT_NO_THROW(base1.merge(base2));
+
+ // The new value should be stored in the target config, so
+ // both should be specified and have the same value.
+ EXPECT_FALSE(base1.getServerTag().unspecified());
+ EXPECT_FALSE(base2.getServerTag().unspecified());
+ EXPECT_EQ("new-base2", base1.getServerTag().get());
+ EXPECT_EQ("new-base2", base2.getServerTag().get());
+}
+
+// Verifies that server tag can be copied to another config.
+TEST(ConfigBase, copyServerTag) {
+ ConfigBaseImpl base1;
+ ConfigBaseImpl base2;
+
+ // Set server tag for the base2.
+ base2.setServerTag(std::string("base2"));
+
+ // The base1 has server tag unspecified. Copying it to the
+ // base2 should result in unspecified server tag in base2.
+ ASSERT_NO_THROW(base1.copy(base2));
+ EXPECT_TRUE(base2.getServerTag().unspecified());
+
+ // Set server tag for base1 and copy it to base2.
+ base1.setServerTag(std::string("base1"));
+ ASSERT_NO_THROW(base1.copy(base2));
+
+ // The base2 should now hold the value from base1.
+ EXPECT_FALSE(base2.getServerTag().unspecified());
+ EXPECT_EQ("base1", base2.getServerTag().get());
+
+ // Set base1 value to a different value.
+ base1.setServerTag(std::string("new-base1"));
+
+ // Copy again.
+ ASSERT_NO_THROW(base1.copy(base2));
+
+ // It should override the value in the base2.
+ EXPECT_FALSE(base2.getServerTag().unspecified());
+ EXPECT_EQ("new-base1", base2.getServerTag().get());
+}
diff --git a/src/lib/process/tests/config_ctl_info_unittests.cc b/src/lib/process/tests/config_ctl_info_unittests.cc
new file mode 100644
index 0000000..7c78014
--- /dev/null
+++ b/src/lib/process/tests/config_ctl_info_unittests.cc
@@ -0,0 +1,180 @@
+// Copyright (C) 2018-2022 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 <process/config_ctl_info.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+#include <iostream>
+
+using namespace isc::process;
+using namespace isc::data;
+using namespace isc::util;
+
+// Verifies initializing via an access string and unparsing into elements
+// We just test basic unparsing, as more rigorous testing is done in
+// libkea-db testing which ConfigDBInfo uses.
+TEST(ConfigDbInfo, basicOperation) {
+ ConfigDbInfo db;
+ std::string access = "type=mysql user=tom password=terrific";
+ std::string redacted_access = "password=***** type=mysql user=tom";
+ std::string access_json = "{\n"
+ " \"type\":\"mysql\", \n"
+ " \"user\":\"tom\", \n"
+ " \"password\":\"terrific\" \n"
+ "} \n";
+
+ // Convert the above configuration into Elements for comparison.
+ ElementPtr exp_elems;
+ ASSERT_NO_THROW(exp_elems = Element::fromJSON(access_json))
+ << "test is broken";
+
+ // Initialize the db from an the access string
+ db.setAccessString(access);
+ EXPECT_EQ(access, db.getAccessString());
+
+ EXPECT_EQ(redacted_access, db.redactedAccessString());
+
+ // Convert the db into Elements and make sure they are as expected.
+ ElementPtr db_elems;
+ ASSERT_NO_THROW(db_elems = db.toElement());
+ EXPECT_TRUE(db_elems->equals(*exp_elems));
+}
+
+// Verify that db parameter values may be retrieved.
+TEST(ConfigDbInfo, getParameterValue) {
+ ConfigDbInfo db1;
+ std::string access1 = "type=mysql name=keatest port=33 readonly=false";
+ db1.setAccessString(access1);
+
+ std::string value;
+ bool found = false;
+
+ // Should find "type"
+ ASSERT_NO_THROW(found = db1.getParameterValue("type", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("mysql", value);
+
+ // Should find "name"
+ ASSERT_NO_THROW(found = db1.getParameterValue("name", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("keatest", value);
+
+ // Should find "port"
+ ASSERT_NO_THROW(found = db1.getParameterValue("port", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("33", value);
+
+ // Should find "readonly"
+ ASSERT_NO_THROW(found = db1.getParameterValue("readonly", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("false", value);
+
+ // Should not find "bogus"
+ ASSERT_NO_THROW(found = db1.getParameterValue("bogus", value));
+ EXPECT_FALSE(found);
+}
+
+// Verify that db equality operators work correctly.
+TEST(ConfigDbInfo, equalityOperators) {
+ ConfigDbInfo db1;
+ std::string access1 = "type=mysql user=tom password=terrific";
+ ASSERT_NO_THROW(db1.setAccessString(access1));
+
+ ConfigDbInfo db2;
+ std::string access2 = "type=postgresql user=tom password=terrific";
+ ASSERT_NO_THROW(db2.setAccessString(access2));
+
+ // Verify that the two unequal dbs are in fact not equal.
+ EXPECT_FALSE(db1.equals(db2));
+ EXPECT_FALSE(db1 == db2);
+ EXPECT_TRUE(db1 != db2);
+
+ // Verify that the two equal dbs are in fact equal.
+ db2.setAccessString(access1);
+ EXPECT_TRUE(db1.equals(db2));
+ EXPECT_TRUE(db1 == db2);
+ EXPECT_FALSE(db1 != db2);
+}
+
+// Verifies the basic operations of ConfigControlInfo
+TEST(ConfigControlInfo, basicOperation) {
+
+ ConfigControlInfo ctl;
+ // We should have no dbs in the list.
+ EXPECT_EQ(0, ctl.getConfigDatabases().size());
+ // The default fetch time is 30 and it is unspecified.
+ EXPECT_TRUE(ctl.getConfigFetchWaitTime().unspecified());
+ EXPECT_EQ(30, ctl.getConfigFetchWaitTime().get());
+
+ // Override the default fetch time.
+ ctl.setConfigFetchWaitTime(Optional<uint16_t>(123));
+ EXPECT_EQ(123, ctl.getConfigFetchWaitTime().get());
+
+ // We should be able to add two distinct, valid dbs
+ std::string access_str1 = "type=mysql host=machine1.org";
+ ASSERT_NO_THROW(ctl.addConfigDatabase(access_str1));
+
+ std::string access_str2 = "type=postgresql host=machine2.org";
+ ASSERT_NO_THROW(ctl.addConfigDatabase(access_str2));
+
+ // We should fail on a duplicate db.
+ ASSERT_THROW(ctl.addConfigDatabase(access_str1), isc::BadValue);
+
+ // We should have two dbs in the list.
+ const ConfigDbInfoList& db_list = ctl.getConfigDatabases();
+ EXPECT_EQ(2, db_list.size());
+
+ // Verify the dbs in the list are as we expect them to be.
+ EXPECT_EQ (access_str1, db_list[0].getAccessString());
+ EXPECT_EQ (access_str2, db_list[1].getAccessString());
+
+ // Verify we can find dbs based on a property values.
+ const ConfigDbInfo& db_info = ctl.findConfigDb("type", "mysql");
+ EXPECT_FALSE(db_info == ConfigControlInfo::EMPTY_DB());
+ EXPECT_EQ (access_str1, db_info.getAccessString());
+
+ const ConfigDbInfo& db_info2 = ctl.findConfigDb("host", "machine2.org");
+ EXPECT_FALSE(db_info2 == ConfigControlInfo::EMPTY_DB());
+ EXPECT_EQ (access_str2, db_info2.getAccessString());
+
+ // Verify not finding a db returns EMPTY_DB().
+ const ConfigDbInfo& db_info3 = ctl.findConfigDb("type", "bogus");
+ EXPECT_TRUE(db_info3 == ConfigControlInfo::EMPTY_DB());
+
+ // Verify we can clear the list of dbs and the fetch time.
+ ctl.clear();
+ EXPECT_EQ(0, ctl.getConfigDatabases().size());
+ EXPECT_TRUE(ctl.getConfigFetchWaitTime().unspecified());
+ EXPECT_EQ(30, ctl.getConfigFetchWaitTime().get());
+}
+
+// Verifies the copy ctor and equality functions ConfigControlInfo
+TEST(ConfigControlInfo, copyAndEquality) {
+
+ // Make an instance with two dbs.
+ ConfigControlInfo ctl1;
+ ASSERT_NO_THROW(ctl1.addConfigDatabase("type=mysql host=mach1.org"));
+ ASSERT_NO_THROW(ctl1.addConfigDatabase("type=postgresql host=mach2.org"));
+ ctl1.setConfigFetchWaitTime(Optional<uint16_t>(123));
+
+ // Clone that instance.
+ ConfigControlInfo ctl2(ctl1);
+
+ // They should be equal.
+ EXPECT_TRUE(ctl1.equals(ctl2));
+
+ // Make a third instance with a different db.
+ ConfigControlInfo ctl3;
+ ASSERT_NO_THROW(ctl1.addConfigDatabase("type=mysql host=other.org"));
+
+ // They should not equal.
+ EXPECT_FALSE(ctl3.equals(ctl1));
+}
+
diff --git a/src/lib/process/tests/config_ctl_parser_unittests.cc b/src/lib/process/tests/config_ctl_parser_unittests.cc
new file mode 100644
index 0000000..8e5b328
--- /dev/null
+++ b/src/lib/process/tests/config_ctl_parser_unittests.cc
@@ -0,0 +1,102 @@
+// Copyright (C) 2018-2019 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 <cc/dhcp_config_error.h>
+#include <process/config_ctl_parser.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+#include <iostream>
+
+using namespace isc::process;
+using namespace isc::data;
+
+// Verifies valid configurations are parsed correctly. The test
+// uses round-trip comparison of configuration Elements to determine
+// if parsing was correct.
+TEST(ConfigCtlInfoParser, validConfigs) {
+ std::string configs[] = {
+ "{}",
+
+ "{ \"config-databases\": [], \n"
+ " \"config-fetch-wait-time\": 20 \n"
+ "}",
+
+ "{ \"config-databases\": [ \n"
+ " { \n"
+ " \"type\": \"mysql\", \n"
+ " \"user\":\"tom\", \n"
+ " \"password\":\"terrific\" \n"
+ " }, \n"
+ " { \n"
+ " \"type\": \"postgresql\",\n"
+ " \"user\":\"bob\", \n"
+ " \"password\":\"wonder\" \n"
+ " } \n"
+ "] } \n"
+ };
+
+ for (auto config : configs) {
+ ConfigControlParser parser;
+ ConfigControlInfoPtr ctl_info;
+
+ // Turn the JSON config into Elements.
+ ElementPtr source_elem;
+ ASSERT_NO_THROW (source_elem = Element::fromJSON(config)) <<
+ " JSON error, test is broken: " << config;
+
+ // Parse the Elements into a ConfigControlInfo.
+ ASSERT_NO_THROW(ctl_info = parser.parse(source_elem));
+ ASSERT_TRUE(ctl_info);
+
+ // Turn the newly constructed info instance back into elements.
+ ElementPtr parsed_elem;
+ ASSERT_NO_THROW(parsed_elem = ctl_info->toElement());
+
+ // When the config is empty, ControlConfigInfo::toElement still
+ // generates a map with an empty db list. Replace source for
+ // element comparison below.
+ if (source_elem->size() == 0) {
+ ASSERT_NO_THROW (source_elem = Element::fromJSON(
+ "{ \"config-databases\": [] }"));
+ }
+
+ // The parsed element should match the source element.
+ EXPECT_TRUE(parsed_elem->equals(*source_elem)) << "config: " << config;
+ }
+}
+
+// Verify that invalid configurations fail to parse gracefully.
+TEST(ConfigCtlInfoParser, invalidConfigs) {
+ // Note that configurations are must be valid JSON, but invalid logically.
+ std::string configs[] = {
+ "{ \"config-databases\": \"not_list\" }",
+ "{ \"config-databases\": [ \n"
+ " { \n"
+ " \"bogus\": \"param\" \n"
+ " } \n"
+ "] } \n",
+ "{ \"config-fetch-wait-time\": -1 }",
+ "{ \"config-fetch-wait-time\": 65537 }",
+ "{ \"config-fetch-wait-time\": \"a-string\" }",
+ };
+
+ for (auto config : configs) {
+ ConfigControlParser parser;
+
+ // Turn the JSON config into Elements.
+ ElementPtr source_elem;
+ ASSERT_NO_THROW (source_elem = Element::fromJSON(config)) <<
+ " JSON error, test is broken: " << config;
+
+ // Parse the Elements into a ConfigControlInfo.
+ ASSERT_THROW(parser.parse(source_elem), isc::ConfigError)
+ << "config: " << config;
+ }
+}
diff --git a/src/lib/process/tests/d_cfg_mgr_unittests.cc b/src/lib/process/tests/d_cfg_mgr_unittests.cc
new file mode 100644
index 0000000..faa3e92
--- /dev/null
+++ b/src/lib/process/tests/d_cfg_mgr_unittests.cc
@@ -0,0 +1,375 @@
+// 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 <cc/command_interpreter.h>
+#include <exceptions/exceptions.h>
+#include <process/testutils/d_test_stubs.h>
+#include <process/d_cfg_mgr.h>
+#include <process/redact_config.h>
+
+#include <boost/foreach.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <gtest/gtest.h>
+
+#include <sstream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::config;
+using namespace isc::process;
+using namespace isc::data;
+using namespace boost::posix_time;
+
+namespace {
+
+/// @brief Test Class for verifying that configuration context cannot be null
+/// during construction.
+class DCtorTestCfgMgr : public DCfgMgrBase {
+public:
+ /// @brief Constructor - Note that is passes in an empty configuration
+ /// pointer to the base class constructor.
+ DCtorTestCfgMgr() : DCfgMgrBase(ConfigPtr()) {
+ }
+
+ /// @brief Destructor
+ virtual ~DCtorTestCfgMgr() {
+ }
+
+ /// @brief Dummy implementation as this method is abstract.
+ virtual ConfigPtr createNewContext() {
+ return (ConfigPtr());
+ }
+
+ /// @brief Returns summary of configuration in the textual format.
+ virtual std::string getConfigSummary(const uint32_t) {
+ return ("");
+ }
+};
+
+/// @brief Test fixture class for testing DCfgMgrBase class.
+/// It maintains an member instance of DStubCfgMgr and derives from
+/// ConfigParseTest fixture, thus providing methods for converting JSON
+/// strings to configuration element sets, checking parse results,
+/// accessing the configuration context and trying to unparse.
+class DStubCfgMgrTest : public ConfigParseTest {
+public:
+
+ /// @brief Constructor
+ DStubCfgMgrTest():cfg_mgr_(new DStubCfgMgr) {
+ }
+
+ /// @brief Destructor
+ ~DStubCfgMgrTest() {
+ }
+
+ /// @brief Convenience method which returns a DStubContextPtr to the
+ /// configuration context.
+ ///
+ /// @return returns a DStubContextPtr.
+ DStubContextPtr getStubContext() {
+ return (boost::dynamic_pointer_cast<DStubContext>
+ (cfg_mgr_->getContext()));
+ }
+
+ /// @brief Configuration manager instance.
+ DStubCfgMgrPtr cfg_mgr_;
+};
+
+///@brief Tests basic construction/destruction of configuration manager.
+/// Verifies that:
+/// 1. Proper construction succeeds.
+/// 2. Configuration context is initialized by construction.
+/// 3. Destruction works properly.
+/// 4. Construction with a null context is not allowed.
+TEST(DCfgMgrBase, construction) {
+ DCfgMgrBasePtr cfg_mgr;
+
+ // Verify that configuration manager constructions without error.
+ ASSERT_NO_THROW(cfg_mgr.reset(new DStubCfgMgr()));
+
+ // Verify that the context can be retrieved and is not null.
+ ConfigPtr context = cfg_mgr->getContext();
+ EXPECT_TRUE(context);
+
+ // Verify that the manager can be destructed without error.
+ EXPECT_NO_THROW(cfg_mgr.reset());
+
+ // Verify that an attempt to construct a manger with a null context fails.
+ ASSERT_THROW(DCtorTestCfgMgr(), DCfgMgrBaseError);
+}
+
+///@brief Tests fundamental aspects of configuration parsing.
+/// Verifies that:
+/// 1. A correctly formed simple configuration parses without error.
+/// 2. An error building the element is handled.
+/// 3. An error committing the element is handled.
+/// 4. An unknown element error is handled.
+TEST_F(DStubCfgMgrTest, basicParseTest) {
+ // Create a simple configuration.
+ string config = "{ \"test-value\": [] } ";
+ ASSERT_TRUE(fromJSON(config));
+
+ // Verify that we can parse a simple configuration.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ EXPECT_TRUE(checkAnswer(0));
+
+ // Verify that we can check a simple configuration.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, true);
+ EXPECT_TRUE(checkAnswer(0));
+}
+
+/// @brief Tests that element ids supported by the base class as well as those
+/// added by the derived class function properly.
+/// This test verifies that:
+/// 1. Boolean parameters can be parsed and retrieved.
+/// 2. Uint32 parameters can be parsed and retrieved.
+/// 3. String parameters can be parsed and retrieved.
+/// 4. Map elements can be parsed and retrieved.
+/// 5. List elements can be parsed and retrieved.
+/// 6. Parsing a second configuration, updates the existing context values
+/// correctly.
+TEST_F(DStubCfgMgrTest, simpleTypesTest) {
+ // Create a configuration with all of the parameters.
+ string config = "{ \"bool_test\": true , "
+ " \"uint32_test\": 77 , "
+ " \"string_test\": \"hmmm chewy\" , "
+ " \"map_test\" : {} , "
+ " \"list_test\": [] }";
+ ASSERT_TRUE(fromJSON(config));
+
+ // Verify that the configuration parses without error.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ ASSERT_TRUE(checkAnswer(0));
+ DStubContextPtr context = getStubContext();
+ ASSERT_TRUE(context);
+
+ // Create a configuration which "updates" all of the parameter values.
+ string config2 = "{ \"bool_test\": false , "
+ " \"uint32_test\": 88 , "
+ " \"string_test\": \"ewww yuk!\" , "
+ " \"map_test2\" : {} , "
+ " \"list_test2\": [] }";
+ ASSERT_TRUE(fromJSON(config2));
+
+ // Verify that the configuration parses without error.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ EXPECT_TRUE(checkAnswer(0));
+ context = getStubContext();
+ ASSERT_TRUE(context);
+}
+
+/// @brief Tests that the configuration context is preserved after failure
+/// during parsing causes a rollback.
+/// 1. Verifies configuration context rollback.
+TEST_F(DStubCfgMgrTest, rollBackTest) {
+ // Create a configuration with all of the parameters.
+ string config = "{ \"bool_test\": true , "
+ " \"uint32_test\": 77 , "
+ " \"string_test\": \"hmmm chewy\" , "
+ " \"map_test\" : {} , "
+ " \"list_test\": [] }";
+ ASSERT_TRUE(fromJSON(config));
+
+ // Verify that the configuration parses without error.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ EXPECT_TRUE(checkAnswer(0));
+ DStubContextPtr context = getStubContext();
+ ASSERT_TRUE(context);
+
+ // Create a configuration which "updates" all of the parameter values
+ // plus one unknown at the end.
+ string config2 = "{ \"bool_test\": false , "
+ " \"uint32_test\": 88 , "
+ " \"string_test\": \"ewww yuk!\" , "
+ " \"map_test2\" : {} , "
+ " \"list_test2\": [] , "
+ " \"zeta_unknown\": 33 } ";
+ ASSERT_TRUE(fromJSON(config2));
+}
+
+/// @brief Tests that the configuration context is preserved during
+/// check only parsing.
+TEST_F(DStubCfgMgrTest, checkOnly) {
+ // Create a configuration with all of the parameters.
+ string config = "{ \"bool_test\": true , "
+ " \"uint32_test\": 77 , "
+ " \"string_test\": \"hmmm chewy\" , "
+ " \"map_test\" : {} , "
+ " \"list_test\": [] }";
+ ASSERT_TRUE(fromJSON(config));
+
+ // Verify that the configuration parses without error.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ EXPECT_TRUE(checkAnswer(0));
+ DStubContextPtr context = getStubContext();
+ ASSERT_TRUE(context);
+
+
+ // Create a configuration which "updates" all of the parameter values.
+ string config2 = "{ \"bool_test\": false , "
+ " \"uint32_test\": 88 , "
+ " \"string_test\": \"ewww yuk!\" , "
+ " \"map_test2\" : {} , "
+ " \"list_test2\": [] }";
+ ASSERT_TRUE(fromJSON(config2));
+
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, true);
+ EXPECT_TRUE(checkAnswer(0));
+ context = getStubContext();
+ ASSERT_TRUE(context);
+
+}
+
+// Tests that configuration element position is returned by getParam variants.
+TEST_F(DStubCfgMgrTest, paramPosition) {
+ // Create a configuration with one of each scalar types. We end them
+ // with line feeds so we can test position value.
+ string config = "{ \"bool_test\": true , \n"
+ " \"uint32_test\": 77 , \n"
+ " \"string_test\": \"hmmm chewy\" }";
+ ASSERT_TRUE(fromJSON(config));
+
+ // Verify that the configuration parses without error.
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ ASSERT_TRUE(checkAnswer(0));
+ DStubContextPtr context = getStubContext();
+ ASSERT_TRUE(context);
+
+}
+
+// This tests if some aspects of simpleParseConfig are behaving properly.
+// Thorough testing is only possible for specific implementations. This
+// is done for control agent (see CtrlAgentControllerTest tests in
+// src/bin/agent/tests/ctrl_agent_controller_unittest.cc for example).
+// Also, shell tests in src/bin/agent/ctrl_agent_process_tests.sh test
+// the whole CA process that uses simpleParseConfig. The alternative
+// would be to implement whole parser that would set the context
+// properly. The ROI for this is not worth the effort.
+TEST_F(DStubCfgMgrTest, simpleParseConfig) {
+ using namespace isc::data;
+
+ // Passing just null pointer should result in error return code
+ answer_ = cfg_mgr_->simpleParseConfig(ConstElementPtr(), false);
+ EXPECT_TRUE(checkAnswer(1));
+
+ // Ok, now try with a dummy, but valid json code
+ string config = "{ \"bool_test\": true , \n"
+ " \"uint32_test\": 77 , \n"
+ " \"string_test\": \"hmmm chewy\" }";
+ ASSERT_NO_THROW(fromJSON(config));
+
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false);
+ EXPECT_TRUE(checkAnswer(0));
+}
+
+// This test checks that the post configuration callback function is
+// executed by the simpleParseConfig function.
+TEST_F(DStubCfgMgrTest, simpleParseConfigWithCallback) {
+ string config = "{ \"bool_test\": true , \n"
+ " \"uint32_test\": 77 , \n"
+ " \"string_test\": \"hmmm chewy\" }";
+ ASSERT_NO_THROW(fromJSON(config));
+
+ answer_ = cfg_mgr_->simpleParseConfig(config_set_, false,
+ []() {
+ isc_throw(Unexpected, "unexpected configuration error");
+ });
+ EXPECT_TRUE(checkAnswer(1));
+}
+
+// This test checks that redactConfig works as expected.
+TEST_F(DStubCfgMgrTest, redactConfig) {
+ // Basic case.
+ string config = "{ \"foo\": 1 }";
+ ConstElementPtr elem;
+ ASSERT_NO_THROW(elem = Element::fromJSON(config));
+ ConstElementPtr ret;
+ ASSERT_NO_THROW(ret = redactConfig(elem));
+ EXPECT_EQ(ret->str(), elem->str());
+
+ // Verify redaction.
+ config = "{ \"password\": \"foo\", \"secret\": \"bar\" }";
+ ASSERT_NO_THROW(elem = Element::fromJSON(config));
+ ASSERT_NO_THROW(ret = redactConfig(elem));
+ string expected = "{ \"password\": \"*****\", \"secret\": \"*****\" }";
+ EXPECT_EQ(expected, ret->str());
+
+ // Verify that user context are skipped.
+ config = "{ \"user-context\": { \"password\": \"foo\" } }";
+ ASSERT_NO_THROW(elem = Element::fromJSON(config));
+ ASSERT_NO_THROW(ret = redactConfig(elem));
+ EXPECT_EQ(ret->str(), elem->str());
+
+ // Verify that only given subtrees are handled.
+ list<string> keys = { "foo" };
+ config = "{ \"foo\": { \"password\": \"foo\" }, ";
+ config += "\"next\": { \"secret\": \"bar\" } }";
+ ASSERT_NO_THROW(elem = Element::fromJSON(config));
+ ASSERT_NO_THROW(ret = redactConfig(elem, keys));
+ expected = "{ \"foo\": { \"password\": \"*****\" }, ";
+ expected += "\"next\": { \"secret\": \"bar\" } }";
+ EXPECT_EQ(expected, ret->str());
+}
+
+// Test that user context is not touched when configuration is redacted.
+TEST(RedactConfig, userContext) {
+ ConstElementPtr const config(Element::fromJSON(R"(
+ {
+ "some-database": {
+ "password": "sensitive",
+ "secret": "sensitive",
+ "user": "keatest",
+ "nested-map": {
+ "password": "sensitive",
+ "secret": "sensitive",
+ "user": "keatest"
+ }
+ },
+ "user-context": {
+ "password": "keatest",
+ "secret": "keatest",
+ "user": "keatest",
+ "nested-map": {
+ "password": "keatest",
+ "secret": "keatest",
+ "user": "keatest"
+ }
+ }
+ }
+ )"));
+ ConstElementPtr const expected(Element::fromJSON(R"(
+ {
+ "some-database": {
+ "password": "*****",
+ "secret": "*****",
+ "user": "keatest",
+ "nested-map": {
+ "password": "*****",
+ "secret": "*****",
+ "user": "keatest"
+ }
+ },
+ "user-context": {
+ "password": "keatest",
+ "secret": "keatest",
+ "user": "keatest",
+ "nested-map": {
+ "password": "keatest",
+ "secret": "keatest",
+ "user": "keatest"
+ }
+ }
+ }
+ )"));
+ ConstElementPtr redacted(redactConfig(config));
+ EXPECT_TRUE(isEquivalent(redacted, expected))
+ << "Actual:\n" << prettyPrint(redacted) << "\n"
+ "Expected:\n" << prettyPrint(expected);
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/process/tests/d_controller_unittests.cc b/src/lib/process/tests/d_controller_unittests.cc
new file mode 100644
index 0000000..4d7b73c
--- /dev/null
+++ b/src/lib/process/tests/d_controller_unittests.cc
@@ -0,0 +1,470 @@
+// 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 <kea_version.h>
+
+#include <asiolink/testutils/timed_signal.h>
+#include <cc/command_interpreter.h>
+#include <process/testutils/d_test_stubs.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <gtest/gtest.h>
+
+#include <sstream>
+
+using namespace isc::asiolink::test;
+using namespace boost::posix_time;
+
+namespace isc {
+namespace process {
+
+/// @brief Test fixture class for testing DControllerBase class. This class
+/// derives from DControllerTest and wraps a DStubController. DStubController
+/// has been constructed to exercise DControllerBase.
+class DStubControllerTest : public DControllerTest {
+public:
+ /// @brief Constructor.
+ /// Note the constructor passes in the static DStubController instance
+ /// method.
+ DStubControllerTest() : DControllerTest(DStubController::instance) {
+ controller_ = boost::dynamic_pointer_cast<DStubController>
+ (DControllerTest::
+ getController());
+ }
+
+ /// @brief The controller.
+ DStubControllerPtr controller_;
+};
+
+/// @brief Basic Controller instantiation testing.
+/// Verifies that the controller singleton gets created and that the
+/// basic derivation from the base class is intact.
+TEST_F(DStubControllerTest, basicInstanceTesting) {
+ // Verify that the singleton exists and it is the correct type.
+ DControllerBasePtr& controller = DControllerTest::getController();
+ ASSERT_TRUE(controller);
+ ASSERT_NO_THROW(boost::dynamic_pointer_cast<DStubController>(controller));
+
+ // Verify that controller's app name is correct.
+ EXPECT_TRUE(checkAppName(DStubController::stub_app_name_));
+
+ // Verify that controller's bin name is correct.
+ EXPECT_TRUE(checkBinName(DStubController::stub_bin_name_));
+
+ // Verify that controller's IOService exists.
+ EXPECT_TRUE(checkIOService());
+
+ // Verify that the Process does NOT exist.
+ EXPECT_FALSE(checkProcess());
+}
+
+/// @brief Tests basic command line processing.
+/// Verifies that:
+/// 1. Standard command line options are supported.
+/// 2. Custom command line options are supported.
+/// 3. Invalid options are detected.
+/// 4. Extraneous command line information is detected.
+TEST_F(DStubControllerTest, commandLineArgs) {
+
+ // Verify that verbose flag is false initially.
+ EXPECT_TRUE(checkVerbose(false));
+
+ // Verify that standard options can be parsed without error.
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-c"),
+ const_cast<char*>("cfgName"),
+ const_cast<char*>("-d") };
+ int argc = 4;
+ EXPECT_NO_THROW(parseArgs(argc, argv));
+
+ // Verify that verbose is true.
+ EXPECT_TRUE(checkVerbose(true));
+
+ // Verify configuration file name is correct
+ EXPECT_TRUE(checkConfigFileName("cfgName"));
+
+ // Verify that the custom command line option is parsed without error.
+ char xopt[3] = "- ";
+ xopt[1] = *DStubController::stub_option_x_;
+ char* argv1[] = { const_cast<char*>("progName"), xopt};
+ argc = 2;
+ EXPECT_NO_THROW (parseArgs(argc, argv1));
+
+ // Verify that an unknown option is detected.
+ char* argv2[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-bs") };
+ argc = 2;
+ EXPECT_THROW (parseArgs(argc, argv2), InvalidUsage);
+
+ // Verify that extraneous information is detected.
+ char* argv3[] = { const_cast<char*>("progName"),
+ const_cast<char*>("extra"),
+ const_cast<char*>("information") };
+ argc = 3;
+ EXPECT_THROW (parseArgs(argc, argv3), InvalidUsage);
+}
+
+/// @brief Tests application process creation and initialization.
+/// Verifies that:
+/// 1. An error during process creation is handled.
+/// 2. A NULL returned by process creation is handled.
+/// 3. An error during process initialization is handled.
+/// 4. Process can be successfully created and initialized.
+TEST_F(DStubControllerTest, initProcessTesting) {
+ // Verify that a failure during process creation is caught.
+ SimFailure::set(SimFailure::ftCreateProcessException);
+ EXPECT_THROW(initProcess(), DControllerBaseError);
+ EXPECT_FALSE(checkProcess());
+
+ // Verify that a NULL returned by process creation is handled.
+ SimFailure::set(SimFailure::ftCreateProcessNull);
+ EXPECT_THROW(initProcess(), DControllerBaseError);
+ EXPECT_FALSE(checkProcess());
+
+ // Re-create controller, verify that we are starting clean
+ resetController();
+ EXPECT_FALSE(checkProcess());
+
+ // Verify that an error during process initialization is handled.
+ SimFailure::set(SimFailure::ftProcessInit);
+ EXPECT_THROW(initProcess(), DProcessBaseError);
+
+ // Re-create controller, verify that we are starting clean
+ resetController();
+ EXPECT_FALSE(checkProcess());
+
+ // Verify that the application process can created and initialized.
+ ASSERT_NO_THROW(initProcess());
+ EXPECT_TRUE(checkProcess());
+}
+
+/// @brief Tests launch handling of invalid command line.
+/// This test launches with an invalid command line which should throw
+/// an InvalidUsage.
+TEST_F(DStubControllerTest, launchInvalidUsage) {
+ // Command line to run integrated
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-z") };
+ int argc = 2;
+
+ // Launch the controller in integrated mode.
+ EXPECT_THROW(launch(argc, argv), InvalidUsage);
+}
+
+/// @brief Tests launch handling of failure in application process
+/// initialization. This test launches with a valid command line but with
+/// SimFailure set to fail during process creation. Launch should throw
+/// ProcessInitError.
+TEST_F(DStubControllerTest, launchProcessInitError) {
+ // Command line to run integrated
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-c"),
+ const_cast<char*>(DControllerTest::CFG_TEST_FILE),
+ const_cast<char*>("-d") };
+ int argc = 4;
+
+ // Launch the controller in stand alone mode.
+ SimFailure::set(SimFailure::ftCreateProcessException);
+ EXPECT_THROW(launch(argc, argv), ProcessInitError);
+}
+
+/// @brief Tests launch and normal shutdown (stand alone mode).
+/// This creates an interval timer to generate a normal shutdown and then
+/// launches with a valid, command line, with a valid configuration file
+/// and no simulated errors.
+TEST_F(DStubControllerTest, launchNormalShutdown) {
+ // Write the valid, empty, config and then run launch() for 1000 ms
+ time_duration elapsed_time;
+ ASSERT_NO_THROW(runWithConfig("{}", 2000, elapsed_time));
+
+ // Verify that duration of the run invocation is the same as the
+ // timer duration. This demonstrates that the shutdown was driven
+ // by an io_service event and callback.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() >= 1900 &&
+ elapsed_time.total_milliseconds() <= 2300);
+}
+
+/// @brief A variant of the launch and normal shutdown test using a callback.
+TEST_F(DStubControllerTest, launchNormalShutdownWithCallback) {
+ // Write the valid, empty, config and then run launch() for 1000 ms
+ // Access to the internal state.
+ auto callback = [&] { EXPECT_FALSE(getProcess()->shouldShutdown()); };
+ time_duration elapsed_time;
+ ASSERT_NO_THROW(runWithConfig("{}", 2000,
+ static_cast<const TestCallback&>(callback),
+ elapsed_time));
+
+ // Verify that duration of the run invocation is the same as the
+ // timer duration. This demonstrates that the shutdown was driven
+ // by an io_service event and callback.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() >= 1900 &&
+ elapsed_time.total_milliseconds() <= 2300);
+}
+
+/// @brief Tests launch with an non-existing configuration file.
+TEST_F(DStubControllerTest, nonExistingConfigFile) {
+ // command line to run standalone
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-c"),
+ const_cast<char*>("bogus-file"),
+ const_cast<char*>("-d") };
+ int argc = 4;
+
+ // Record start time, and invoke launch().
+ EXPECT_THROW(launch(argc, argv), ProcessInitError);
+}
+
+/// @brief Tests launch with configuration file argument but no file name
+TEST_F(DStubControllerTest, missingConfigFileName) {
+ // command line to run standalone
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-c"),
+ const_cast<char*>("-d") };
+ int argc = 3;
+
+ // Record start time, and invoke launch().
+ EXPECT_THROW(launch(argc, argv), ProcessInitError);
+}
+
+/// @brief Tests launch with no configuration file argument
+TEST_F(DStubControllerTest, missingConfigFileArgument) {
+ // command line to run standalone
+ char* argv[] = { const_cast<char*>("progName"),
+ const_cast<char*>("-d") };
+ int argc = 2;
+
+ // Record start time, and invoke launch().
+ EXPECT_THROW(launch(argc, argv), LaunchError);
+}
+
+/// @brief Tests launch with an operational error during application execution.
+/// This test creates an interval timer to generate a runtime exception during
+/// the process event loop. It launches with a valid, stand-alone command line
+/// and no simulated errors. Launch should throw ProcessRunError.
+TEST_F(DStubControllerTest, launchRuntimeError) {
+ // Use an asiolink IntervalTimer and callback to generate the
+ // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
+ isc::asiolink::IntervalTimer timer(*getIOService());
+ timer.setup(genFatalErrorCallback, 2000);
+
+ // Write the valid, empty, config and then run launch() for 5000 ms
+ time_duration elapsed_time;
+ EXPECT_THROW(runWithConfig("{}", 5000, elapsed_time), ProcessRunError);
+
+ // Verify that duration of the run invocation is the same as the
+ // timer duration. This demonstrates that the shutdown was driven
+ // by an io_service event and callback.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() >= 1900 &&
+ elapsed_time.total_milliseconds() <= 2300);
+}
+
+/// @brief Configuration update event testing.
+/// This really tests just the ability of the handlers to invoke the necessary
+/// chain of methods and handle error conditions. Configuration parsing and
+/// retrieval should be tested as part of the d2 configuration management
+/// implementation.
+/// This test verifies that:
+/// 1. That a valid configuration update results in successful status return.
+/// 2. That an application process error in configuration updating is handled
+/// properly.
+TEST_F(DStubControllerTest, configUpdateTests) {
+ int rcode = -1;
+ isc::data::ConstElementPtr answer;
+
+ // Initialize the application process.
+ ASSERT_NO_THROW(initProcess());
+ EXPECT_TRUE(checkProcess());
+
+ // Create a configuration set. Content is arbitrary, just needs to be
+ // valid JSON.
+ std::string config = "{ \"test-value\": 1000 } ";
+ isc::data::ElementPtr config_set = isc::data::Element::fromJSON(config);
+
+ // Verify that a valid config gets a successful update result.
+ answer = updateConfig(config_set);
+ isc::config::parseAnswer(rcode, answer);
+ EXPECT_EQ(0, rcode);
+
+ // Verify that a valid config gets a successful check result.
+ answer = checkConfig(config_set);
+ isc::config::parseAnswer(rcode, answer);
+ EXPECT_EQ(0, rcode);
+
+ // Verify that an error in process configure method is handled.
+ SimFailure::set(SimFailure::ftProcessConfigure);
+ answer = updateConfig(config_set);
+ isc::config::parseAnswer(rcode, answer);
+ EXPECT_EQ(1, rcode);
+
+ // Verify that an error is handled too when the config is checked for.
+ SimFailure::set(SimFailure::ftProcessConfigure);
+ answer = checkConfig(config_set);
+ isc::config::parseAnswer(rcode, answer);
+ EXPECT_EQ(1, rcode);
+}
+
+// Tests that handleOtherObjects behaves as expected.
+TEST_F(DStubControllerTest, handleOtherObjects) {
+ using namespace isc::data;
+
+ // A bad config.
+ ElementPtr config = Element::createMap();
+ config->set(controller_->getAppName(), Element::create(1));
+ config->set("foo", Element::create(2));
+ config->set("bar", Element::create(3));
+
+ // Check the error message.
+ std::string errmsg;
+ EXPECT_NO_THROW(errmsg = controller_->handleOtherObjects(config));
+ EXPECT_EQ(" contains unsupported 'bar' parameter (and 'foo')", errmsg);
+
+ // Retry with no error.
+ config = Element::createMap();
+ config->set(controller_->getAppName(), Element::create(1));
+ EXPECT_NO_THROW(errmsg = controller_->handleOtherObjects(config));
+ EXPECT_TRUE(errmsg.empty());
+}
+
+// Tests that registered signals are caught and handled.
+TEST_F(DStubControllerTest, ioSignals) {
+ // Tell test controller just to record the signals, don't call the
+ // base class signal handler.
+ controller_->recordSignalOnly(true);
+
+ // Setup to raise SIGHUP in 10 ms.
+ TimedSignal sighup(*getIOService(), SIGHUP, 10);
+ TimedSignal sigint(*getIOService(), SIGINT, 100);
+ TimedSignal sigterm(*getIOService(), SIGTERM, 200);
+
+ // Write the valid, empty, config and then run launch() for 500 ms
+ time_duration elapsed_time;
+ runWithConfig("{}", 500, elapsed_time);
+
+ // Verify that we caught the signals as expected.
+ std::vector<int>& signals = controller_->getProcessedSignals();
+ ASSERT_EQ(3, signals.size());
+ EXPECT_EQ(SIGHUP, signals[0]);
+ EXPECT_EQ(SIGINT, signals[1]);
+ EXPECT_EQ(SIGTERM, signals[2]);
+}
+
+// Tests that the original configuration is retained after a SIGHUP triggered
+// reconfiguration fails due to invalid config content.
+TEST_F(DStubControllerTest, invalidConfigReload) {
+ // Schedule to rewrite the configuration file after launch. This way the
+ // file is updated after we have done the initial configuration. The
+ // new content is invalid JSON which will cause the config parse to fail.
+ scheduleTimedWrite("{ \"string_test\": BOGUS JSON }", 100);
+
+ // Setup to raise SIGHUP in 200 ms.
+ TimedSignal sighup(*getIOService(), SIGHUP, 200);
+
+ // Write the config and then run launch() for 500 ms
+ // After startup, which will load the initial configuration this enters
+ // the process's runIO() loop. We will first rewrite the config file.
+ // Next we process the SIGHUP signal which should cause us to reconfigure.
+ time_duration elapsed_time;
+ runWithConfig("{ \"string_test\": \"first value\" }", 500, elapsed_time);
+
+ // Verify that we saw the signal.
+ std::vector<int>& signals = controller_->getProcessedSignals();
+ ASSERT_EQ(1, signals.size());
+ EXPECT_EQ(SIGHUP, signals[0]);
+}
+
+// Tests that the original configuration is retained after a SIGHUP triggered
+// reconfiguration fails due to invalid config content.
+TEST_F(DStubControllerTest, alternateParsing) {
+ controller_->useAlternateParser(true);
+
+ // Setup to raise SIGHUP in 200 ms.
+ TimedSignal sighup(*getIOService(), SIGHUP, 200);
+
+ // Write the config and then run launch() for 500 ms
+ // After startup, which will load the initial configuration this enters
+ // the process's runIO() loop. We will first rewrite the config file.
+ // Next we process the SIGHUP signal which should cause us to reconfigure.
+ time_duration elapsed_time;
+ runWithConfig("{ \"string_test\": \"first value\" }", 500, elapsed_time);
+
+ // Verify that we saw the signal.
+ std::vector<int>& signals = controller_->getProcessedSignals();
+ ASSERT_EQ(1, signals.size());
+ EXPECT_EQ(SIGHUP, signals[0]);
+}
+
+// Tests that the original configuration is replaced after a SIGHUP triggered
+// reconfiguration succeeds.
+TEST_F(DStubControllerTest, validConfigReload) {
+ // Schedule to rewrite the configuration file after launch. This way the
+ // file is updated after we have done the initial configuration.
+ scheduleTimedWrite("{ \"string_test\": \"second value\" }", 100);
+
+ // Setup to raise SIGHUP in 200 ms and another at 400 ms.
+ TimedSignal sighup(*getIOService(), SIGHUP, 200);
+ TimedSignal sighup2(*getIOService(), SIGHUP, 400);
+
+ // Write the config and then run launch() for 800 ms
+ time_duration elapsed_time;
+ runWithConfig("{ \"string_test\": \"first value\" }", 800, elapsed_time);
+
+ // Verify that we saw two occurrences of the signal.
+ std::vector<int>& signals = controller_->getProcessedSignals();
+ ASSERT_EQ(2, signals.size());
+ EXPECT_EQ(SIGHUP, signals[0]);
+ EXPECT_EQ(SIGHUP, signals[1]);
+}
+
+// Tests that the SIGINT triggers a normal shutdown.
+TEST_F(DStubControllerTest, sigintShutdown) {
+ // Setup to raise SIGHUP in 1 ms.
+ TimedSignal sighup(*getIOService(), SIGINT, 1);
+
+ // Write the config and then run launch() for 1000 ms
+ time_duration elapsed_time;
+ runWithConfig("{ \"string_test\": \"first value\" }", 1000, elapsed_time);
+
+ // Verify that we saw the signal.
+ std::vector<int>& signals = controller_->getProcessedSignals();
+ ASSERT_EQ(1, signals.size());
+ EXPECT_EQ(SIGINT, signals[0]);
+
+ // Duration should be significantly less than our max run time.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
+}
+
+// Verifies that version and extended version information is correct
+TEST_F(DStubControllerTest, getVersion) {
+ std::string text = controller_->getVersion(false);
+ EXPECT_EQ(text,VERSION);
+
+ text = controller_->getVersion(true);
+ EXPECT_NE(std::string::npos, text.find(VERSION));
+ EXPECT_NE(std::string::npos, text.find(EXTENDED_VERSION));
+ EXPECT_NE(std::string::npos, text.find(controller_->getVersionAddendum()));
+}
+
+// Tests that the SIGTERM triggers a normal shutdown.
+TEST_F(DStubControllerTest, sigtermShutdown) {
+ // Setup to raise SIGHUP in 1 ms.
+ TimedSignal sighup(*getIOService(), SIGTERM, 1);
+
+ // Write the config and then run launch() for 1000 ms
+ time_duration elapsed_time;
+ runWithConfig("{ \"string_test\": \"first value\" }", 1000, elapsed_time);
+
+ // Verify that we saw the signal.
+ std::vector<int>& signals = controller_->getProcessedSignals();
+ ASSERT_EQ(1, signals.size());
+ EXPECT_EQ(SIGTERM, signals[0]);
+
+ // Duration should be significantly less than our max run time.
+ EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
+}
+
+}; // end of isc::process namespace
+}; // end of isc namespace
diff --git a/src/lib/process/tests/daemon_unittest.cc b/src/lib/process/tests/daemon_unittest.cc
new file mode 100644
index 0000000..bd80e25
--- /dev/null
+++ b/src/lib/process/tests/daemon_unittest.cc
@@ -0,0 +1,324 @@
+// Copyright (C) 2014-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 <exceptions/exceptions.h>
+#include <cc/data.h>
+#include <process/daemon.h>
+#include <process/config_base.h>
+#include <process/log_parser.h>
+#include <log/logger_support.h>
+
+#include <gtest/gtest.h>
+
+#include <sys/wait.h>
+
+using namespace isc;
+using namespace isc::process;
+using namespace isc::data;
+
+namespace isc {
+namespace process {
+
+// @brief Derived Daemon class
+class DaemonImpl : public Daemon {
+public:
+ static std::string getVersion(bool extended);
+
+ using Daemon::makePIDFileName;
+};
+
+std::string DaemonImpl::getVersion(bool extended) {
+ if (extended) {
+ return (std::string("EXTENDED"));
+ } else {
+ return (std::string("BASIC"));
+ }
+}
+
+};
+};
+
+namespace {
+
+/// @brief Daemon Test test fixture class
+class DaemonTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ DaemonTest() : env_copy_() {
+ // Take a copy of KEA_PIDFILE_DIR environment variable value
+ char *env_value = getenv("KEA_PIDFILE_DIR");
+ if (env_value) {
+ env_copy_ = std::string(env_value);
+ }
+ }
+
+ /// @brief Destructor
+ ///
+ /// As some of the tests have the side-effect of altering the logging
+ /// settings (when configureLogger is called), the logging is reset to
+ /// the default after each test completes.
+ ~DaemonTest() {
+ isc::log::setDefaultLoggingOutput();
+ // Restore KEA_PIDFILE_DIR environment variable value
+ if (env_copy_.empty()) {
+ static_cast<void>(unsetenv("KEA_PIDFILE_DIR"));
+ } else {
+ static_cast<void>(setenv("KEA_PIDFILE_DIR", env_copy_.c_str(), 1));
+ }
+ }
+
+private:
+ /// @brief copy of KEA_PIDFILE_DIR environment variable value
+ std::string env_copy_;
+};
+
+
+// Very simple test. Checks whether Daemon can be instantiated and its
+// default parameters are sane
+TEST_F(DaemonTest, constructor) {
+ // Disable KEA_PIDFILE_DIR
+ EXPECT_EQ(0, unsetenv("KEA_PIDFILE_DIR"));
+
+ EXPECT_NO_THROW(Daemon instance1);
+
+ // Check only instance values.
+ Daemon instance2;
+ EXPECT_TRUE(instance2.getConfigFile().empty());
+ EXPECT_EQ(std::string(DATA_DIR), instance2.getPIDFileDir());
+ EXPECT_TRUE(instance2.getPIDFileName().empty());
+}
+
+// Verify config file accessors
+TEST_F(DaemonTest, getSetConfigFile) {
+ Daemon instance;
+
+ EXPECT_NO_THROW(instance.setConfigFile("test.txt"));
+ EXPECT_EQ("test.txt", instance.getConfigFile());
+ EXPECT_NO_THROW(instance.checkConfigFile());
+}
+
+// Verify config file checker.
+TEST_F(DaemonTest, checkConfigFile) {
+ Daemon instance;
+
+ EXPECT_THROW(instance.checkConfigFile(), BadValue);
+ EXPECT_NO_THROW(instance.setConfigFile("/tmp/"));
+ EXPECT_THROW(instance.checkConfigFile(), BadValue);
+ EXPECT_NO_THROW(instance.setConfigFile("/tmp/test.txt"));
+ EXPECT_NO_THROW(instance.checkConfigFile());
+}
+
+// Verify process name accessors
+TEST_F(DaemonTest, getSetProcName) {
+ Daemon instance;
+
+ EXPECT_NO_THROW(instance.setProcName("myproc"));
+ EXPECT_EQ("myproc", instance.getProcName());
+}
+
+// Verify PID file directory name accessors
+TEST_F(DaemonTest, getSetPIDFileDir) {
+ Daemon instance;
+
+ EXPECT_NO_THROW(instance.setPIDFileDir("/tmp"));
+ EXPECT_EQ("/tmp", instance.getPIDFileDir());
+}
+
+// Verify PID file name accessors.
+TEST_F(DaemonTest, setPIDFileName) {
+ Daemon instance;
+
+ // Verify that PID file name may not be set to empty
+ EXPECT_THROW(instance.setPIDFileName(""), BadValue);
+
+ EXPECT_NO_THROW(instance.setPIDFileName("myproc"));
+ EXPECT_EQ("myproc", instance.getPIDFileName());
+
+ // Verify that setPIDFileName cannot be called twice on the same instance.
+ EXPECT_THROW(instance.setPIDFileName("again"), InvalidOperation);
+}
+
+// Test the getVersion() redefinition
+TEST_F(DaemonTest, getVersion) {
+ EXPECT_THROW(Daemon::getVersion(false), NotImplemented);
+
+ ASSERT_NO_THROW(DaemonImpl::getVersion(false));
+
+ EXPECT_EQ(DaemonImpl::getVersion(false), "BASIC");
+
+ ASSERT_NO_THROW(DaemonImpl::getVersion(true));
+
+ EXPECT_EQ(DaemonImpl::getVersion(true), "EXTENDED");
+}
+
+// Verify makePIDFileName method
+TEST_F(DaemonTest, makePIDFileName) {
+ DaemonImpl instance;
+
+ // Verify that config file cannot be blank
+ instance.setProcName("notblank");
+ EXPECT_THROW(instance.makePIDFileName(), InvalidOperation);
+
+ // Verify that proc name cannot be blank
+ instance.setProcName("");
+ instance.setConfigFile("notblank");
+ EXPECT_THROW(instance.makePIDFileName(), InvalidOperation);
+
+ // Verify that config file must contain a file name
+ instance.setProcName("myproc");
+ instance.setConfigFile(".txt");
+ EXPECT_THROW(instance.makePIDFileName(), BadValue);
+ instance.setConfigFile("/tmp/");
+ EXPECT_THROW(instance.makePIDFileName(), BadValue);
+
+ // Given a valid config file name and proc name we should good to go
+ instance.setConfigFile("/tmp/test.conf");
+ std::string name;
+ EXPECT_NO_THROW(name = instance.makePIDFileName());
+
+ // Make sure the name is as we expect
+ std::ostringstream stream;
+ stream << instance.getPIDFileDir() << "/test.myproc.pid";
+ EXPECT_EQ(stream.str(), name);
+
+ // Verify that the default directory can be overridden
+ instance.setPIDFileDir("/tmp");
+ EXPECT_NO_THROW(name = instance.makePIDFileName());
+ EXPECT_EQ("/tmp/test.myproc.pid", name);
+}
+
+// Verifies the creation a PID file and that a pre-existing PID file
+// which points to a live PID causes a throw.
+TEST_F(DaemonTest, createPIDFile) {
+ DaemonImpl instance;
+
+ instance.setConfigFile("test.conf");
+ instance.setProcName("daemon_test");
+ instance.setPIDFileDir(TEST_DATA_BUILDDIR);
+
+ EXPECT_NO_THROW(instance.createPIDFile());
+
+ std::ostringstream stream;
+ stream << TEST_DATA_BUILDDIR << "/test.daemon_test.pid";
+ EXPECT_EQ(stream.str(), instance.getPIDFileName());
+
+ // If we try again, we should see our own PID file and fail
+ EXPECT_THROW(instance.createPIDFile(), DaemonPIDExists);
+}
+
+// Verifies that a pre-existing PID file which points to a dead PID
+// is overwritten.
+TEST_F(DaemonTest, createPIDFileOverwrite) {
+ DaemonImpl instance;
+
+ // We're going to use fork to generate a PID we KNOW is dead.
+ int pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ // This is the child, die right away. Tragic, no?
+ _exit (0);
+ }
+
+ // Back in the parent test, we need to wait for the child to die
+ // As with debugging waitpid() can be interrupted ignore EINTR.
+ int stat;
+ int ret;
+ do {
+ ret = waitpid(pid, &stat, 0);
+ } while ((ret == -1) && (errno == EINTR));
+ ASSERT_EQ(ret, pid);
+
+ // Ok, so we should now have a PID that we know to be dead.
+ // Let's use it to create a PID file.
+ instance.setConfigFile("test.conf");
+ instance.setProcName("daemon_test");
+ instance.setPIDFileDir(TEST_DATA_BUILDDIR);
+ EXPECT_NO_THROW(instance.createPIDFile(pid));
+
+ // If we try to create the PID file again, this should work.
+ EXPECT_NO_THROW(instance.createPIDFile());
+}
+
+// Verifies that Daemon destruction deletes the PID file
+TEST_F(DaemonTest, PIDFileCleanup) {
+ boost::shared_ptr<DaemonImpl> instance;
+ instance.reset(new DaemonImpl);
+
+ instance->setConfigFile("test.conf");
+ instance->setProcName("daemon_test");
+ instance->setPIDFileDir(TEST_DATA_BUILDDIR);
+ EXPECT_NO_THROW(instance->createPIDFile());
+
+ // If we try again, we should see our own PID file
+ EXPECT_THROW(instance->createPIDFile(), DaemonPIDExists);
+
+ // Save the pid file name
+ std::string pid_file_name = instance->getPIDFileName();
+
+ // Now delete the Daemon instance. This should remove the
+ // PID file.
+ instance.reset();
+
+ struct stat stat_buf;
+ ASSERT_EQ(-1, stat(pid_file_name.c_str(), &stat_buf));
+ EXPECT_EQ(errno, ENOENT);
+}
+
+// Checks that configureLogger method is behaving properly.
+// More dedicated tests are available for LogConfigParser class.
+// See logger_unittest.cc
+TEST_F(DaemonTest, parsingConsoleOutput) {
+ Daemon::setVerbose(false);
+
+ // Storage - parsed configuration will be stored here
+ ConfigPtr storage(new ConfigBase());
+
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"stdout\""
+ " }"
+ " ],"
+ " \"debuglevel\": 99,"
+ " \"severity\": \"DEBUG\""
+ " }"
+ "]}";
+ ConstElementPtr config = Element::fromJSON(config_txt);
+
+ // Spawn a daemon and tell it to configure logger
+ Daemon x;
+ EXPECT_NO_THROW(x.configureLogger(config, storage));
+
+ // The parsed configuration should be processed by the daemon and
+ // stored in configuration storage.
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(99, storage->getLoggingInfo()[0].debuglevel_);
+ EXPECT_EQ(isc::log::DEBUG, storage->getLoggingInfo()[0].severity_);
+
+ ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[0].output_);
+}
+
+TEST_F(DaemonTest, exitValue) {
+ DaemonImpl instance;
+
+ EXPECT_EQ(EXIT_SUCCESS, instance.getExitValue());
+ instance.setExitValue(77);
+ EXPECT_EQ(77, instance.getExitValue());
+}
+
+
+// More tests will appear here as we develop Daemon class.
+
+};
diff --git a/src/lib/process/tests/log_parser_unittests.cc b/src/lib/process/tests/log_parser_unittests.cc
new file mode 100644
index 0000000..0341dd7
--- /dev/null
+++ b/src/lib/process/tests/log_parser_unittests.cc
@@ -0,0 +1,530 @@
+// Copyright (C) 2014-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 <cc/data.h>
+#include <process/log_parser.h>
+#include <process/process_messages.h>
+#include <exceptions/exceptions.h>
+#include <log/logger_support.h>
+#include <process/d_log.h>
+#include <testutils/gtest_utils.h>
+#include <testutils/io_utils.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::process;
+using namespace isc::data;
+
+namespace {
+
+/// @brief Logging Test Fixture Class
+///
+/// Trivial class that ensures that the logging is reset to its defaults after
+/// each test. Strictly speaking this only resets the testing root logger (which
+/// has the name "kea") but as the only other logger mentioned here ("wombat")
+/// is not used elsewhere, that is sufficient.
+class LoggingTest : public ::testing::Test {
+ public:
+ /// @brief Constructor
+ LoggingTest() {}
+
+ /// @brief Destructor
+ ///
+ /// Reset root logger back to defaults.
+ ~LoggingTest() {
+ isc::log::initLogger();
+ wipeFiles();
+ }
+
+ /// @brief Generates a log file name suffixed with a rotation number
+ /// @param rotation number to the append to the end of the file
+ std::string logName(int rotation) {
+ std::ostringstream os;
+ os << TEST_LOG_NAME << "." << rotation;
+ return (os.str());
+ }
+
+ /// @brief Removes the base log file name and 1 rotation
+ void wipeFiles() {
+ static_cast<void>(remove(TEST_LOG_NAME));
+ for (int i = 1; i < TEST_MAX_VERS + 1; ++i) {
+ static_cast<void>(remove(logName(i).c_str()));
+ }
+
+ // Remove the lock file
+ std::ostringstream os;
+ os << TEST_LOG_NAME << ".lock";
+ static_cast<void>(remove(os.str().c_str()));
+ }
+
+ /// @brief Name of the log file
+ static const char* TEST_LOG_NAME;
+
+ /// @brief Maximum log size
+ static const int TEST_MAX_SIZE;
+
+ /// @brief Maximum rotated log versions
+ static const int TEST_MAX_VERS;
+
+};
+
+const char* LoggingTest::TEST_LOG_NAME = "kea.test.log";
+const int LoggingTest::TEST_MAX_SIZE = 204800; // Smallest without disabling rotation
+const int LoggingTest::TEST_MAX_VERS = 2; // More than the default of 1
+
+// Checks that the constructor is able to process specified storage properly.
+TEST_F(LoggingTest, constructor) {
+
+ ConfigPtr null_ptr;
+ EXPECT_THROW(LogConfigParser parser(null_ptr), BadValue);
+
+ ConfigPtr nonnull(new ConfigBase());
+
+ EXPECT_NO_THROW(LogConfigParser parser(nonnull));
+}
+
+// Checks if the LogConfigParser class is able to transform JSON structures
+// into Configuration usable by log4cplus. This test checks for output
+// configured to stdout on debug level.
+TEST_F(LoggingTest, parsingConsoleOutput) {
+
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"stdout\","
+ " \"flush\": true"
+ " }"
+ " ],"
+ " \"debuglevel\": 99,"
+ " \"severity\": \"DEBUG\""
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ EXPECT_NO_THROW(parser.parseConfiguration(config));
+
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(99, storage->getLoggingInfo()[0].debuglevel_);
+ EXPECT_EQ(isc::log::DEBUG, storage->getLoggingInfo()[0].severity_);
+
+ ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[0].output_);
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
+}
+
+// Check that LogConfigParser can parse configuration that
+// lacks a severity entry.
+TEST_F(LoggingTest, parsingNoSeverity) {
+
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"stdout\","
+ " \"flush\": true"
+ " }"
+ " ],"
+ " \"debuglevel\": 99"
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ // No exception should be thrown.
+ EXPECT_NO_THROW_LOG(parser.parseConfiguration(config));
+
+ // Entries should be the ones set.
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+ LoggingInfo const& logging_info(storage->getLoggingInfo()[0]);
+ EXPECT_EQ("kea", logging_info.name_);
+ EXPECT_EQ(99, logging_info.debuglevel_);
+ ASSERT_EQ(1, logging_info.destinations_.size());
+ EXPECT_EQ("stdout" , logging_info.destinations_[0].output_);
+ EXPECT_TRUE(logging_info.destinations_[0].flush_);
+
+ // Severity should default to DEFAULT.
+ EXPECT_EQ(isc::log::DEFAULT, logging_info.severity_);
+
+ // Pattern should default to empty string.
+ EXPECT_TRUE(logging_info.destinations_[0].pattern_.empty());
+}
+
+// Checks if the LogConfigParser class is able to transform JSON structures
+// into Configuration usable by log4cplus. This test checks for output
+// configured to a file on INFO level.
+TEST_F(LoggingTest, parsingFile) {
+
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"logfile.txt\""
+ " }"
+ " ],"
+ " \"severity\": \"INFO\""
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ EXPECT_NO_THROW(parser.parseConfiguration(config));
+
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(0, storage->getLoggingInfo()[0].debuglevel_);
+ EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
+
+ ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("logfile.txt" , storage->getLoggingInfo()[0].destinations_[0].output_);
+ // Default for immediate flush is true
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
+
+ // Pattern should default to empty string.
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].pattern_.empty());
+}
+
+// Checks if the LogConfigParser class is able to transform data structures
+// into Configuration usable by log4cplus. This test checks that more than
+// one logger can be configured.
+TEST_F(LoggingTest, multipleLoggers) {
+
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"logfile.txt\","
+ " \"flush\": true"
+ " }"
+ " ],"
+ " \"severity\": \"INFO\""
+ " },"
+ " {"
+ " \"name\": \"wombat\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"logfile2.txt\","
+ " \"flush\": false"
+ " }"
+ " ],"
+ " \"severity\": \"DEBUG\","
+ " \"debuglevel\": 99"
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ EXPECT_NO_THROW(parser.parseConfiguration(config));
+
+ ASSERT_EQ(2, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(0, storage->getLoggingInfo()[0].debuglevel_);
+ EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
+ ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("logfile.txt" , storage->getLoggingInfo()[0].destinations_[0].output_);
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
+
+ EXPECT_EQ("wombat", storage->getLoggingInfo()[1].name_);
+ EXPECT_EQ(99, storage->getLoggingInfo()[1].debuglevel_);
+ EXPECT_EQ(isc::log::DEBUG, storage->getLoggingInfo()[1].severity_);
+ ASSERT_EQ(1, storage->getLoggingInfo()[1].destinations_.size());
+ EXPECT_EQ("logfile2.txt" , storage->getLoggingInfo()[1].destinations_[0].output_);
+ EXPECT_FALSE(storage->getLoggingInfo()[1].destinations_[0].flush_);
+}
+
+// Checks if the LogConfigParser class is able to transform data structures
+// into Configuration usable by log4cplus. This test checks that more than
+// one logging destination can be configured.
+TEST_F(LoggingTest, multipleLoggingDestinations) {
+
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"logfile.txt\""
+ " },"
+ " {"
+ " \"output\": \"stdout\""
+ " }"
+ " ],"
+ " \"severity\": \"INFO\""
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ EXPECT_NO_THROW(parser.parseConfiguration(config));
+
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(0, storage->getLoggingInfo()[0].debuglevel_);
+ EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
+ ASSERT_EQ(2, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("logfile.txt" , storage->getLoggingInfo()[0].destinations_[0].output_);
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].flush_);
+ EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[1].output_);
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[1].flush_);
+}
+
+// Verifies that log rotation occurs when configured. We do not
+// worry about contents of the log files, only that rotation occurs.
+// Such details are tested in lib/log. This test verifies that
+// we can correctly configure logging such that rotation occurs as
+// expected.
+TEST_F(LoggingTest, logRotate) {
+ wipeFiles();
+
+ std::ostringstream os;
+ os <<
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \""
+ << TEST_LOG_NAME << "\"," <<
+ " \"flush\": true,"
+ " \"maxsize\":"
+ << TEST_MAX_SIZE << "," <<
+ " \"maxver\":"
+ << TEST_MAX_VERS <<
+ " }"
+ " ],"
+ " \"debuglevel\": 99,"
+ " \"severity\": \"DEBUG\""
+ " }"
+ "]}";
+
+ // Create our server config container.
+ ConfigPtr server_cfg(new ConfigBase());
+
+ // LogConfigParser expects a list of loggers, so parse
+ // the JSON text and extract the "loggers" element from it
+ ConstElementPtr config = Element::fromJSON(os.str());
+ config = config->get("loggers");
+
+ // Parse the config and then apply it.
+ LogConfigParser parser(server_cfg);
+ ASSERT_NO_THROW(parser.parseConfiguration(config));
+ ASSERT_NO_THROW(server_cfg->applyLoggingCfg());
+
+ EXPECT_EQ(TEST_MAX_SIZE, server_cfg->getLoggingInfo()[0].destinations_[0].maxsize_);
+ EXPECT_EQ(TEST_MAX_VERS, server_cfg->getLoggingInfo()[0].destinations_[0].maxver_);
+
+ // Make sure we have the initial log file.
+ ASSERT_TRUE(isc::test::fileExists(TEST_LOG_NAME));
+
+ // Now generate a log we know will be large enough to force a rotation.
+ // We borrow a one argument log message for the test.
+ std::string big_arg(TEST_MAX_SIZE, 'x');
+ isc::log::Logger logger("kea");
+
+ for (int i = 1; i < TEST_MAX_VERS + 1; i++) {
+ // Output the big log and make sure we get the expected rotation file.
+ LOG_INFO(logger, DCTL_CONFIG_COMPLETE).arg(big_arg);
+ EXPECT_TRUE(isc::test::fileExists(logName(i).c_str()));
+ }
+
+ // Clean up.
+ wipeFiles();
+}
+
+// Verifies that a valid output option,'pattern' parses correctly.
+TEST_F(LoggingTest, validPattern) {
+
+ // Note the backslash must be doubled in the pattern definition.
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"stdout\","
+ " \"pattern\": \"mylog %m\\n\""
+ " }"
+ " ],"
+ " \"severity\": \"INFO\""
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ EXPECT_NO_THROW(parser.parseConfiguration(config));
+
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
+
+ ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[0].output_);
+ EXPECT_EQ(storage->getLoggingInfo()[0].destinations_[0].pattern_,
+ std::string("mylog %m\n"));
+}
+
+// Verifies that output option,'pattern', may be an empty string
+TEST_F(LoggingTest, emptyPattern) {
+ const char* config_txt =
+ "{ \"loggers\": ["
+ " {"
+ " \"name\": \"kea\","
+ " \"output_options\": ["
+ " {"
+ " \"output\": \"stdout\","
+ " \"pattern\": \"\""
+ " }"
+ " ],"
+ " \"severity\": \"INFO\""
+ " }"
+ "]}";
+
+ ConfigPtr storage(new ConfigBase());
+
+ LogConfigParser parser(storage);
+
+ // We need to parse properly formed JSON and then extract
+ // "loggers" element from it. For some reason fromJSON is
+ // throwing at opening square bracket
+ ConstElementPtr config = Element::fromJSON(config_txt);
+ config = config->get("loggers");
+
+ EXPECT_NO_THROW(parser.parseConfiguration(config));
+
+ ASSERT_EQ(1, storage->getLoggingInfo().size());
+
+ EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
+ EXPECT_EQ(isc::log::INFO, storage->getLoggingInfo()[0].severity_);
+
+ ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
+ EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[0].output_);
+ EXPECT_TRUE(storage->getLoggingInfo()[0].destinations_[0].pattern_.empty());
+}
+
+void testMaxSize(uint64_t maxsize_candidate, uint64_t expected_maxsize) {
+ std::string const logger(R"(
+ {
+ "loggers": [
+ {
+
+ "debuglevel": 99,
+ "name": "kea",
+ "output_options": [
+ {
+ "output": "kea.test.log",
+ "flush": true,
+ "maxsize": )" + std::to_string(maxsize_candidate) + R"(,
+ "maxver": 2
+ }
+ ],
+ "severity": "DEBUG"
+ }
+ ]
+ }
+ )");
+
+ // Create our server config container.
+ ConfigPtr server_cfg(boost::make_shared<ConfigBase>());
+
+ // LogConfigParser expects a list of loggers, so parse
+ // the JSON text and extract the "loggers" element from it
+ ConstElementPtr config(Element::fromJSON(logger));
+ config = config->get("loggers");
+
+ // Parse the config and then apply it.
+ LogConfigParser parser(server_cfg);
+ ASSERT_NO_THROW(parser.parseConfiguration(config));
+ ASSERT_NO_THROW(server_cfg->applyLoggingCfg());
+
+ EXPECT_EQ(server_cfg->getLoggingInfo()[0].destinations_[0].maxsize_,
+ expected_maxsize);
+}
+
+// Test that maxsize can be configured with high values.
+TEST_F(LoggingTest, maxsize) {
+ testMaxSize(TEST_MAX_SIZE, TEST_MAX_SIZE);
+ testMaxSize(std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
+ testMaxSize(std::numeric_limits<uint32_t>::max(), std::numeric_limits<uint32_t>::max());
+ testMaxSize(1000LL * std::numeric_limits<int32_t>::max(), 1000LL * std::numeric_limits<int32_t>::max());
+ testMaxSize(1000000LL * std::numeric_limits<int32_t>::max(), 1000000LL * std::numeric_limits<int32_t>::max());
+}
+
+/// @todo Add tests for malformed logging configuration
+
+/// @todo There is no easy way to test applyConfiguration() and defaultLogging().
+/// To test them, it would require instrumenting log4cplus to actually fake
+/// the logging set up. Alternatively, we could develop set of test suites
+/// that check each logging destination separately (e.g. configure log file, then
+/// check if the file is indeed created or configure stdout destination, then
+/// swap console file descriptors and check that messages are really logged.
+
+} // namespace
diff --git a/src/lib/process/tests/logging_info_unittests.cc b/src/lib/process/tests/logging_info_unittests.cc
new file mode 100644
index 0000000..388a8a5
--- /dev/null
+++ b/src/lib/process/tests/logging_info_unittests.cc
@@ -0,0 +1,208 @@
+// Copyright (C) 2014-2022 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 <process/daemon.h>
+#include <process/logging_info.h>
+#include <testutils/test_to_element.h>
+#include <gtest/gtest.h>
+
+using namespace isc::process;
+using namespace isc::test;
+using namespace isc::data;
+
+namespace {
+
+// Checks if two destinations can be compared for equality.
+TEST(LoggingDestination, equals) {
+ LoggingDestination dest1;
+ LoggingDestination dest2;
+
+ EXPECT_TRUE(dest1.equals(dest2));
+
+ dest1.output_ = "stderr";
+ EXPECT_FALSE(dest1.equals(dest2));
+
+ dest2.output_ = "stdout";
+ EXPECT_FALSE(dest1.equals(dest2));
+
+ dest2.output_ = "stderr";
+ EXPECT_TRUE(dest1.equals(dest2));
+
+ dest1.maxver_ = 10;
+ dest2.maxver_ = 5;
+ EXPECT_FALSE(dest1.equals(dest2));
+
+ dest2.maxver_ = 10;
+ EXPECT_TRUE(dest1.equals(dest2));
+
+ dest1.maxsize_ = 64;
+ dest2.maxsize_ = 32;
+ EXPECT_FALSE(dest1.equals(dest2));
+
+ dest1.maxsize_ = 32;
+ EXPECT_TRUE(dest1.equals(dest2));
+}
+
+/// @brief Test fixture class for testing @c LoggingInfo.
+class LoggingInfoTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor
+ LoggingInfoTest() = default;
+
+ /// @brief Destructor
+ virtual ~LoggingInfoTest() = default;
+
+ /// @brief Setup the test.
+ virtual void SetUp() {
+ Daemon::setVerbose(false);
+ }
+
+ /// @brief Clear after the test.
+ virtual void TearDown() {
+ Daemon::setVerbose(false);
+ }
+};
+
+// Checks if default logging configuration is correct.
+TEST_F(LoggingInfoTest, defaults) {
+
+ // We now need to set the default logger explicitly.
+ // Otherwise leftovers from previous tests that use DController
+ // would leave the default logger set to TestBin.
+ Daemon::setDefaultLoggerName("kea");
+
+ LoggingInfo info_non_verbose;
+
+ // The DStubTest framework sets up the default binary name to TestBin
+ EXPECT_EQ("kea", info_non_verbose.name_);
+ EXPECT_EQ(isc::log::INFO, info_non_verbose.severity_);
+ EXPECT_EQ(0, info_non_verbose.debuglevel_);
+
+ ASSERT_EQ(1, info_non_verbose.destinations_.size());
+ EXPECT_EQ("stdout", info_non_verbose.destinations_[0].output_);
+
+ std::string header = "{\n";
+ std::string begin =
+ "\"name\": \"kea\",\n"
+ "\"output_options\": [ {\n"
+ " \"output\": \"stdout\", \"flush\": true, \"pattern\": \"\" } ],\n"
+ "\"severity\": \"";
+ std::string dbglvl = "\",\n\"debuglevel\": ";
+ std::string trailer = "\n}\n";
+ std::string expected = header + begin + "INFO" + dbglvl + "0" + trailer;
+ runToElementTest<LoggingInfo>(expected, info_non_verbose);
+
+ // Add a user context
+ std::string comment = "\"comment\": \"foo\"";
+ std::string user_context = "{ " + comment + " }";
+ std::string user_context_nl = "{\n" + comment + "\n}";
+ EXPECT_FALSE(info_non_verbose.getContext());
+ info_non_verbose.setContext(Element::fromJSON(user_context));
+ ASSERT_TRUE(info_non_verbose.getContext());
+ EXPECT_EQ(user_context, info_non_verbose.getContext()->str());
+ expected = header;
+ expected += "\"user-context\": " + user_context_nl + ",\n";
+ expected += begin + "INFO" + dbglvl + "0" + trailer;
+ runToElementTest<LoggingInfo>(expected, info_non_verbose);
+
+ Daemon::setVerbose(true);
+ LoggingInfo info_verbose;
+ EXPECT_EQ("kea", info_verbose.name_);
+ EXPECT_EQ(isc::log::DEBUG, info_verbose.severity_);
+ EXPECT_EQ(99, info_verbose.debuglevel_);
+
+ ASSERT_EQ(1, info_verbose.destinations_.size());
+ EXPECT_EQ("stdout", info_verbose.destinations_[0].output_);
+
+ EXPECT_EQ(10240000, info_verbose.destinations_[0].maxsize_);
+ EXPECT_EQ(1, info_verbose.destinations_[0].maxver_);
+
+ expected = header + begin + "DEBUG" + dbglvl + "99" + trailer;
+ runToElementTest<LoggingInfo>(expected, info_verbose);
+
+ // User comment again
+ EXPECT_FALSE(info_verbose.getContext());
+ info_verbose.setContext(Element::fromJSON(user_context));
+ ASSERT_TRUE(info_verbose.getContext());
+ EXPECT_EQ(user_context, info_verbose.getContext()->str());
+ expected = header;
+ expected += "\"user-context\": " + user_context_nl + ",\n";
+ expected += begin + "DEBUG" + dbglvl + "99" + trailer;
+ runToElementTest<LoggingInfo>(expected, info_verbose);
+}
+
+// Checks if (in)equality operators work for LoggingInfo.
+TEST_F(LoggingInfoTest, equalityOperators) {
+ LoggingInfo info1;
+ LoggingInfo info2;
+
+ // Initially, both objects are the same.
+ EXPECT_TRUE(info1 == info2);
+
+ // Differ by name.
+ info1.name_ = "foo";
+ info2.name_ = "bar";
+ EXPECT_FALSE(info1 == info2);
+ EXPECT_TRUE(info1 != info2);
+
+ // Names equal.
+ info2.name_ = "foo";
+ EXPECT_TRUE(info1 == info2);
+ EXPECT_FALSE(info1 != info2);
+
+ // Differ by severity.
+ info1.severity_ = isc::log::DEBUG;
+ info2.severity_ = isc::log::INFO;
+ EXPECT_FALSE(info1 == info2);
+ EXPECT_TRUE(info1 != info2);
+
+ // Severities equal.
+ info2.severity_ = isc::log::DEBUG;
+ EXPECT_TRUE(info1 == info2);
+ EXPECT_FALSE(info1 != info2);
+
+ // Differ by debug level.
+ info1.debuglevel_ = 99;
+ info2.debuglevel_ = 1;
+ EXPECT_FALSE(info1 == info2);
+ EXPECT_TRUE(info1 != info2);
+
+ // Debug level equal.
+ info2.debuglevel_ = 99;
+ EXPECT_TRUE(info1 == info2);
+ EXPECT_FALSE(info1 != info2);
+
+ // Create two different destinations.
+ LoggingDestination dest1;
+ LoggingDestination dest2;
+ dest1.output_ = "foo";
+ dest2.output_ = "bar";
+
+ // Push destinations in some order to info1.
+ info1.destinations_.push_back(dest1);
+ info1.destinations_.push_back(dest2);
+
+ // Push in reverse order to info2. Order shouldn't matter.
+ info2.destinations_.push_back(dest2);
+ info2.destinations_.push_back(dest1);
+
+ EXPECT_TRUE(info1 == info2);
+ EXPECT_FALSE(info1 != info2);
+
+ // Change one of the destinations.
+ LoggingDestination dest3;
+ dest3.output_ = "foobar";
+
+ info2.destinations_[2] = dest3;
+
+ // The should now be unequal.
+ EXPECT_FALSE(info1 == info2);
+ EXPECT_TRUE(info1 != info2);
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/process/tests/run_unittests.cc b/src/lib/process/tests/run_unittests.cc
new file mode 100644
index 0000000..a7c1f68
--- /dev/null
+++ b/src/lib/process/tests/run_unittests.cc
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 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 <process/d_log.h>
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+
+ // Override --localstatedir value for PID files
+ setenv("KEA_PIDFILE_DIR", TEST_DATA_BUILDDIR, 1);
+
+ int result = RUN_ALL_TESTS();
+
+ return (result);
+}