Browse Source

[master] Merge branch 'trac3422'

Marcin Siodelski 10 years ago
parent
commit
e1d164c7a9

+ 13 - 0
configure.ac

@@ -1446,16 +1446,24 @@ AC_CONFIG_FILES([compatcheck/Makefile
                  src/bin/d2/tests/test_data_files_config.h
                  src/bin/dhcp4/Makefile
                  src/bin/dhcp4/spec_config.h.pre
+                 src/bin/dhcp4/tests/dhcp4_process_tests.sh
                  src/bin/dhcp4/tests/Makefile
                  src/bin/dhcp4/tests/marker_file.h
                  src/bin/dhcp4/tests/test_data_files_config.h
                  src/bin/dhcp4/tests/test_libraries.h
                  src/bin/dhcp6/Makefile
                  src/bin/dhcp6/spec_config.h.pre
+                 src/bin/dhcp6/tests/dhcp6_process_tests.sh
                  src/bin/dhcp6/tests/Makefile
                  src/bin/dhcp6/tests/marker_file.h
                  src/bin/dhcp6/tests/test_data_files_config.h
                  src/bin/dhcp6/tests/test_libraries.h
+                 src/bin/keactrl/keactrl
+                 src/bin/keactrl/kea.conf
+                 src/bin/keactrl/keactrl.conf
+                 src/bin/keactrl/Makefile
+                 src/bin/keactrl/tests/keactrl_tests.sh
+                 src/bin/keactrl/tests/Makefile
                  src/bin/Makefile
                  src/bin/msgq/Makefile
                  src/bin/msgq/msgq.py
@@ -1559,6 +1567,7 @@ AC_CONFIG_FILES([compatcheck/Makefile
                  src/lib/python/isc/util/Makefile
                  src/lib/python/isc/util/tests/Makefile
                  src/lib/python/Makefile
+                 src/lib/testutils/dhcp_test_lib.sh
                  src/lib/testutils/Makefile
                  src/lib/testutils/testdata/Makefile
                  src/lib/util/io/Makefile
@@ -1587,6 +1596,10 @@ AC_CONFIG_FILES([compatcheck/Makefile
            chmod +x src/bin/bindctl/tests/bindctl_test
            chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/cmdctl/tests/cmdctl_test
+           chmod +x src/bin/dhcp4/tests/dhcp4_process_tests.sh
+           chmod +x src/bin/dhcp6/tests/dhcp6_process_tests.sh
+           chmod +x src/bin/keactrl/keactrl
+           chmod +x src/bin/keactrl/tests/keactrl_tests.sh
            chmod +x src/bin/msgq/run_msgq.sh
            chmod +x src/bin/sysinfo/run_sysinfo.sh
            chmod +x src/bin/usermgr/run_b10-cmdctl-usermgr.sh

+ 4 - 0
src/bin/Makefile.am

@@ -3,4 +3,8 @@ SUBDIRS = bind10 bindctl cfgmgr msgq cmdctl \
 	usermgr stats tests  sockcreator dhcp4 dhcp6 \
 	d2 sysinfo
 
+if CONFIG_BACKEND_JSON
+SUBDIRS += keactrl
+endif
+
 check-recursive: all-recursive

+ 4 - 4
src/bin/dhcp4/dhcp4_messages.mes

@@ -327,10 +327,10 @@ A debug message listing the data returned to the client.
 The DHCPv4 server has encountered a fatal error and is terminating.
 The reason for the failure is included in the message.
 
-% DHCP4_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone
-The server has failed to establish communication with the rest of BIND
-10 and is running in stand-alone mode.  (This behavior will change once
-the DHCPv4 server is properly integrated with the rest of BIND 10.)
+% DHCP4_INIT_FAIL failed to initialize Kea server: %1
+The server has failed to initialize. This may be because the configuration
+was not successful, or it encountered any other critical error on startup.
+Attached error message provides more details about the issue.
 
 % DHCP4_SHUTDOWN server shutdown
 The DHCPv4 server has terminated normally.

+ 1 - 1
src/bin/dhcp4/main.cc

@@ -115,7 +115,7 @@ main(int argc, char* argv[]) {
             // Initialize the server.
             server.init(config_file);
         } catch (const std::exception& ex) {
-            LOG_ERROR(dhcp4_logger, DHCP4_SESSION_FAIL).arg(ex.what());
+            LOG_ERROR(dhcp4_logger, DHCP4_INIT_FAIL).arg(ex.what());
 
             // We should not continue if were told to configure (either read
             // config file or establish Bundy control session).

+ 1 - 0
src/bin/dhcp4/tests/.gitignore

@@ -2,3 +2,4 @@
 /marker_file.h
 /test_data_files_config.h
 /test_libraries.h
+/dhcp4_process_tests.sh

+ 7 - 8
src/bin/dhcp4/tests/Makefile.am

@@ -5,16 +5,13 @@ SHTESTS =
 # The test of dynamic reconfiguration based on signals will work only
 # if we are using file based configuration approach.
 if CONFIG_BACKEND_JSON
-SHTESTS += dhcp4_reconfigure_test.sh
-SHTESTS += dhcp4_sigterm_test.sh
-SHTESTS += dhcp4_sigint_test.sh
+SHTESTS += dhcp4_process_tests.sh
 endif
 
+noinst_SCRIPTS = dhcp4_process_tests.sh
+
 EXTRA_DIST  = $(PYTESTS)
-EXTRA_DIST += dhcp4_reconfigure_test.sh
-EXTRA_DIST += dhcp4_sigterm_test.sh
-EXTRA_DIST += dhcp4_sigint_test.sh
-EXTRA_DIST += dhcp4_shutdown_test.sh
+EXTRA_DIST += dhcp4_process_tests.sh.in
 
 # Explicitly specify paths to dynamic libraries required by loadable python
 # modules. That is required on Mac OS systems. Otherwise we will get exception
@@ -37,7 +34,7 @@ check-local:
 	for shtest in $(SHTESTS) ; do \
 	echo Running test: $$shtest ; \
 	export B10_LOCKFILE_DIR_FROM_BUILD=$(abs_top_builddir); \
-	$(abs_srcdir)/$$shtest || exit ; \
+	${SHELL} $(abs_builddir)/$$shtest || exit ; \
 	done
 
 
@@ -55,6 +52,8 @@ CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
 CLEANFILES += $(builddir)/load_marker.txt $(builddir)/unload_marker.txt
 CLEANFILES += *.json *.log
 
+DISTCLEANFILES = dhcp4_process_tests.sh
+
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 if USE_CLANGPP
 # Disable unused parameter warning caused by some Boost headers when compiling with clang

+ 231 - 0
src/bin/dhcp4/tests/dhcp4_process_tests.sh.in

@@ -0,0 +1,231 @@
+# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Path to the temporary configuration file.
+CFG_FILE=@abs_top_builddir@/src/bin/dhcp4/tests/test_config.json
+# Path to the Kea log file.
+LOG_FILE=@abs_top_builddir@/src/bin/dhcp4/tests/test.log
+# Kea configuration to be stored in the configuration file.
+CONFIG="{
+    \"Dhcp4\":
+    {
+        \"interfaces\": [ ],
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"persist\": false
+        },
+        \"subnet4\": [
+        {
+            \"subnet\": \"10.0.0.0/8\",
+            \"pool\": [ \"10.0.0.10-10.0.0.100\" ]
+        } ]
+    }
+}"
+# Invalid configuration (negative valid-lifetime) to check that Kea
+# gracefully handles reconfiguration errors.
+CONFIG_INVALID="{
+    \"Dhcp4\":
+    {
+        \"interfaces\": [ ],
+        \"valid-lifetime\": -3,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"persist\": false
+        },
+        \"subnet4\": [
+        {
+            \"subnet\": \"10.0.0.0/8\",
+            \"pool\": [ \"10.0.0.10-10.0.0.100\" ]
+        } ]
+    }
+}"
+
+# Set the location of the executable.
+bin="b10-dhcp4"
+bin_path=@abs_top_builddir@/src/bin/dhcp4
+
+# Import common test library.
+. @abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh
+
+# This test verifies that DHCPv4 can be reconfigured with a SIGHUP signal.
+dynamic_reconfiguration_test() {
+    # Log the start of the test and print test name.
+    test_start "dhcpv4_srv.dynamic_reconfiguration"
+    # Remove dangling Kea instances and remove log files.
+    cleanup
+    # Create new configuration file.
+    create_config "${CONFIG}"
+    # Instruct Kea to log to the specific file.
+    set_logger
+    # Start Kea.
+    start_kea ${bin_path}/${bin}
+    # Wait up to 20s for Kea to start.
+    wait_for_kea 20
+    if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+        printf "ERROR: timeout waiting for Kea to start.\n"
+        clean_exit 1
+    fi
+
+    # Check if it is still running. It could have terminated (e.g. as a result
+    # of configuration failure).
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: expected one Kea process to be started. Found %d processes\
+ started.\n" ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    # Check in the log file, how many times server has been configured. It should
+    # be just once on startup.
+    get_reconfigs
+    if [ ${_GET_RECONFIGS} -ne 1 ]; then
+        printf "ERROR: server hasn't been configured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully configured.\n"
+    fi
+
+    # Now use invalid configuration.
+    create_config "${CONFIG_INVALID}"
+
+    # Try to reconfigure by sending SIGHUP
+    send_signal 1 ${bin}
+
+    # The configuration should fail and the error message should be there.
+    wait_for_message 10 "DHCP4_CONFIG_LOAD_FAIL" 1
+
+    # After receiving SIGHUP the server should try to reconfigure itself.
+    # The configuration provided is invalid so it should result in
+    # reconfiguration failure but the server should still be running.
+    get_reconfigs
+    if [ ${_GET_RECONFIGS} -ne 1 ]; then
+        printf "ERROR: server has been reconfigured despite bogus configuration.\n"
+        clean_exit 1
+    elif [ ${_GET_RECONFIG_ERRORS} -ne 1 ]; then
+        printf "ERROR: server did not report reconfiguration error despite attempt\
+ to configure it with invalid configuration.\n"
+        clean_exit 1
+    fi
+
+    # Make sure the server is still operational.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
+        clean_exit 1
+    fi
+
+    # Restore the good configuration.
+    create_config "${CONFIG}"
+
+    # Reconfigure the server with SIGHUP.
+    send_signal 1 ${bin}
+
+    # There should be two occurrences of the DHCP4_CONFIG_COMPLETE messages.
+    # Wait for it up to 10s.
+    wait_for_message 10 "DHCP4_CONFIG_COMPLETE" 2
+
+    # After receiving SIGHUP the server should get reconfigured and the
+    # reconfiguration should be noted in the log file. We should now
+    # have two configurations logged in the log file.
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: server hasn't been reconfigured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully reconfigured.\n"
+    fi
+
+    # Make sure the server is still operational.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
+        clean_exit 1
+    fi
+
+    # All ok. Shut down Kea and exit.
+    test_finish 0
+}
+
+# This test verifies that DHCPv4 server is shut down gracefully when it
+# receives a SIGINT or SIGTERM signal.
+shutdown_test() {
+    test_name=${1}  # Test name
+    signum=${2}      # Signal number
+    # Log the start of the test and print test name.
+    test_start ${test_name}
+    # Remove dangling Kea instances and remove log files.
+    cleanup
+    # Create new configuration file.
+    create_config "${CONFIG}"
+    # Instruct Kea to log to the specific file.
+    set_logger
+    # Start Kea.
+    start_kea ${bin_path}/${bin}
+    # Wait up to 20s for Kea to start.
+    wait_for_kea 20
+    if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+        printf "ERROR: timeout waiting for Kea to start.\n"
+        clean_exit 1
+    fi
+
+    # Check if it is still running. It could have terminated (e.g. as a result
+    # of configuration failure).
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: expected one Kea process to be started. Found %d processes\
+ started.\n" ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    # Check in the log file, how many times server has been configured. It should
+    # be just once on startup.
+    get_reconfigs
+    if [ ${_GET_RECONFIGS} -ne 1 ]; then
+        printf "ERROR: server hasn't been configured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully configured.\n"
+    fi
+
+    # Send signal to Kea (SIGTERM, SIGINT etc.)
+    send_signal ${signum} ${bin}
+
+    # Wait up to 10s for the server's graceful shutdown. The graceful shut down
+    # should be recorded in the log file with the appropriate message.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: Server did not record shutdown in the log.\n"
+        clean_exit 1
+    fi
+
+    # Server should have shut down.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 0 ]; then
+        printf "ERROR: Kea did not shut down after receiving signal.\n"\
+ ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    test_finish 0
+}
+
+dynamic_reconfiguration_test
+shutdown_test "dhcpv4.sigterm_test" 15
+shutdown_test "dhcpv4.sigint_test" 2

+ 0 - 163
src/bin/dhcp4/tests/dhcp4_reconfigure_test.sh

@@ -1,163 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# Test name
-TEST_NAME="DHCPv4.dynamicReconfiguration"
-# Path to the temporary configuration file.
-CFG_FILE="test_config.json"
-# Path to the Kea log file.
-LOG_FILE="test.log"
-# Kea configuration to be stored in the configuration file.
-CONFIG="{
-    \"Dhcp4\":
-    {
-        \"interfaces\": [ ],
-        \"valid-lifetime\": 4000,
-        \"renew-timer\": 1000,
-        \"rebind-timer\": 2000,
-        \"lease-database\":
-        {
-            \"type\": \"memfile\",
-            \"persist\": false
-        },
-        \"subnet4\": [
-        {
-            \"subnet\": \"10.0.0.0/8\",
-            \"pool\": [ \"10.0.0.10-10.0.0.100\" ]
-        } ]
-    }
-}"
-# Invalid configuration (negative valid-lifetime) to check that Kea
-# gracefully handles reconfiguration errors.
-CONFIG_INVALID="{
-    \"Dhcp4\":
-    {
-        \"interfaces\": [ ],
-        \"valid-lifetime\": -3,
-        \"renew-timer\": 1000,
-        \"rebind-timer\": 2000,
-        \"lease-database\":
-        {
-            \"type\": \"memfile\",
-            \"persist\": false
-        },
-        \"subnet4\": [
-        {
-            \"subnet\": \"10.0.0.0/8\",
-            \"pool\": [ \"10.0.0.10-10.0.0.100\" ]
-        } ]
-    }
-}"
-
-# Set the location of the executable.
-BIN="b10-dhcp4"
-BIN_PATH=".."
-
-# Import common test library.
-. $(dirname $0)/../../../lib/testutils/dhcp_test_lib.sh
-
-# Log the start of the test and print test name.
-test_start
-# Remove dangling Kea instances and remove log files.
-cleanup
-# Create new configuration file.
-create_config "${CONFIG}"
-# Instruct Kea to log to the specific file.
-set_logger
-# Start Kea.
-start_kea
-# Wait up to 20s for Kea to start.
-wait_for_kea 20
-if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
-    printf "ERROR: timeout waiting for Kea to start.\n"
-    clean_exit 1
-fi
-
-# Check if it is still running. It could have terminated (e.g. as a result
-# of configuration failure).
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: expected one Kea process to be started. Found %d processes\
- started.\n" ${_GET_PIDS_NUM}
-    clean_exit 1
-fi
-
-# Check in the log file, how many times server has been configured. It should
-# be just once on startup.
-get_reconfigs
-if [ ${_GET_RECONFIGS} -ne 1 ]; then
-    printf "ERROR: server hasn't been configured.\n"
-    clean_exit 1
-else
-    printf "Server successfully configured.\n"
-fi
-
-# Now use invalid configuration.
-create_config "${CONFIG_INVALID}"
-
-# Try to reconfigure by sending SIGHUP
-send_signal 1
-
-# The configuration should fail and the error message should be there.
-wait_for_message 10 "DHCP4_CONFIG_LOAD_FAIL" 1
-
-# After receiving SIGHUP the server should try to reconfigure itself.
-# The configuration provided is invalid so it should result in
-# reconfiguration failure but the server should still be running.
-get_reconfigs
-if [ ${_GET_RECONFIGS} -ne 1 ]; then
-    printf "ERROR: server has been reconfigured despite bogus configuration.\n"
-    clean_exit 1
-elif [ ${_GET_RECONFIG_ERRORS} -ne 1 ]; then
-    printf "ERROR: server did not report reconfiguration error despite attempt\
- to configure it with invalid configuration.\n"
-    clean_exit 1
-fi
-
-# Make sure the server is still operational.
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
-    clean_exit 1
-fi
-
-# Restore the good configuration.
-create_config "${CONFIG}"
-
-# Reconfigure the server with SIGHUP.
-send_signal 1
-
-# There should be two occurrences of the DHCP4_CONFIG_COMPLETE messages.
-# Wait for it up to 10s.
-wait_for_message 10 "DHCP4_CONFIG_COMPLETE" 2
-
-# After receiving SIGHUP the server should get reconfigured and the
-# reconfiguration should be noted in the log file. We should now
-# have two configurations logged in the log file.
-if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
-    printf "ERROR: server hasn't been reconfigured.\n"
-    clean_exit 1
-else
-    printf "Server successfully reconfigured.\n"
-fi
-
-# Make sure the server is still operational.
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
-    clean_exit 1
-fi
-
-# All ok. Shut down Kea and exit.
-clean_exit 0

+ 0 - 111
src/bin/dhcp4/tests/dhcp4_shutdown_test.sh

@@ -1,111 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-if [ $# -ne 2 ]; then
-    printf "USAGE: dhcp4_shutdown_test.sh <test_name> <signal_num>\n"
-    exit 1
-fi
-
-# Test name
-TEST_NAME=$1
-# Signal number to be used for this test.
-SIG_NUM=$2
-# Path to the temporary configuration file.
-CFG_FILE="test_config.json"
-# Path to the Kea log file.
-LOG_FILE="test.log"
-# Kea configuration to be stored in the configuration file.
-CONFIG="{
-    \"Dhcp4\":
-    {
-        \"interfaces\": [ ],
-        \"valid-lifetime\": 4000,
-        \"renew-timer\": 1000,
-        \"rebind-timer\": 2000,
-        \"lease-database\":
-        {
-            \"type\": \"memfile\",
-            \"persist\": false
-        },
-        \"subnet4\": [
-        {
-            \"subnet\": \"10.0.0.0/8\",
-            \"pool\": [ \"10.0.0.10-10.0.0.100\" ]
-        } ]
-    }
-}"
-
-# Set the location of the executable.
-BIN="b10-dhcp4"
-BIN_PATH=".."
-
-# Import common test library.
-. $(dirname $0)/../../../lib/testutils/dhcp_test_lib.sh
-
-# Log the start of the test and print test name.
-test_start
-# Remove dangling Kea instances and remove log files.
-cleanup
-# Create new configuration file.
-create_config "${CONFIG}"
-# Instruct Kea to log to the specific file.
-set_logger
-# Start Kea.
-start_kea
-# Wait up to 20s for Kea to start.
-wait_for_kea 20
-if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
-    printf "ERROR: timeout waiting for Kea to start.\n"
-    clean_exit 1
-fi
-
-# Check if it is still running. It could have terminated (e.g. as a result
-# of configuration failure).
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: expected one Kea process to be started. Found %d processes\
- started.\n" ${_GET_PIDS_NUM}
-    clean_exit 1
-fi
-
-# Check in the log file, how many times server has been configured. It should
-# be just once on startup.
-get_reconfigs
-if [ ${_GET_RECONFIGS} -ne 1 ]; then
-    printf "ERROR: server hasn't been configured.\n"
-    clean_exit 1
-else
-    printf "Server successfully configured.\n"
-fi
-
-# Send signal to Kea (SIGTERM, SIGINT etc.)
-send_signal ${SIG_NUM}
-
-# Wait up to 10s for the server's graceful shutdown. The graceful shut down
-# should be recorded in the log file with the appropriate message.
-wait_for_message 10 "DHCP4_SHUTDOWN" 1
-if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
-    printf "ERROR: Server did not record shutdown in the log.\n"
-    clean_exit 1
-fi
-
-# Server should have shut down.
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 0 ]; then
-    printf "ERROR: Kea did not shut down after receiving signal.\n"\
- ${_GET_PIDS_NUM}
-    clean_exit 1
-fi
-
-clean_exit 0

+ 0 - 16
src/bin/dhcp4/tests/dhcp4_sigint_test.sh

@@ -1,16 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# Run a test that sends SIGINT to Kea and checks if it shuts down gracefully.
-$(dirname $0)/dhcp4_shutdown_test.sh "DHCPv4.sigint" 2

+ 0 - 16
src/bin/dhcp4/tests/dhcp4_sigterm_test.sh

@@ -1,16 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# Run a test that sends SIGTERM to Kea and checks if it shuts down gracefully.
-$(dirname $0)/dhcp4_shutdown_test.sh "DHCPv4.sigterm" 15

+ 1 - 0
src/bin/dhcp6/tests/.gitignore

@@ -2,3 +2,4 @@
 /marker_file.h
 /test_data_files_config.h
 /test_libraries.h
+/dhcp6_process_tests.sh

+ 7 - 8
src/bin/dhcp6/tests/Makefile.am

@@ -4,16 +4,13 @@ SHTESTS =
 # The test of dynamic reconfiguration based on signals will work only
 # if we are using file based configuration approach.
 if CONFIG_BACKEND_JSON
-SHTESTS += dhcp6_reconfigure_test.sh
-SHTESTS += dhcp6_sigterm_test.sh
-SHTESTS += dhcp6_sigint_test.sh
+SHTESTS += dhcp6_process_tests.sh
 endif
 
+noinst_SCRIPTS = dhcp6_process_tests.sh
+
 EXTRA_DIST = $(PYTESTS)
-EXTRA_DIST += dhcp6_reconfigure_test.sh
-EXTRA_DIST += dhcp6_sigterm_test.sh
-EXTRA_DIST += dhcp6_sigint_test.sh
-EXTRA_DIST += dhcp6_shutdown_test.sh
+EXTRA_DIST += dhcp6_process_tests.sh.in
 
 # Explicitly specify paths to dynamic libraries required by loadable python
 # modules. That is required on Mac OS systems. Otherwise we will get exception
@@ -36,7 +33,7 @@ check-local:
 	for shtest in $(SHTESTS) ; do \
 	echo Running test: $$shtest ; \
 	export B10_LOCKFILE_DIR_FROM_BUILD=$(abs_top_builddir); \
-	$(abs_srcdir)/$$shtest || exit ; \
+	${SHELL} $(abs_builddir)/$$shtest || exit ; \
 	done
 
 
@@ -51,6 +48,8 @@ CLEANFILES  = $(builddir)/interfaces.txt $(builddir)/logger_lockfile
 CLEANFILES += $(builddir)/load_marker.txt $(builddir)/unload_marker.txt
 CLEANFILES += *.json *.log
 
+DISTCLEANFILES = dhcp6_process_tests.sh
+
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 if USE_CLANGPP
 # Disable unused parameter warning caused by some Boost headers when compiling with clang

+ 234 - 0
src/bin/dhcp6/tests/dhcp6_process_tests.sh.in

@@ -0,0 +1,234 @@
+# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Path to the temporary configuration file.
+CFG_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test_config.json
+# Path to the Kea log file.
+LOG_FILE=@abs_top_builddir@/src/bin/dhcp6/tests/test.log
+# Kea configuration to be stored in the configuration file.
+CONFIG="{
+    \"Dhcp6\":
+    {
+        \"interfaces\": [ ],
+        \"preferred-lifetime\": 3000,
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"persist\": false
+        },
+        \"subnet6\": [
+        {
+            \"subnet\": \"2001:db8:1::/64\",
+            \"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
+        } ]
+    }
+}"
+# Invalid configuration (negative preferred-lifetime) to check that Kea
+# gracefully handles reconfiguration errors.
+CONFIG_INVALID="{
+    \"Dhcp6\":
+    {
+        \"interfaces\": [ ],
+        \"preferred-lifetime\": -3,
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"persist\": false
+        },
+        \"subnet6\": [
+        {
+            \"subnet\": \"2001:db8:1::/64\",
+            \"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
+        } ]
+    }
+}"
+
+# Set the location of the executable.
+bin="b10-dhcp6"
+bin_path=@abs_top_builddir@/src/bin/dhcp6
+
+# Import common test library.
+. @abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh
+
+# This test verifies that DHCPv6 can be reconfigured with a SIGHUP signal.
+dynamic_reconfiguration_test() {
+    # Log the start of the test and print test name.
+    test_start "dhcpv6_srv.dynamic_reconfiguration"
+    # Remove dangling Kea instances and remove log files.
+    cleanup
+    # Create new configuration file.
+    create_config "${CONFIG}"
+    # Instruct Kea to log to the specific file.
+    set_logger
+    # Start Kea.
+    start_kea ${bin_path}/${bin}
+    # Wait up to 20s for Kea to start.
+    wait_for_kea 20
+    if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+        printf "ERROR: timeout waiting for Kea to start.\n"
+        clean_exit 1
+    fi
+
+    # Check if it is still running. It could have terminated (e.g. as a result
+    # of configuration failure).
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: expected one Kea process to be started. Found %d processes\
+ started.\n" ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    # Check in the log file, how many times server has been configured. It should
+    # be just once on startup.
+    get_reconfigs
+    if [ ${_GET_RECONFIGS} -ne 1 ]; then
+        printf "ERROR: server hasn't been configured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully configured.\n"
+    fi
+
+    # Now use invalid configuration.
+    create_config "${CONFIG_INVALID}"
+
+    # Try to reconfigure by sending SIGHUP
+    send_signal 1 ${bin}
+
+    # The configuration should fail and the error message should be there.
+    wait_for_message 10 "DHCP6_CONFIG_LOAD_FAIL" 1
+
+    # After receiving SIGHUP the server should try to reconfigure itself.
+    # The configuration provided is invalid so it should result in
+    # reconfiguration failure but the server should still be running.
+    get_reconfigs
+    if [ ${_GET_RECONFIGS} -ne 1 ]; then
+        printf "ERROR: server has been reconfigured despite bogus configuration.\n"
+        clean_exit 1
+    elif [ ${_GET_RECONFIG_ERRORS} -ne 1 ]; then
+        printf "ERROR: server did not report reconfiguration error despite attempt\
+ to configure it with invalid configuration.\n"
+        clean_exit 1
+    fi
+
+    # Make sure the server is still operational.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
+        clean_exit 1
+    fi
+
+    # Restore the good configuration.
+    create_config "${CONFIG}"
+
+    # Reconfigure the server with SIGHUP.
+    send_signal 1 ${bin}
+
+    # There should be two occurrences of the DHCP6_CONFIG_COMPLETE messages.
+    # Wait for it up to 10s.
+    wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2
+
+    # After receiving SIGHUP the server should get reconfigured and the
+    # reconfiguration should be noted in the log file. We should now
+    # have two configurations logged in the log file.
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: server hasn't been reconfigured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully reconfigured.\n"
+    fi
+
+    # Make sure the server is still operational.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
+        clean_exit 1
+    fi
+
+    # All ok. Shut down Kea and exit.
+    test_finish 0
+}
+
+# This test verifies that DHCPv6 server is shut down gracefully when it
+# receives a SIGINT or SIGTERM signal.
+shutdown_test() {
+    test_name=${1}  # Test name
+    signum=${2}      # Signal number
+
+    # Log the start of the test and print test name.
+    test_start ${test_name}
+    # Remove dangling Kea instances and remove log files.
+    cleanup
+    # Create new configuration file.
+    create_config "${CONFIG}"
+    # Instruct Kea to log to the specific file.
+    set_logger
+    # Start Kea.
+    start_kea ${bin_path}/${bin}
+    # Wait up to 20s for Kea to start.
+    wait_for_kea 20
+    if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+        printf "ERROR: timeout waiting for Kea to start.\n"
+        clean_exit 1
+    fi
+
+    # Check if it is still running. It could have terminated (e.g. as a result
+    # of configuration failure).
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: expected one Kea process to be started. Found %d processes\
+ started.\n" ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    # Check in the log file, how many times server has been configured. It should
+    # be just once on startup.
+    get_reconfigs
+    if [ ${_GET_RECONFIGS} -ne 1 ]; then
+        printf "ERROR: server hasn't been configured.\n"
+        clean_exit 1
+    else
+        printf "Server successfully configured.\n"
+    fi
+
+    # Send signal to Kea (SIGTERM, SIGINT etc.)
+    send_signal ${signum} ${bin}
+
+    # Wait up to 10s for the server's graceful shutdown. The graceful shut down
+    # should be recorded in the log file with the appropriate message.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+        printf "ERROR: Server did not record shutdown in the log.\n"
+        clean_exit 1
+    fi
+
+    # Server should have shut down.
+    get_pids ${bin}
+    if [ ${_GET_PIDS_NUM} -ne 0 ]; then
+        printf "ERROR: Kea did not shut down after receiving signal.\n"\
+ ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+
+    test_finish 0
+}
+
+dynamic_reconfiguration_test
+shutdown_test "dhcpv4.sigterm_test" 15
+shutdown_test "dhcpv4.sigint_test" 2

+ 0 - 165
src/bin/dhcp6/tests/dhcp6_reconfigure_test.sh

@@ -1,165 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# Test name
-TEST_NAME="DHCPv6.dynamicReconfiguration"
-# Path to the temporary configuration file.
-CFG_FILE="test_config.json"
-# Path to the Kea log file.
-LOG_FILE="test.log"
-# Kea configuration to be stored in the configuration file.
-CONFIG="{
-    \"Dhcp6\":
-    {
-        \"interfaces\": [ ],
-        \"preferred-lifetime\": 3000,
-        \"valid-lifetime\": 4000,
-        \"renew-timer\": 1000,
-        \"rebind-timer\": 2000,
-        \"lease-database\":
-        {
-            \"type\": \"memfile\",
-            \"persist\": false
-        },
-        \"subnet6\": [
-        {
-            \"subnet\": \"2001:db8:1::/64\",
-            \"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
-        } ]
-    }
-}"
-# Invalid configuration (negative preferred-lifetime) to check that Kea
-# gracefully handles reconfiguration errors.
-CONFIG_INVALID="{
-    \"Dhcp6\":
-    {
-        \"interfaces\": [ ],
-        \"preferred-lifetime\": -3,
-        \"valid-lifetime\": 4000,
-        \"renew-timer\": 1000,
-        \"rebind-timer\": 2000,
-        \"lease-database\":
-        {
-            \"type\": \"memfile\",
-            \"persist\": false
-        },
-        \"subnet6\": [
-        {
-            \"subnet\": \"2001:db8:1::/64\",
-            \"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
-        } ]
-    }
-}"
-
-# Set the location of the executable.
-BIN="b10-dhcp6"
-BIN_PATH=".."
-
-# Import common test library.
-. $(dirname $0)/../../../lib/testutils/dhcp_test_lib.sh
-
-# Log the start of the test and print test name.
-test_start
-# Remove dangling Kea instances and remove log files.
-cleanup
-# Create new configuration file.
-create_config "${CONFIG}"
-# Instruct Kea to log to the specific file.
-set_logger
-# Start Kea.
-start_kea
-# Wait up to 20s for Kea to start.
-wait_for_kea 20
-if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
-    printf "ERROR: timeout waiting for Kea to start.\n"
-    clean_exit 1
-fi
-
-# Check if it is still running. It could have terminated (e.g. as a result
-# of configuration failure).
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: expected one Kea process to be started. Found %d processes\
- started.\n" ${_GET_PIDS_NUM}
-    clean_exit 1
-fi
-
-# Check in the log file, how many times server has been configured. It should
-# be just once on startup.
-get_reconfigs
-if [ ${_GET_RECONFIGS} -ne 1 ]; then
-    printf "ERROR: server hasn't been configured.\n"
-    clean_exit 1
-else
-    printf "Server successfully configured.\n"
-fi
-
-# Now use invalid configuration.
-create_config "${CONFIG_INVALID}"
-
-# Try to reconfigure by sending SIGHUP
-send_signal 1
-
-# The configuration should fail and the error message should be there.
-wait_for_message 10 "DHCP6_CONFIG_LOAD_FAIL" 1
-
-# After receiving SIGHUP the server should try to reconfigure itself.
-# The configuration provided is invalid so it should result in
-# reconfiguration failure but the server should still be running.
-get_reconfigs
-if [ ${_GET_RECONFIGS} -ne 1 ]; then
-    printf "ERROR: server has been reconfigured despite bogus configuration.\n"
-    clean_exit 1
-elif [ ${_GET_RECONFIG_ERRORS} -ne 1 ]; then
-    printf "ERROR: server did not report reconfiguration error despite attempt\
- to configure it with invalid configuration.\n"
-    clean_exit 1
-fi
-
-# Make sure the server is still operational.
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
-    clean_exit 1
-fi
-
-# Restore the good configuration.
-create_config "${CONFIG}"
-
-# Reconfigure the server with SIGHUP.
-send_signal 1
-
-# There should be two occurrences of the DHCP6_CONFIG_COMPLETE messages.
-# Wait for it up to 10s.
-wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2
-
-# After receiving SIGHUP the server should get reconfigured and the
-# reconfiguration should be noted in the log file. We should now
-# have two configurations logged in the log file.
-if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
-    printf "ERROR: server hasn't been reconfigured.\n"
-    clean_exit 1
-else
-    printf "Server successfully reconfigured.\n"
-fi
-
-# Make sure the server is still operational.
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: Kea process was killed when attempting reconfiguration.\n"
-    clean_exit 1
-fi
-
-# All ok. Shut down Kea and exit.
-clean_exit 0

+ 0 - 112
src/bin/dhcp6/tests/dhcp6_shutdown_test.sh

@@ -1,112 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-if [ $# -ne 2 ]; then
-    printf "USAGE: dhcp6_shutdown_test.sh <test_name> <signal_num>\n"
-    exit 1
-fi
-
-# Test name
-TEST_NAME=$1
-# Signal number to be used for this test.
-SIG_NUM=$2
-# Path to the temporary configuration file.
-CFG_FILE="test_config.json"
-# Path to the Kea log file.
-LOG_FILE="test.log"
-# Kea configuration to be stored in the configuration file.
-CONFIG="{
-    \"Dhcp6\":
-    {
-        \"interfaces\": [ ],
-        \"preferred-lifetime\": 3000,
-        \"valid-lifetime\": 4000,
-        \"renew-timer\": 1000,
-        \"rebind-timer\": 2000,
-        \"lease-database\":
-        {
-            \"type\": \"memfile\",
-            \"persist\": false
-        },
-        \"subnet6\": [
-        {
-            \"subnet\": \"2001:db8:1::/64\",
-            \"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
-        } ]
-    }
-}"
-
-# Set the location of the executable.
-BIN="b10-dhcp6"
-BIN_PATH=".."
-
-# Import common test library.
-. $(dirname $0)/../../../lib/testutils/dhcp_test_lib.sh
-
-# Log the start of the test and print test name.
-test_start
-# Remove dangling Kea instances and remove log files.
-cleanup
-# Create new configuration file.
-create_config "${CONFIG}"
-# Instruct Kea to log to the specific file.
-set_logger
-# Start Kea.
-start_kea
-# Wait up to 20s for Kea to start.
-wait_for_kea 20
-if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
-    printf "ERROR: timeout waiting for Kea to start.\n"
-    clean_exit 1
-fi
-
-# Check if it is still running. It could have terminated (e.g. as a result
-# of configuration failure).
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-    printf "ERROR: expected one Kea process to be started. Found %d processes\
- started.\n" ${_GET_PIDS_NUM}
-    clean_exit 1
-fi
-
-# Check in the log file, how many times server has been configured. It should
-# be just once on startup.
-get_reconfigs
-if [ ${_GET_RECONFIGS} -ne 1 ]; then
-    printf "ERROR: server hasn't been configured.\n"
-    clean_exit 1
-else
-    printf "Server successfully configured.\n"
-fi
-
-# Send signal to Kea (SIGTERM, SIGINT etc.)
-send_signal ${SIG_NUM}
-
-# Wait up to 10s for the server's graceful shutdown. The graceful shut down
-# should be recorded in the log file with the appropriate message.
-wait_for_message 10 "DHCP6_SHUTDOWN" 1
-if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
-    printf "ERROR: Server did not record shutdown in the log.\n"
-    clean_exit 1
-fi
-
-# Server should have shut down.
-get_pids
-if [ ${_GET_PIDS_NUM} -ne 0 ]; then
-    printf "ERROR: Kea did not shut down after receiving signal.\n"\
- ${_GET_PIDS_NUM}
-    clean_exit 1
-fi
-
-clean_exit 0

+ 0 - 16
src/bin/dhcp6/tests/dhcp6_sigint_test.sh

@@ -1,16 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# Run a test that sends SIGINT to Kea and checks if it shuts down gracefully.
-$(dirname $0)/dhcp6_shutdown_test.sh "DHCPv6.sigint" 2

+ 0 - 16
src/bin/dhcp6/tests/dhcp6_sigterm_test.sh

@@ -1,16 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# Run a test that sends SIGTERM to Kea and checks if it shuts down gracefully.
-$(dirname $0)/dhcp6_shutdown_test.sh "DHCPv6.sigterm" 15

+ 3 - 0
src/bin/keactrl/.gitignore

@@ -0,0 +1,3 @@
+/keactrl
+/kea.conf
+/keactrl.conf

+ 23 - 0
src/bin/keactrl/Makefile.am

@@ -0,0 +1,23 @@
+SUBDIRS = . tests
+
+# Install keactrl in sbin and the keactrl.conf required by the keactrl
+# in etc. keactrl will look for its configuration file in the etc folder.
+# If the default location needs to be changed it may be achieved by
+# setting KEACTRL_CONF environment variable.
+sbin_SCRIPTS  = keactrl
+CONFIGFILES = keactrl.conf kea.conf
+
+DISTCLEANFILES = keactrl $(CONFIGFILES)
+EXTRA_DIST = keactrl.in keactrl.conf.in kea.conf.in
+
+if INSTALL_CONFIGURATIONS
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)/@sysconfdir@/@PACKAGE@
+	for f in $(CONFIGFILES) ; do	\
+	  if test ! -f $(DESTDIR)$(sysconfdir)/@PACKAGE@/$$f; then	\
+	    ${INSTALL_DATA} $$f $(DESTDIR)$(sysconfdir)/@PACKAGE@/ ;	\
+	  fi ;	\
+	done
+
+endif

+ 7 - 0
src/bin/keactrl/README

@@ -0,0 +1,7 @@
+This directory contains the source for the "keactrl" script which is used to
+start, stop and reconfigure Kea processes:
+- DHCPv4 server,
+- DHCPv6 server,
+- DDNS module (a.k.a D2)
+
+The "tests" directory contains unit tests for the script.

+ 60 - 0
src/bin/keactrl/kea.conf.in

@@ -0,0 +1,60 @@
+# This is a basic configuration for the Kea DHCPv4 and DHCPv6 servers.
+# Subnet declarations are commented out and no interfaces are listed.
+# Therefore, the servers will not listen or to any queries. The basic
+# configuration must be extended to specify interfaces on which the
+# servers should listen. Also, subnets and options must be declared.
+{
+
+# DHCPv4 configuration starts here.
+"Dhcp4":
+{
+# Add names of interfaces to listen on.
+  "interfaces": [ ],
+
+# Use Memfile lease database backend to store leases in a CSV file.
+  "lease-database": {
+    "type": "memfile"
+  },
+
+# Global (inherited by all subnets) lease lifetime is mandatory parameter.
+  "valid-lifetime": 4000,
+
+# Below an example of the simple subnet declaration. Uncomment to
+# enable it.
+  "subnet4": [
+#  {    "subnet": "192.0.2.0/24",
+#       "pool": [ "192.0.2.1 - 192.0.2.200" ] }
+  ]
+},
+
+# DHCPv6 configuration starts here.
+"Dhcp6":
+{
+# Add names of interfaces to listen on.
+  "interfaces": [ ],
+
+# Addresses will be assigned with preferred and valid lifetimes
+# being 3000 and 4000, respectively. Client is told to start
+# renewing after 1000 seconds. If the server does not repond
+# after 2000 seconds since the lease was granted, client is supposed
+# to start REBIND procedure (emergency renewal that allows switching
+# to a different server).
+  "preferred-lifetime": 3000,
+  "valid-lifetime": 4000,
+  "renew-timer": 1000,
+  "rebind-timer": 2000,
+
+# The following list defines subnets. Uncomment to enable them.
+  "subnet6": [
+#  {    "subnet": "2001:db8:1::/64",
+#       "pool": [ "2001:db8:1::/80" ] },
+#  {    "subnet": "2001:db8:2::/64",
+#       "pool": [ "2001:db8:2::/80" ] },
+#  {    "subnet": "2001:db8:3::/64",
+#       "pool": [ "2001:db8:3::/80" ] },
+#  {    "subnet": "2001:db8:4::/64",
+#       "pool": [ "2001:db8:4::/80" ] }
+   ]
+}
+
+}

+ 24 - 0
src/bin/keactrl/keactrl.conf.in

@@ -0,0 +1,24 @@
+# This is a configuration file for keactrl script which controls
+# the startup, shutdown, reconfiguration and gathering the status
+# of the Kea's processes.
+
+# prefix holds the location where the Kea is installed.
+prefix=@prefix@
+
+# Location of Kea configuration file.
+kea_config_file=@sysconfdir@/@PACKAGE@/kea.conf
+
+# Location of Kea binaries.
+exec_prefix=@exec_prefix@
+dhcp4_srv=@libexecdir@/@PACKAGE@/b10-dhcp4
+dhcp6_srv=@libexecdir@/@PACKAGE@/b10-dhcp6
+dhcp_ddns=@libexecdir@/@PACKAGE@/b10-dhcp-ddns
+
+# Start DHCPv4 server?
+dhcp4=yes
+
+# Start DHCPv6 server?
+dhcp6=yes
+
+# Be verbose?
+kea_verbose=no

+ 336 - 0
src/bin/keactrl/keactrl.in

@@ -0,0 +1,336 @@
+#!/bin/sh
+
+# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# This is keactrl script responsible for starting up Kea processes.
+# This script is used to run Kea from installation directory,
+# as well as for running tests.
+
+### Logging functions ###
+
+# Logs message at the error level.
+log_error() {
+    printf "ERROR/keactrl: ${1}\n"
+}
+
+# Logs message at the warning level.
+log_warning() {
+    printf "WARNING/keactrl: ${1}\n"
+}
+
+# Logs message at the info level.
+log_info() {
+    printf "INFO/keactrl: ${1}\n"
+}
+
+### Convenience functions ###
+
+# Checks if the value is in the list. An example usage of this function
+# is to determine whether the keactrl command belongs to the list of
+# supported commands.
+is_in_list() {
+    local member=${1}  # Value to be checked
+    local list="${2}"  # Comma separated list of items
+    _inlist=0          # Return value: 0 if not in list, 1 otherwise.
+    if [ -z ${member} ]; then
+        log_error "missing ${class}"
+    fi
+    # Iterate over all items on the list and compare with the member.
+    # If they match, return, otherwise log error and exit.
+    for item in ${list}
+    do
+        if [ ${item} = ${member} ]; then
+            _inlist=1
+            return
+        fi
+    done
+}
+
+# Prints keactrl usage.
+usage() {
+    printf "usage is %s [-c keactrl-config-file] [-s server[,server,..]]\n" $( basename ${0} )
+}
+
+### Functions managing Kea processes ###
+
+# Returns a list of existing PIDs and a number of PIDs for the process
+# having a name specified as an argument to the function.
+get_pids() {
+    local proc_name=${1}  # Process name.
+    # Return the list of PIDs.
+    _get_pids=$(ps axwwo pid,command | grep ${proc_name} | grep -v grep \
+        | awk '{print $1}')
+    # Return the number of PIDs.
+    _get_pids_num=$(printf "%s" "${_get_pids}" | wc -w | awk '{print $1}')
+}
+
+# Checks if the specified process is running. Internally it calls get_pids
+# to get the number of processes.
+check_running() {
+    local proc_name=${1} # Process name.
+    # Initially mark the process as not running.
+    _running=0
+    get_pids ${proc_name}
+    # If the number of pids is non-zero, the process is running.
+    if [ ${_get_pids_num} -gt 0 ]; then
+        _running=1
+    fi
+}
+
+# Sends a signal to a group of processes having a specified name.
+send_signal() {
+    local sig=${1}        # Signal number
+    local proc_name=${2}  # Process name.
+    # Get all PIDs for the specified process name.
+    get_pids ${proc_name}
+    # If no processes running, there is no process we can send the signal
+    # to. This is not neccessarily an error.
+    if [ -z ${_get_pids} ]; then
+        log_info "Skip sending signal ${sig} to process ${proc_name}: \
+process is not running\n"
+        return
+    fi
+    # Send a signal to all processes.
+    kill -${sig} ${_get_pids} >/dev/null 2>&1
+    if [ $? -ne 0 ]; then
+        log_error "Failed to send signal ${sig} to process ${proc_name}.\n"
+    fi
+}
+
+# Start the Kea process. Do not start the process if there is an instance
+# already running.
+start_server() {
+    binary_path=${1}   # Full path to the binary.
+    binary_args="${2}" # Arguments.
+    # Extract the name of the binary from the path.
+    local binary_name=$(basename ${binary_path})
+    # Use the binary name to check if the process is already running.
+    check_running ${binary_name}
+    # If process is running, don't start another one. Just log a message.
+    if [ ${_running} -ne 0 ]; then
+        log_info "Skip starting ${binary_name} \
+as another instance is already running."
+    else
+        log_info "Starting ${binary_name} ${args}"
+        # Start the process.
+        ${binary_path} ${args} &
+    fi
+}
+
+# Run the specified command if the server has been enabled.
+# In order for the command to run, the following conditions have to be met:
+# - server must be on the list of servers (e.g. specified from command line)
+#   or servers must contain all
+# - if check_file_cfg is non zero, the server must be enabled in the
+#   configuration file, so the variable named after server name should exist
+#   and be set to yes, e.g. ${dhcp4} should be equal to yes if server name
+#   is dhcp4
+run_conditional() {
+    local server=${1}         # Server name: dhcp4, dhcp6, dhcp_ddns
+    local command="${2}"      # Command to execute
+    local check_file_cfg=${3} # Check if server enabled in the configuration file
+
+    # If keyword "all" is not on the list of servers we will have to check
+    # if our specific server is on the list. If, not return.
+    is_in_list "all" "${servers}"
+    if [ ${_inlist} -eq 0 ]; then
+        is_in_list ${server} "${servers}"
+        if [ ${_inlist} -eq 0 ]; then
+            return
+        fi
+    fi
+
+    # Get the configuration value of the keactrl which indicates whether
+    # the server should be enabled or not. Variables that hold these values
+    # are: ${dhcp4}, ${dhcp6}, ${dhcp_ddns}.
+    local file_config=$( eval printf "%s" \${$server} )
+    # Run the command if we ignore the configuration setting or if the
+    # setting is "yes".
+    if [ ${check_file_cfg} -eq 0 ] || [ "${file_config}" = "yes" ]; then
+        ${command}
+    fi
+}
+
+### Script starts here ###
+
+# Configure logger to log messages into the file.
+# Do not set destination if the B10_LOGGER_DESTINATION is set,
+# because a unit test could have set this to some other location.
+# @todo Rely on the Kea configuration file once #3427 is done.
+if [ -z ${B10_LOGGER_DESTINATION} ]; then
+    prefix=@prefix@
+    export B10_LOGGER_DESTINATION=@localstatedir@/@PACKAGE@/kea.log
+fi
+
+command=${1}
+if [ -z ${command} ]; then
+    log_error "missing command"
+    usage
+    exit 1
+fi
+is_in_list "${command}" "start stop reload status"
+if [ ${_inlist} -eq 0 ]; then
+    log_error "invalid command: ${command}"
+    exit 1
+fi
+
+# Get the location of the keactrl configuration file.
+prefix=@prefix@
+keactrl_conf=@sysconfdir@/@PACKAGE@/keactrl.conf
+
+servers="all"
+
+shift
+while [ ! -z "${1}" ]
+do
+    option=${1}
+    case ${option} in
+        # Override keactrl configuration file.
+        -c|--ctrl-config)
+            shift
+            keactrl_conf=${1}
+            if [ -z ${keactrl_conf} ]; then
+                log_error "keactrl-config-file not specified"
+                usage
+                exit 1
+            fi
+            ;;
+        # Get the specific servers for which the command will be
+        # executed.
+        -s|--server)
+            shift
+            servers=$( printf "%s" ${1} | tr "," "\n" )
+            if [ -z ${servers} ]; then
+                log_error "servers not specified"
+                usage
+                exit 1
+            fi
+            # Validate that the specifief server names are correct.
+            for s in ${servers}
+            do
+                is_in_list "${s}" "all dhcp4 dhcp6 dhcp_ddns"
+                if [ ${_inlist} -eq 0 ]; then
+                    log_error "invalid server name: ${s}"
+                    exit 1
+                fi
+            done
+            ;;
+        *)
+            log_error "invalid option: ${option}"
+            usage
+            exit 1
+    esac
+    shift
+done
+
+# Check if the file exists. If it doesn't, it is a fatal error.
+if [ ! -f ${keactrl_conf} ]; then
+    log_error "keactrl configuration file doesn't exist in ${keactrl_conf}."
+    exit 1
+fi
+
+# Include the configuration file.
+. ${keactrl_conf}
+
+# Get location of the DHCPv4 server binary.
+if [ -z ${dhcp4_srv} ]; then
+    log_error "dhcp4_srv parameter not specified"
+    exit 1
+fi
+
+# Get location of the DHCPv6 server binary.
+if [ -z ${dhcp6_srv} ]; then
+    log_error "dhcp6_srv parameter not specified"
+    exit 1
+fi
+
+# Get location of the DHCP DDNS server binary.
+if [ -z ${dhcp_ddns} ]; then
+    log_error "dhcp_ddns parameter not specified"
+    exit 1
+fi
+
+# Check if the Kea configuration file location has been specified in the
+# keactrl configuration file. If not, it is a fatal error.
+if [ -z ${kea_config_file} ]; then
+    log_error "Configuration file for Kea not specified."
+    exit 1
+elif [ ! -f ${kea_config_file} ]; then
+    log_error "Configuration file for Kea does not exist: ${kea_config_file}."
+    exit 1
+fi
+
+# dhcp4 and dhcp6 (=yes) indicate if we should start DHCPv4 and DHCPv6 server
+# respectively.
+dhcp4=$( printf "%s" ${dhcp4} | tr [:upper:] [:lower:] )
+dhcp6=$( printf "%s" ${dhcp6} | tr [:upper:] [:lower:] )
+
+case ${command} in
+    # Start the servers.
+    start)
+        args="-c ${kea_config_file}"
+
+        if [ "${kea_verbose}" = "yes" ]; then
+            args="${args} -v"
+        fi
+
+        # Run servers if they are on the list of servers from the command line
+        # and if they are enabled in the keactrl configuration file.
+        run_conditional "dhcp4" "start_server ${dhcp4_srv} \"${args}\"" 1
+        run_conditional "dhcp6" "start_server ${dhcp6_srv} \"${args}\"" 1
+
+        exit 0 ;;
+
+    # Stop running servers.
+    stop)
+        # Stop all servers or servers specified from the command line.
+        run_conditional "dhcp4" "send_signal 15 $(basename ${dhcp4_srv})" 0
+        run_conditional "dhcp6" "send_signal 15 $(basename ${dhcp6_srv})" 0
+
+        exit 0 ;;
+
+    # Reconfigure the servers.
+    reload)
+        # Reconfigure all servers or servers specified from the command line.
+        run_conditional "dhcp4" "send_signal 1 $(basename ${dhcp4_srv})" 0
+        run_conditional "dhcp6" "send_signal 1 $(basename ${dhcp6_srv})" 0
+
+        exit 0 ;;
+
+    status)
+        kea4_status="inactive"
+        check_running $(basename ${dhcp4_srv})
+        if [ ${_running} -eq 1 ]; then
+            kea4_status="active"
+        fi
+        printf "DHCPv4 server: %s\n" ${kea4_status}
+
+        kea6_status="inactive"
+        check_running $(basename ${dhcp6_srv})
+        if [ ${_running} -eq 1 ]; then
+            kea6_status="active"
+        fi
+        printf "DHCPv6 server: %s\n" ${kea6_status}
+        printf "Kea configuration file: %s\n" ${kea_config_file}
+        printf "keactrl configuration file: %s\n" ${keactrl_conf}
+
+        exit 0 ;;
+
+    # No other commands are supported.
+    *)
+        log_error "Invalid command:  ${command}."
+        exit 1 ;;
+esac
+fi

+ 1 - 0
src/bin/keactrl/tests/.gitignore

@@ -0,0 +1 @@
+keactrl_tests.sh

+ 20 - 0
src/bin/keactrl/tests/Makefile.am

@@ -0,0 +1,20 @@
+SUBDIRS = .
+
+SHTESTS = keactrl_tests.sh
+
+noinst_SCRIPTS = keactrl_tests.sh
+
+CLEANFILES = *.log *.json
+DISTCLEANFILES = keactrl_tests.sh
+
+EXTRA_DIST = keactrl_tests.sh.in
+
+# Execute all test scripts.
+check-local:
+	for shtest in $(SHTESTS) ; do \
+	echo Running test: $$shtest ; \
+	chmod +x $(abs_builddir)/$$shtest ; \
+	export KEACTRL_BUILD_DIR=$(abs_top_builddir); \
+	export KEACTRL_CONF=$(abs_top_builddir)/src/bin/keactrl/tests/keactrl_test.conf; \
+	${SHELL} $(abs_builddir)/$$shtest || exit ; \
+	done

+ 774 - 0
src/bin/keactrl/tests/keactrl_tests.sh.in

@@ -0,0 +1,774 @@
+#!/bin/sh
+
+# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Include common test library.
+. @abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh
+
+# Set location of the keactrl.
+keactrl=@abs_top_builddir@/src/bin/keactrl/keactrl
+
+# A name of the configuration file to be used by Kea.
+CFG_FILE=@abs_top_builddir@/src/bin/keactrl/tests/test_config.json
+# A name of the keactrl config file
+KEACTRL_CFG_FILE=@abs_top_builddir@/src/bin/keactrl/tests/keactrl_test.conf
+# Path to the Kea log file.
+LOG_FILE=@abs_top_builddir@/src/bin/keactrl/tests/test.log
+# Binaries' names
+kea4_name="b10-dhcp4"
+kea6_name="b10-dhcp6"
+# Kea configuration
+config="{
+    \"Dhcp4\":
+    {
+        \"interfaces\": [ ],
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"persist\": false
+        },
+        \"subnet4\": [
+        {
+            \"subnet\": \"10.0.0.0/24\",
+            \"pool\": [ \"10.0.0.10-10.0.0.100\" ]
+        } ]
+    },
+    \"Dhcp6\":
+    {
+        \"interfaces\": [ ],
+        \"preferred-lifetime\": 3000,
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"persist\": false
+        },
+        \"subnet6\": [
+        {
+            \"subnet\": \"2001:db8:1::/64\",
+            \"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
+        } ]
+    }
+}"
+
+# Fixed part of the keactrl configuration file.
+keactrl_fixed_config="dhcp4_srv=${KEACTRL_BUILD_DIR}/src/bin/dhcp4/b10-dhcp4\n\
+dhcp6_srv=${KEACTRL_BUILD_DIR}/src/bin/dhcp6/b10-dhcp6\n\
+dhcp_ddns=${KEACTRL_BUILD_DIR}/src/bin/d2/b10-dhcp-ddns\n"
+
+# This test checks that both DHCPv4 and DHCPv6 server can be started and
+# shut down.
+start_both_servers_no_verbose_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # both DHCPv4 and DHCPv6 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=yes\nkea_verbose=no\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.start_both_servers_no_verbose_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start servers using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE} -s all\n"
+    # Append the -s option to specify all servers. This is not necessary
+    # because all should be a default but let's see if it is accepted
+    # by the command line parser.
+    ${keactrl} start -c ${KEACTRL_CFG_FILE} -s all
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # Wait up to 20s for the DHCPv6 server to configure.
+    wait_for_message 20 "DHCP6_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 20s for the DHCPv4 server to configure.
+    wait_for_message 20 "DHCP4_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that debug messages are not logged (non-verbose mode).
+    get_log_messages "DHCP6_START_INFO"
+    assert_eq 0 ${_GET_LOG_MESSAGES} \
+        "Expected get_log_messages return %d, returned %d."
+
+    # Make sure that debug messages are not logged (non-verbose mode).
+    get_log_messages "DHCP4_START_INFO"
+    assert_eq 0 ${_GET_LOG_MESSAGES} \
+        "Expected get_log_messages return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that both servers are running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Use keactrl stop to shutdown the servers.
+    printf "Stopping Kea: ${keactrl} stop  -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv6 server to stop.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 10s for the DHCPv4 server to stop.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the servers are down.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} processes running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+    test_finish 0
+}
+
+# This test checks that both DHCPv4 and DHCPv6 server can be started in
+# a verbose mode.
+start_both_servers_verbose_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # both DHCPv4 and DHCPv6 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=yes\nkea_verbose=yes\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.start_both_servers_verbose_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start servers using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # Wait up to 20s for the DHCPv6 server to configure.
+    wait_for_message 20 "DHCP6_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 20s for the DHCPv4 server to configure.
+    wait_for_message 20 "DHCP4_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Check if the debug message is present, which should only be the case if
+    # the verbose mode is on.
+    get_log_messages "DHCP6_START_INFO" 1
+    assert_eq 1 ${_GET_LOG_MESSAGES} \
+        "Expected get_log_messages for DHCP6_START_INFO return %d, returned %d."
+
+    # Check if the debug message is present, which should only be the case if
+    # the verbose mode is on.
+    get_log_messages "DHCP4_START_INFO" 1
+    assert_eq 1 ${_GET_LOG_MESSAGES} \
+        "Expected get_log_messages for DHCP4_START_INFO return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that both servers are running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Use keactrl stop to shutdown the servers.
+    printf "Stopping Kea: ${keactrl} stop -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv6 server to stop.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 10s for the DHCPv4 server to stop.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the servers are down.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} processes running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+
+    test_finish 0
+}
+
+
+# This test checks that only DHCPv4 server can be started and that the DHCPv6
+# server is not started.
+start_v4_server_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # DHCPv4 server but disables DHCPv6 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=no\nkea_verbose=no\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.start_v4_server_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start DHCPv4 server using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to retrun 0, returned value was ${ret}"
+
+    # Wait up to 20s for the DHCPv4 server to configure.
+    wait_for_message 20 "DHCP4_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that DHCPv4 server is running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    # Make sure that DHCPv6 server is not running.
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Make sure that the status command returns appropriate status.
+    printf "Getting status of Kea modules: %s\n" "${keactrl} status \
+-c ${KEACTRL_CFG_FILE}"
+    output=$( ${keactrl} status -c ${KEACTRL_CFG_FILE} )
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned %d"
+    assert_string_contains "DHCPv4 server: active" "${output}" \
+        "Expected keactrl status command return %s"
+    assert_string_contains "DHCPv6 server: inactive" "${output}" \
+        "Expected keactrl status command return %s"
+
+    # Use keactrl stop to shutdown the servers.
+    printf "Stopping Kea: ${keactrl} stop -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv4 server to stop.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the servers are down.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} processes running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+    test_finish 0
+}
+
+# This test checks that only DHCPv6 server can be started and that the DHCPv4
+# server is not started.
+start_v6_server_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # DHCPv6 server but disables DHCPv4 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=no\ndhcp6=yes\nkea_verbose=no\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.start_v6_server_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start DHCPv6 server using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # Wait up to 20s for the DHCPv6 server to configure.
+    wait_for_message 20 "DHCP6_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that DHCPv6 server is running.
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Make sure that DHCPv4 server is not running.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    # Make sure that the status command returns appropriate status.
+    printf "Getting status of Kea modules: %s\n" "${keactrl} status -c ${KEACTRL_CFG_FILE}"
+    output=$( ${keactrl} status -c ${KEACTRL_CFG_FILE} )
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned %d"
+    assert_string_contains "DHCPv4 server: inactive" "${output}" \
+        "Expected keactrl status command return %s"
+    assert_string_contains "DHCPv6 server: active" "${output}" \
+        "Expected keactrl status command return %s"
+
+    # Use keactrl stop to shutdown the servers.
+    printf "Stopping Kea: ${keactrl} stop -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv6 server to stop.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the servers are down.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} processes running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+    test_finish 0
+}
+
+# This test checks that the DHCPv6 server can be started first, and then the
+# DHCPv4 server can be started while DHCPv6 server is already running.
+# Also check that both servers can be reconfigured.
+late_start_v4_server_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # DHCPv6 server but disables DHCPv4 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=no\ndhcp6=yes\nkea_verbose=no\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.late_start_v4_server_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start DHCPv6 server using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to retrun 0, returned value was ${ret}"
+
+    # Wait up to 20s for the DHCPv6 server to configure.
+    wait_for_message 20 "DHCP6_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that DHCPv6 server is running.
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Make sure that DHCPv4 server is not running.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    # Trigger reconfiguration, make sure that the DHCPv6 server reconfigured.
+    printf "Reconfiguring the DHCPv6 server: ${keactrl} reload -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} reload -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # There should be two completed reconfigurations so far.
+    wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} "Timeout waiting for ${kea6_name} to reconfigure. \
+Expected wait_for_message to return %d, returned %d."
+
+    # Update keactrl config to enable v4 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=yes\nkea_verbose=yes\n\
+${keactrl_fixed_config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Start DHCPv4 server using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # Wait up to 20s for the DHCPv4 server to configure.
+    wait_for_message 20 "DHCP4_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that DHCPv6 server is running.
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Make sure that DHCPv4 server is running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    # Trigger reconfiguration, make sure that servers are reconfigured.
+    printf "Reconfiguring DHCPv6 and DHCPv4 servers: ${keactrl} reload \
+-c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} reload -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # There should be three completed configurations of DHCPv6 server.
+    wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 3
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} "Timeout waiting for ${kea6_name} to reconfigure. \
+Expected wait_for_message to return %d, returned %d."
+
+    # There should be two completed configurations of DHCPv4 server.
+    wait_for_message 10 "DHCP4_CONFIG_COMPLETE" 2
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} "Timeout waiting for ${kea4_name} to reconfigure. \
+Expected wait_for_message to return %d, returned %d."
+
+    # Use keactrl stop to shutdown the servers.
+    printf "Stopping Kea: ${keactrl} stop -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv6 server to stop.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 10s for the DHCPv4 server to stop.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the servers are down.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} processes running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+    test_finish 0
+}
+
+# This test checks that the DHCPv4 server can be started first, and then the
+# DHCPv6 server can be started while DHCPv4 server is already running.
+# Also check that both servers can be reconfigured.
+late_start_v6_server_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # DHCPv4 server but disables DHCPv6 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=no\nkea_verbose=yes\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.late_start_v6_server_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start DHCPv4 server using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to retrun 0, returned value was ${ret}"
+
+    # Wait up to 20s for the DHCPv4 server to configure.
+    wait_for_message 20 "DHCP4_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that DHCPv4 server is running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    # Make sure that DHCPv6 server is not running.
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Trigger reconfiguration, make sure that the DHCPv4 server is reconfigured.
+    printf "Reconfiguring the DHCPv4 server: ${keactrl} reload -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} reload -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # There should be two completed reconfigurations so far.
+    wait_for_message 10 "DHCP4_CONFIG_COMPLETE" 2
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} "Timeout waiting for ${kea4_name} to reconfigure. \
+Expected wait_for_message to return %d, returned %d."
+
+    # Update keactrl config to enable v6 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=yes\nkea_verbose=no\n\
+${keactrl_fixed_config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Start DHCPv6 server using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to retrun 0, returned value was ${ret}"
+
+    # Wait up to 20s for the DHCPv6 server to configure.
+    wait_for_message 20 "DHCP6_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that DHCPv6 server is running.
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Make sure that DHCPv4 server is running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    # Trigger reconfiguration, make sure that servers are reconfigured.
+    printf "Reconfiguring DHCPv6 and DHCPv4 servers: ${keactrl} reload \
+-c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} reload -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # There should be three completed configurations of DHCPv4 server.
+    wait_for_message 10 "DHCP4_CONFIG_COMPLETE" 3
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} "Timeout waiting for ${kea4_name} to reconfigure. \
+Expected wait_for_message to return %d, returned %d."
+
+    # There should be two completed configurations of DHCPv6 server.
+    wait_for_message 10 "DHCP6_CONFIG_COMPLETE" 2
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} "Timeout waiting for ${kea6_name} to reconfigure. \
+Expected wait_for_message to return %d, returned %d."
+
+    # Use keactrl stop to shutdown the servers.
+    printf "Stopping Kea: ${keactrl} stop -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv6 server to stop.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 10s for the DHCPv4 server to stop.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the servers are down.
+    get_pids ${kea4_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} processes running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+    test_finish 0
+}
+
+# This test checks that the servers can be shutdown selectively.
+stop_selected_server_test() {
+    # Create configuration file for keactrl. This configuration enables
+    # both DHCPv4 and DHCPv6 server.
+    keactrl_config="kea_config_file=${CFG_FILE}\ndhcp4=yes\ndhcp6=yes\nkea_verbose=no\n\
+${keactrl_fixed_config}"
+
+    test_start "keactrl.stop_selected_server_test"
+
+    # Create configuration file for Kea and for keactrl.
+    create_config "${config}"
+    create_keactrl_config "${keactrl_config}"
+
+    # Set logging to a file.
+    set_logger
+
+    # Start servers using keactrl script.
+    printf "Starting Kea: ${keactrl} start -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} start -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d"
+
+    # Wait up to 20s for the DHCPv6 server to configure.
+    wait_for_message 20 "DHCP6_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Wait up to 20s for the DHCPv4 server to configure.
+    wait_for_message 20 "DHCP4_CONFIG_COMPLETE" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to start. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that debug messages are not logged (non-verbose mode).
+    get_log_messages "DHCP6_START_INFO"
+    assert_eq 0 ${_GET_LOG_MESSAGES} \
+        "Expected get_log_messages return %d, returned %d."
+
+    # Make sure that debug messages are not logged (non-verbose mode).
+    get_log_messages "DHCP4_START_INFO"
+    assert_eq 0 ${_GET_LOG_MESSAGES} \
+        "Expected get_log_messages return %d, returned %d."
+
+    # Server may shut down imediatelly after configuration has competed.
+    # Give it some time to shutdown.
+    sleep 3
+
+    # Make sure that both servers are running.
+    get_pids ${kea4_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea4_name} process running, found %d processes running"
+
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Use keactrl stop to shutdown DHCPv4 server.
+    printf "Stopping DHCPv4 server: ${keactrl} stop -s dhcp4 -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -s dhcp4 -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv4 server to stop.
+    wait_for_message 10 "DHCP4_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea4_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure DHCPv6 server is still running
+    get_pids ${kea6_name}
+    assert_eq 1 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} process running, found %d processes running"
+
+    # Use keactrl stop to shutdown DHCPv6 server.
+    printf "Stopping DHCPv6 server: ${keactrl} stop -s dhcp6 -c ${KEACTRL_CFG_FILE}\n"
+    ${keactrl} stop -s dhcp6 -c ${KEACTRL_CFG_FILE}
+    ret=${?}
+    assert_eq 0 ${ret} "Expected keactrl to return %d, returned value was %d."
+
+    # Wait up to 10s for the DHCPv6 server to stop.
+    wait_for_message 10 "DHCP6_SHUTDOWN" 1
+    assert_eq 1 ${_WAIT_FOR_MESSAGE} \
+        "Timeout waiting for ${kea6_name} to shutdown. \
+Expected wait_for_message return %d, returned %d."
+
+    # Make sure that the DHCPv6 server is down.
+    get_pids ${kea6_name}
+    assert_eq 0 ${_GET_PIDS_NUM} \
+        "Expected %d ${kea6_name} processes running, found %d processes running"
+
+    test_finish 0
+}
+
+
+start_both_servers_no_verbose_test
+start_both_servers_verbose_test
+start_v4_server_test
+start_v6_server_test
+late_start_v4_server_test
+late_start_v6_server_test
+stop_selected_server_test
+

+ 1 - 1
src/bin/tests/process_rename_test.py.in

@@ -47,7 +47,7 @@ class TestRename(unittest.TestCase):
 
         # Scripts named in this list are not expected to be renamed and
         # should be excluded from the scan.
-        EXCLUDED_SCRIPTS = ['isc-sysinfo', 'bind10']
+        EXCLUDED_SCRIPTS = ['isc-sysinfo', 'bind10', 'keactrl']
 
         # Regexp to find all the *_SCRIPTS = something lines (except for
         # noinst_SCRIPTS, which are scripts for tests), including line

+ 1 - 0
src/lib/testutils/.gitignore

@@ -0,0 +1 @@
+/dhcp_test_lib.sh

+ 3 - 1
src/lib/testutils/Makefile.am

@@ -16,6 +16,8 @@ libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
 endif
 
 # Include common libraries being used by shell-based tests.
-SHLIBS = dhcp_test_lib.sh
+SHLIBS = dhcp_test_lib.sh.in
 
 EXTRA_DIST = portconfig.h socket_request.h $(SHLIBS)
+
+CLEANFILES = dhcp_test_lib.sh

+ 0 - 192
src/lib/testutils/dhcp_test_lib.sh

@@ -1,192 +0,0 @@
-# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-# PERFORMANCE OF THIS SOFTWARE.
-
-# The following two parameters must to be specified in a script
-# including this library.
-# - BIN - Name of the Kea executable (excluding a path), e.g. b10-dhcp6
-# - BIN_PATH - Path to the Kea executable (excluding an executable name),
-#              e.g. ../
-
-# Begins a test by prining its name.
-# It requires the ${TEST_NAME} variable to hold the test name.
-test_start() {
-    printf "\nSTART TEST ${TEST_NAME}\n"
-}
-
-# Stores the configuration specified as a parameter in the configuration
-# file which name has been set in the ${CFG_FILE} variable.
-create_config() {
-    printf "Creating Kea configuration file: %s.\n" ${CFG_FILE}
-    printf "%b" ${1} > ${CFG_FILE}
-}
-
-# Sets Kea logger to write to the file specified by the global value
-# ${LOG_FILE}.
-set_logger() {
-    printf "Kea log will be stored in %s.\n" ${LOG_FILE}
-    export B10_LOGGER_DESTINATION=${LOG_FILE}
-}
-
-# Returns the number of running process pids and the list of pids.
-_GET_PIDS=     # Return value: holds space separated list of DHCPv6 pids.
-_GET_PIDS_NUM= # Return value: holds the number of DHCPv6 server pids.
-get_pids() {
-    _GET_PIDS=`ps axwwo pid,command | grep ${BIN} | grep -v grep | awk '{print $1}'`
-    _GET_PIDS_NUM=`printf "%s" "${_GET_PIDS}" | wc -w | awk '{print $1}'`
-}
-
-# Returns the number of occurrences of the Kea log message in the
-# log file.
-_GET_LOG_MESSAGES= # Holds the number of log message occurrences.
-get_log_messages() {
-    # Grep log file for the logger message occurrences.
-    _GET_LOG_MESSAGES=`grep -o ${1} ${LOG_FILE} | wc -w`
-    # Remove whitespaces.
-    ${_GET_LOG_MESSAGES##*[! ]}
-}
-
-# Returns the number of server configurations performed so far. Also
-# returns the number of configuration errors.
-_GET_RECONFIGS=        # Return value: number of configurations so far.
-_GET_RECONFIG_ERRORS=  # Return value: number of configuration errors.
-get_reconfigs() {
-    # Grep log file for DHCP6_CONFIG_COMPLETE occurences. There should
-    # be one occurence per (re)configuration.
-    _GET_RECONFIGS=`grep -o CONFIG_COMPLETE ${LOG_FILE} | wc -w`
-    # Grep log file for DHCP6_CONFIG_LOAD_FAIL to check for configuration
-    # failures.
-    _GET_RECONFIG_ERRORS=`grep -o CONFIG_LOAD_FAIL ${LOG_FILE} | wc -w`
-    # Remove whitespaces
-    ${_GET_RECONFIGS##*[! ]}
-    ${_GET_RECONFIG_ERRORS##*[! ]}
-}
-
-# Performs cleanup for a test.
-# It shuts down running Kea processes and removes temporary files.
-# The location of the log file and the configuration file should be set
-# in the ${LOG_FILE} and ${CFG_FILE} variables recpectively, prior to
-# calling this function.
-cleanup() {
-    get_pids
-    # Shut down running Kea processes.
-    for pid in ${_GET_PIDS}
-    do
-        printf "Shutting down Kea proccess having pid %d.\n" ${pid}
-        kill -9 ${pid}
-    done
-    # Remove temporary files.
-    rm -rf ${LOG_FILE}
-    rm -rf ${CFG_FILE}
-}
-
-# Exists the test in the clean way.
-# It peformes the cleanup and prints whether the test has passed or failed.
-# If a test fails, the Kea log is dumped.
-clean_exit() {
-    exit_code=${1}  # Exit code to be returned by the exit function.
-    if [ ${exit_code} -eq 0 ]; then
-        cleanup
-        printf "PASSED ${TEST_NAME}\n\n"
-    else
-        # Dump log file if exists for debugging purposes.
-        if [ -s ${LOG_FILE} ]; then
-            printf "Log file dump:\n"
-            cat ${LOG_FILE}
-        fi
-        cleanup
-        printf "FAILED ${TEST_NAME}\n\n"
-    fi
-    exit ${exit_code}
-}
-
-# Starts Kea process in background using a configuration file specified
-# in the global variable ${CFG_FILE}
-start_kea() {
-    printf "Running command %s.\n" "\"${BIN_PATH}/${BIN} -c ${CFG_FILE}\""
-    ${BIN_PATH}/$BIN -c ${CFG_FILE} &
-}
-
-# Waits for Kea to startup with timeout.
-# This function repeatedly checs if the Kea log file has been created
-# and is non-empty. If it is, the function assumes that Kea has started.
-# It doesn't check the contents of the log file though.
-# If the log file doesn't exist the function sleeps for a second and
-# checks again. This is repeated until timeout is reached or non-empty
-# log file is found. If timeout is reached, the function reports an
-# error.
-_WAIT_FOR_KEA=0  # Return value: Holds 0 if Kea hasn't started, 1 otherwise
-wait_for_kea() {
-    timeout=${1} # Desired timeout in seconds.
-    loops=0 # Loops counter
-    _WAIT_FOR_KEA=0
-    while [ ! -s ${LOG_FILE} ] && [ ${loops} -le ${timeout} ]; do
-        printf "."
-        sleep 1
-        loops=`expr $loops + 1`
-    done
-    printf "\n"
-    if [ ${loops} -le ${timeout} ]; then
-        _WAIT_FOR_KEA=1
-    fi
-}
-
-# Waits for a specific message to occur in the Kea log file.
-# This function is called when the test expects specific message
-# to show up in the log file as a result of some action that has
-# been taken. Typically, the test expects that the message
-# is logged when the SIGHUP or SIGTERM signal has been sent to the
-# Kea process.
-# This function waits a specified number of seconds for the number
-# of message occurrences to show up. If the expected number of
-# message doesn't occur, the error status is returned.
-_WAIT_FOR_MESSAGE=0  # Return value: holds 0 if the message hasn't occured,
-                     # 1 otherwise.
-wait_for_message() {
-    timeout=${1}     # Expecte timeout value in seconds.
-    message=${2}     # Expected message id.
-    occurrences=${3} # Number of expected occurrences.
-    loops=0          # Number of loops performed so far.
-    _WAIT_FOR_MESSAGE=0
-    # Check if log file exists and if we reached timeout.
-    while [ ! -s {LOG_FILE} ] && [ ${loops} -le ${timeout} ]; do
-        printf "."
-        # Check if the message has been logged.
-        get_log_messages ${message}
-        if [ ${_GET_LOG_MESSAGES} -eq ${occurrences} ]; then
-            printf "\n"
-            _WAIT_FOR_MESSAGE=1
-            return
-        fi
-        # Message not recorded. Keep going.
-        sleep 1
-        loops=`expr ${loops} + 1`
-    done
-    printf "\n"
-    # Timeout.
-}
-
-# Sends specified signal to the Kea process.
-send_signal() {
-    sig=${1}  # Signal number.
-    # Get Kea pid.
-    get_pids
-    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
-        printf "ERROR: expected one Kea process to be started.\
- Found %d processes started.\n" ${_GET_PIDS_NUM}
-        clean_exit 1
-    fi
-    printf "Sending signal ${sig} to Kea process (pid=%s).\n" ${_GET_PIDS}
-    # Actually send a signal.
-    kill -${sig} ${_GET_PIDS}
-}

+ 358 - 0
src/lib/testutils/dhcp_test_lib.sh.in

@@ -0,0 +1,358 @@
+# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# A list of Kea processes, mainly used by the cleanup functions.
+KEA_PROCS="b10-dhcp4 b10-dhcp6 b10-dhcp-ddns"
+
+### Logging functions ###
+
+# Prints error message.
+test_lib_error() {
+    printf "ERROR/test_lib: %s\n" "${1}"
+}
+
+# Prints info message.
+test_lib_info() {
+    printf "INFO/test_lib: %s\n" "${1}"
+}
+
+### Assertions ###
+
+# Assertion that checks if two numbers are equal.
+# If numbers are not equal, the mismatched values are presented and the
+# detailed error is printed. The detailed error must use the printf
+# formatting like this:
+#    "Expected that some value 1 %d is equal to some other value %d".
+assert_eq() {
+    val1=${1}         # Reference value
+    val2=${2}         # Tested value
+    detailed_err=${3} # Detailed error format string
+    # If nothing found, present an error an exit.
+    if [ ${val1} -ne ${val2} ]; then
+        printf "Assertion failure: ${val1} != ${val2}, for val1=${val1}, val2=${val2}\n"
+        printf "${detailed_err}\n" ${val1} ${val2}
+        clean_exit 1
+    fi
+}
+
+# Assertion that checks if one string contains another string.
+# If assertion fails, both strings are displayed and the detailed
+# error is printed. The detailed error must use the printf formatting
+# like this:
+#    "Expected some string to contain this string: %s".
+assert_string_contains() {
+    pattern=${1}      # Substring or awk pattern
+    text=${2}         # Text to be searched for substring
+    detailed_err=${3} # Detailed error format string
+    # Search for a pattern
+    match=$( printf "%s" "${text}" | awk /"${pattern}"/ )
+    # If nothing found, present an error and exit.
+    if [ -z "${match}" ]; then
+        printf "Assertion failure: \n\"%s\"\n\ndoesn't contain pattern:\n
+\"%s\"\n\n" "${text}" "${pattern}"
+        printf "${detailed_err}\n" "\"${pattern}\""
+        clean_exit 1
+    fi
+}
+
+# Begins a test by prining its name.
+test_start() {
+    TEST_NAME=${1}
+    if [ -z ${TEST_NAME} ]; then
+        test_lib_error "test_start requires test name as an argument"
+        clean_exit 1
+    fi
+    printf "\nSTART TEST ${TEST_NAME}\n"
+}
+
+# Prints test result an cleans up after the test.
+test_finish() {
+    local exit_code=${1}  # Exit code to be returned by the exit function.
+    if [ ${exit_code} -eq 0 ]; then
+        cleanup
+        printf "PASSED ${TEST_NAME}\n\n"
+    else
+        # Dump log file if exists for debugging purposes.
+        if [ -s ${LOG_FILE} ]; then
+            printf "Log file dump:\n"
+            cat ${LOG_FILE}
+        fi
+        cleanup
+        printf "FAILED ${TEST_NAME}\n\n"
+    fi
+}
+
+# Stores the configuration specified as a parameter in the configuration
+# file which name has been set in the ${CFG_FILE} variable.
+create_config() {
+    local cfg=${1}  # Configuration string.
+    if [ -z ${CFG_FILE} ]; then
+        test_lib_error "create_config requires CFG_FILE variable be set"
+        clean_exit 1
+
+    elif [ -z "${cfg}" ]; then
+        test_lib_error "create_config requires argument holding a configuration"
+        clean_exit 1
+    fi
+    printf "Creating Kea configuration file: %s.\n" ${CFG_FILE}
+    printf "%b" ${cfg} > ${CFG_FILE}
+}
+
+# Stores the keactrl configuration specified as a parameter in the
+# configuration file which name has been set in the ${KEACTRL_CFG_FILE}
+# variable.
+create_keactrl_config() {
+    local cfg=${1} # Configuration string.
+    if [ -z ${KEACTRL_CFG_FILE} ]; then
+        test_lib_error "create_keactrl_config requires KEACTRL_CFG_FILE \
+variable be set"
+        clean_exit 1
+
+    elif [ -z "${cfg}" ]; then
+        test_lib_error "create_keactrl_config requires argument holding a \
+configuration"
+        clean_exit 1
+    fi
+    printf "Creating keactrl configuration file: %s.\n" ${KEACTRL_CFG_FILE}
+    printf "%b" ${cfg} > ${KEACTRL_CFG_FILE}
+}
+
+# Sets Kea logger to write to the file specified by the global value
+# ${LOG_FILE}.
+set_logger() {
+    if [ -z ${LOG_FILE} ]; then
+        test_lib_error "set_logger requies LOG_FILE variable be set"
+        clean_exit 1
+    fi
+    printf "Kea log will be stored in %s.\n" ${LOG_FILE}
+    export B10_LOGGER_DESTINATION=${LOG_FILE}
+}
+
+# Returns the number of running process pids and the list of pids.
+# Return values:
+#   _GET_PIDS: holds space separated list of pids.
+#   _GET_PIDS_NUM: holds the number pids.
+get_pids() {
+    local proc_name=${1} # Process name
+    if [ -z ${proc_name} ]; then
+        test_lib_error "get_pids requires process name"
+        clean_exit 1
+    fi
+    _GET_PIDS=$( ps axwwo pid,command | grep ${proc_name} \
+        | grep -v grep | awk '{print $1}' )
+    _GET_PIDS_NUM=$( printf "%s" "${_GET_PIDS}" | wc -w | awk '{print $1}' )
+}
+
+# Returns the number of occurrences of the Kea log message in the log file.
+# Return value:
+#   _GET_LOG_MESSAGES: number of log message occurrences.
+get_log_messages() {
+    local msg=${1}  # Message id, e.g. DHCP6_SHUTDOWN
+    if [ -z ${msg} ]; then
+        test_lib_error "get_log_messages require message identifier"
+        clean_exit 1
+    fi
+    _GET_LOG_MESSAGES=0
+    # If log file is not present, the number of occurrences is 0.
+    if [ -s ${LOG_FILE} ]; then
+        # Grep log file for the logger message occurrences.
+        _GET_LOG_MESSAGES=$( grep -o ${msg} ${LOG_FILE} | wc -w )
+        # Remove whitespaces.
+        ${_GET_LOG_MESSAGES##*[! ]}
+    fi
+}
+
+# Returns the number of server configurations performed so far. Also
+# returns the number of configuration errors.
+# Return values:
+#   _GET_RECONFIGS: number of configurations so far.
+#   _GET_RECONFIG_ERRORS: number of configuration errors.
+get_reconfigs() {
+    # Grep log file for CONFIG_COMPLETE occurences. There should
+    # be one occurence per (re)configuration.
+    _GET_RECONFIGS=$( grep -o CONFIG_COMPLETE ${LOG_FILE} | wc -w )
+    # Grep log file for CONFIG_LOAD_FAIL to check for configuration
+    # failures.
+    _GET_RECONFIG_ERRORS=$( grep -o CONFIG_LOAD_FAIL ${LOG_FILE} | wc -w )
+    # Remove whitespaces
+    ${_GET_RECONFIGS##*[! ]}
+    ${_GET_RECONFIG_ERRORS##*[! ]}
+}
+
+# Performs cleanup after test.
+# It shuts down running Kea processes and removes temporary files.
+# The location of the log file and the configuration files should be set
+# in the ${LOG_FILE}, ${CFG_FILE} and ${KEACTRL_CFG_FILE} variables
+# recpectively, prior to calling this function.
+cleanup() {
+    # KEA_PROCS holds the name of all Kea processes. Shut down each
+    # of them if running.
+    for proc_name in ${KEA_PROCS}
+    do
+        get_pids ${proc_name}
+        # Shut down running Kea processes.
+        for pid in ${_GET_PIDS}
+        do
+            printf "Shutting down Kea proccess having pid %d.\n" ${pid}
+            kill -9 ${pid}
+        done
+    done
+    # Remove temporary files.
+    rm -rf ${LOG_FILE}
+    rm -rf ${CFG_FILE}
+    rm -rf ${KEACTRL_CFG_FILE}
+}
+
+# Exists the test in the clean way.
+# It peformes the cleanup and prints whether the test has passed or failed.
+# If a test fails, the Kea log is dumped.
+clean_exit() {
+    exit_code=${1}  # Exit code to be returned by the exit function.
+    case ${exit_code} in
+        ''|*[!0-9]*)
+            test_lib_error "argument passed to clean_exit must be a number" ;;
+    esac
+    # Print test result and perform a cleanup
+    test_finish ${exit_code}
+    exit ${exit_code}
+}
+
+# Starts Kea process in background using a configuration file specified
+# in the global variable ${CFG_FILE}.
+start_kea() {
+    local bin=${1}
+    if [ -z ${bin} ]; then
+        test_lib_error "binary name must be specified for start_kea"
+        clean_exit 1
+    fi
+    printf "Running command %s.\n" "\"${bin} -c ${CFG_FILE}\""
+    ${bin} -c ${CFG_FILE} &
+}
+
+# Waits with timeout for Kea to start.
+# This function repeatedly checs if the Kea log file has been created
+# and is non-empty. If it is, the function assumes that Kea has started.
+# It doesn't check the contents of the log file though.
+# If the log file doesn't exist the function sleeps for a second and
+# checks again. This is repeated until timeout is reached or non-empty
+# log file is found. If timeout is reached, the function reports an
+# error.
+# Return value:
+#    _WAIT_FOR_KEA: 0 if Kea hasn't started, 1 otherwise
+wait_for_kea() {
+    local timeout=${1} # Desired timeout in seconds.
+    case ${timeout} in
+        ''|*[!0-9]*)
+            test_lib_error "argument passed to wait_for_kea must be a number"
+            clean_exit 1 ;;
+    esac
+    local loops=0 # Loops counter
+    _WAIT_FOR_KEA=0
+    while [ ! -s ${LOG_FILE} ] && [ ${loops} -le ${timeout} ]; do
+        printf "."
+        sleep 1
+        loops=$( expr $loops + 1 )
+    done
+    printf "\n"
+    if [ ${loops} -le ${timeout} ]; then
+        _WAIT_FOR_KEA=1
+    fi
+}
+
+# Waits for a specific message to occur in the Kea log file.
+# This function is called when the test expects specific message
+# to show up in the log file as a result of some action that has
+# been taken. Typically, the test expects that the message
+# is logged when the SIGHUP or SIGTERM signal has been sent to the
+# Kea process.
+# This function waits a specified number of seconds for the number
+# of message occurrences to show up. If the expected number of
+# message doesn't occur, the error status is returned.
+# Return value:
+#    _WAIT_FOR_MESSAGE: 0 if the message hasn't occured, 1 otherwise.
+wait_for_message() {
+    local timeout=${1}     # Expected timeout value in seconds.
+    local message=${2}     # Expected message id.
+    local occurrences=${3} # Number of expected occurrences.
+
+    # Validate timeout
+    case ${timeout} in
+        ''|*[!0-9]*)
+            test_lib_error "argument timeout passed to wait_for_message must \
+be a number"
+        clean_exit 1 ;;
+    esac
+
+    # Validate message
+    if [ -z ${message} ]; then
+        test_lib_error "message id is a required argument for wait_for_message"
+        clean_exit 1
+    fi
+
+    # Validate occurrences
+    case ${occurrences} in
+        ''|*[!0-9]*)
+            test_lib_error "argument occurrences passed to wait_for_message \
+must be a number"
+        clean_exit 1 ;;
+    esac
+
+    local loops=0          # Number of loops performed so far.
+    _WAIT_FOR_MESSAGE=0
+    # Check if log file exists and if we reached timeout.
+    while [ ${loops} -le ${timeout} ]; do
+        printf "."
+        # Check if the message has been logged.
+        get_log_messages ${message}
+        if [ ${_GET_LOG_MESSAGES} -ge ${occurrences} ]; then
+            printf "\n"
+            _WAIT_FOR_MESSAGE=1
+            return
+        fi
+        # Message not recorded. Keep going.
+        sleep 1
+        loops=$( expr ${loops} + 1 )
+    done
+    printf "\n"
+    # Timeout.
+}
+
+# Sends specified signal to the Kea process.
+send_signal() {
+    local sig=${1}       # Signal number.
+    local proc_name=${2} # Process name
+
+    # Validate signal
+    case ${sig} in
+        ''|*[!0-9]*)
+            test_lib_error "signal number passed to send_signal \
+must be a number"
+        clean_exit 1 ;;
+    esac
+    # Validate process name
+    if [ -z ${proc_name} ]; then
+        test_lib_error "send_signal requires process name be passed as argument"
+        clean_exit 1
+    fi
+    # Get Kea pid.
+    get_pids ${proc_name}
+    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+        printf "ERROR: expected one Kea process to be started.\
+ Found %d processes started.\n" ${_GET_PIDS_NUM}
+        clean_exit 1
+    fi
+    printf "Sending signal ${sig} to Kea process (pid=%s).\n" ${_GET_PIDS}
+    # Actually send a signal.
+    kill -${sig} ${_GET_PIDS}
+}