summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomek Mrugalski <tomasz@isc.org>2017-05-18 20:25:10 +0200
committerTomek Mrugalski <tomasz@isc.org>2017-05-18 20:25:10 +0200
commit647226b8454a755b85e814a15f49716fcc8acadd (patch)
treea7a1026ae350e39534a540237c4448085112e54f
parent8508ee43aeee58c57c51e22e5fb4c811cc5a99e6 (diff)
downloadisc-dhcp-647226b8454a755b85e814a15f49716fcc8acadd.tar.gz
[19430] Initial framework for shell unit-tests added.
-rw-r--r--tests/Makefile.am17
-rw-r--r--tests/shell/dhclient_tests.sh89
-rw-r--r--tests/shell/dhcp_test_lib.sh682
3 files changed, 787 insertions, 1 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9c6c650e..de90d81a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,10 +24,25 @@ EXTRA_DIST = failover/dhcp-1.cf failover/dhcp-2.cf failover/new-failover \
DHCPv6/stubcli-opt-in-na.pl DHCPv6/stubcli.pl \
DHCPv6/test-a.conf DHCPv6/test-b.conf \
HOWTO-unit-test \
- unit_test_sample.c
+ unit_test_sample.c \
+ shell/dhclient_tests.sh \
+ shell/dhcp_test_lib.sh
AM_CPPFLAGS = -I..
check_LIBRARIES = libt_api.a
libt_api_a_SOURCES = t_api.c t_api_dhcp.c
+# Let's start with an empty list of shell tests.
+SHTESTS =
+
+# Let's add dhclient tests. In the future, it will be possible to specify
+# whether those tests should run or not.
+SHTESTS += shell/dhclient_tests.sh
+
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+ @for shtest in $(SHTESTS) ; do \
+ echo Running test: $$shtest ; \
+ ${SHELL} $(abs_builddir)/$$shtest || exit ; \
+ done
diff --git a/tests/shell/dhclient_tests.sh b/tests/shell/dhclient_tests.sh
new file mode 100644
index 00000000..668c0fd0
--- /dev/null
+++ b/tests/shell/dhclient_tests.sh
@@ -0,0 +1,89 @@
+# Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPECTED_VERSION="isc-dhclient-4.4.0-dev"
+
+# dhclient configuration. Currently empty, but future tests may use it.
+CONFIG="#nothing"
+
+CFG_FILE=/home/thomson/devel/dhcp-git/tests/dhclient.conf
+
+# Temporary log file. Make sure this location is writeable.
+LOG_FILE=/home/thomson/devel/dhcp-git/tests/dhclient.log
+
+LEASE_FILE=/home/thomson/devel/dhcp-git/tests/dhclient.leases
+
+PID_FILE=/home/thomson/devel/dhcp-git/tests/dhclient.pid
+
+IFACE=lo
+
+bin="dhclient"
+bin_path=/home/thomson/devel/dhcp-git/client
+
+# Import common test library.
+. /home/thomson/devel/dhcp-git/tests/shell/dhcp_test_lib.sh
+
+# This test verifies that dhclient shuts 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}
+
+ if [ "$EUID" -ne 0 ]; then
+ printf "This test requires to be run as root, skipping.\n"
+ test_finish 2
+ return
+ fi
+
+ # Remove dangling instances and remove log files.
+ cleanup
+
+ # Create new configuration file.
+ create_config "${CONFIG}"
+
+ # Start Control Agent.
+ start_kea ${bin_path}/${bin}
+ # Wait up to 5s for Control Agent to start.
+ wait_for_kea 5
+ if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+ printf "ERROR: timeout waiting for dhclient 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_pid ${bin}
+ if [ ${_GET_PIDS_NUM} -ne 1 ]; then
+ printf "ERROR: expected one dhclient 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.
+ check_client_started
+ if [ ${_CHECK_CLIENT_STARTED} -ne 1 ]; then
+ printf "ERROR: client start failed.\n"
+ clean_exit 1
+ else
+ printf "dhclient started successfully.\n"
+ fi
+
+ # Send signal to Control Agent (SIGTERM, SIGINT etc.)
+ send_signal ${signum} ${bin}
+
+ # Make sure the server is down.
+ wait_for_process_down 5 ${bin}
+ assert_eq 1 ${_WAIT_FOR_PROCESS_DOWN} \
+ "Expected wait_for_server_down return %d, returned %d"
+
+ test_finish 0
+}
+
+version_test "dhclient.version"
+shutdown_test "dhclient.sigterm" 15
diff --git a/tests/shell/dhcp_test_lib.sh b/tests/shell/dhcp_test_lib.sh
new file mode 100644
index 00000000..3052f052
--- /dev/null
+++ b/tests/shell/dhcp_test_lib.sh
@@ -0,0 +1,682 @@
+# Copyright (C) 2014-2015,2017 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# A list of processes, mainly used by the cleanup functions.
+PROCS="dhcpd dhclient"
+
+# colors if not outputting to a dumb terminal and stdout is a tty
+if test "$TERM" != dumb && { test -t 1; } 2>/dev/null; then \
+ red='\033[0;31m'
+ green='\033[0;32m'
+ noclr='\033[0m'
+
+ # if echo supports -e, we must use it to set colors
+ # (output will be "" if its supported)
+ if [ -z "`echo -e`" ]
+ then
+ dash_e="-e"
+ fi
+fi;
+
+### Logging functions ###
+
+# Prints error message.
+test_lib_error() {
+ local s=${1} # Error message.
+ local no_new_line=${2} # If specified, the message not terminated with
+ # new line.
+ printf "ERROR/test_lib: %s" "${s}"
+ if [ -z ${no_new_line} ]; then
+ printf "%s" "\n"
+ fi
+
+}
+
+# Prints info message.
+test_lib_info() {
+ local s=${1} # Info message.
+ local no_new_line=${2} # If specified, the message is not terminated with
+ # new line.
+ printf "INFO/test_lib: %s" "${s}"
+ if [ -z ${no_new_line} ]; then
+ printf "%s" "\n"
+ fi
+}
+
+### 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 two strings 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_str_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}" != "${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 "\n\e[1;34m%-6s\e[m\n" "START TEST ${TEST_NAME}"
+}
+
+# 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 "\e[1;32m%-6s\e[m\n\n" "PASSED ${TEST_NAME}"
+ else
+ if [ ${exit_code} -eq 2 ]; then
+ cleanup
+ printf "\e[1;33m%-6s\e[m\n\n" "SKIPPED ${TEST_NAME}"
+ else
+ # Dump log file for debugging purposes if specified and exists.
+ # Otherwise the code below would simply call cat.
+ if [ -n "${LOG_FILE}" -a -s "${LOG_FILE}" ]; then
+ printf "Log file dump:\n"
+ cat ${LOG_FILE}
+ fi
+ cleanup
+ printf "\e[1;31m%-6s\e[m\n\n" "FAILED ${TEST_NAME}"
+ fi
+ 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 configuration file: %s.\n" ${CFG_FILE}
+ printf "%b" ${cfg} > ${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 "Log will be stored in %s.\n" ${LOG_FILE}
+ export KEA_LOGGER_DESTINATION=${LOG_FILE}
+}
+
+# PID file path is by default <kea-install-dir>/var/kea, but can be
+# overriden by the environmental variable.
+PID_FILE_PATH=${prefix}/var/kea/
+if [ ! -z ${KEA_PIDFILE_DIR} ]; then
+ PID_FILE_PATH="${KEA_PIDFILE_DIR}"
+fi
+
+# Checks if specified process is running.
+#
+# This function uses PID file to obtain the PID and then calls
+# 'kill -0 <pid>' to check if the process is alive.
+# The PID files are expected to be located in the ${PID_FILE}.
+#
+# Return value:
+# _GET_PID: holds a PID if process is running
+# _GET_PIDS_NUM: holds 1 if process is running, 0 otherwise
+get_pid() {
+ local proc_name=${1} # Process name
+
+ # PID file name includes process name. The process name is required.
+ if [ -z ${proc_name} ]; then
+ test_lib_error "get_pid requires process name"
+ clean_exit 1
+ fi
+
+ # Get the absolute location of the PID file for the specified process
+ # name.
+ abs_pidfile_path="${PID_FILE}"
+ _GET_PID=0
+ _GET_PIDS_NUM=0
+
+ # If the PID file exists, get the PID and see if the process is alive.
+ if [ -e ${abs_pidfile_path} ]; then
+ pid=$( cat $abs_pidfile_path )
+ kill -0 ${pid} > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ _GET_PID=${pid}
+ _GET_PIDS_NUM=1
+ fi
+ fi
+}
+
+# Kills processes specified by name.
+#
+# This function kills all processes having a specified name.
+# It uses 'pgrep' to obtain pids of those processes.
+# This function should be used when identifying process by
+# the value in its PID file is not relevant.
+kill_processes_by_name() {
+ local proc_name=${1} # Process name
+ if [ -z ${proc_name} ]; then
+ test_lib_error "get_pids requires process name"
+ clean_exit 1
+ fi
+ # Obtain PIDs of running processes.
+ local pids=$( pgrep ${proc_name} )
+ # For each PID found, send kill signal.
+ for pid in ${pids}
+ do
+ printf "Shutting down Kea process ${proc_name} having pid %d.\n" ${pid}
+ kill -9 ${pid}
+ done
+}
+
+# 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 and remove
+ # whitespaces, if any.
+ _GET_LOG_MESSAGES=$( grep -o ${msg} ${LOG_FILE} | wc -w | tr -d " ")
+ fi
+}
+
+# Returns the number of server configurations performed so far. Also
+# returns the number of configuration errors.
+# Return values:
+# _CHECK_CLIENT_STARTED: number of configurations so far.
+# _CHECK_CLIENT_EXIT: number of configuration errors.
+check_client_started() {
+ # Grep log file for CONFIG_COMPLETE occurrences. There should
+ # be one occurrence per (re)configuration.
+ _CHECK_CLIENT_STARTED=$( grep -o "Listening on " ${LOG_FILE} | wc -l )
+ # Grep log file for CONFIG_LOAD_FAIL to check for configuration
+ # failures.
+ _CHECK_CLIENT_EXIT=$( grep -o "exiting" ${LOG_FILE} | wc -l )
+ # Remove whitespaces
+ ${_CHECK_CLIENT_STARTED##*[! ]}
+ ${_CHECK_CLIENT_EXIT##*[! ]}
+}
+
+# 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} variables recpectively, prior to calling
+# this function.
+cleanup() {
+
+ # If there is no PROCS set, just return
+ if [ -z "${PROCS}" ]; then
+ return
+ fi
+
+ # PROCS holds the name of all processes. Shut down each of them if running.
+ for proc_name in ${PROCS}
+ do
+ get_pid ${proc_name}
+ # Shut down running Kea process.
+ if [ ${_GET_PIDS_NUM} -ne 0 ]; then
+ printf "Shutting down proccess having pid %d.\n" ${_GET_PID}
+ kill -9 ${_GET_PID}
+ fi
+ done
+
+ # Remove temporary files.
+ #rm -rf ${LOG_FILE}
+ # Use asterisk to remove all files starting with the given name,
+ # in case the LFC has been run. LFC creates files with postfixes
+ # appended to the lease file name.
+ if [ ! -z "${LEASE_FILE}" ]; then
+ rm -rf ${LEASE_FILE}*
+ fi
+ rm -rf ${CFG_FILE}
+}
+
+# Exists the test in the clean way.
+# It performes 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 a process in background using a configuration file specified
+# in the global variable ${CFG_FILE} (with logging to ${LOG_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} -cf ${CFG_FILE}\ -lf ${LEASE_FILE} -pf ${PID_FILE} -d ${IFACE} &> ${LOG_FILE}\""
+ ${bin} -cf ${CFG_FILE} -lf ${LEASE_FILE} -pf ${PID_FILE} -d ${IFACE} &> ${LOG_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
+ test_lib_info "wait_for_kea " "skip-new-line"
+ 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 occurred, 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
+ test_lib_info "wait_for_message ${message}: " "skip-new-line"
+ # 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.
+}
+
+# Waits for server to be down.
+# Return value:
+# _WAIT_FOR_PROCESS_DOWN: 1 if server is down, 0 if timeout occurred and the
+# server is still running.
+wait_for_process_down() {
+ local timeout=${1} # Timeout specified in seconds.
+ local proc_name=${2} # Server process name.
+
+ case ${timeout} in
+ ''|*[!0-9]*)
+ test_lib_error "argument passed to wait_for_process_down must be a number"
+ clean_exit 1 ;;
+ esac
+ local loops=0 # Loops counter
+ _WAIT_FOR_PROCESS_DOWN=0
+ test_lib_info "wait_for_process_down ${proc_name}: " "skip-new-line"
+ while [ ${loops} -le ${timeout} ]; do
+ printf "."
+ get_pid ${proc_name}
+ if [ ${_GET_PIDS_NUM} -eq 0 ]; then
+ printf "\n"
+ _WAIT_FOR_PROCESS_DOWN=1
+ return
+ fi
+ sleep 1
+ loops=$( expr $loops + 1 )
+ done
+ printf "\n"
+}
+
+# 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_pid ${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_PID}
+ # Actually send a signal.
+ kill -${sig} ${_GET_PID}
+}
+
+# Verifies that a server is up running by its PID file
+# The PID file is constructed from the given config file name and
+# binary name. If it exists and the PID it contains refers to a
+# live process it sets _SERVER_PID_FILE and _SERVER_PID to the
+# corresponding values. Otherwise, it emits an error and exits.
+verify_server_pid() {
+ local bin_name="${1}" # binary name of the server
+ local cfg_file="${2}" # config file name
+
+ # We will construct the PID file name based on the server config
+ # and binary name
+ if [ -z ${bin_name} ]; then
+ test_lib_error "verify_server_pid requires binary name"
+ clean_exit 1
+ fi
+
+ if [ -z ${cfg_file} ]; then
+ test_lib_error "verify_server_pid requires config file name"
+ clean_exit 1
+ fi
+
+ # Only the file name portion of the config file is used, try and
+ # extract it. NOTE if this "algorithm" changes this code will need
+ # to be updated.
+ fname=`basename ${cfg_file}`
+ fname=`echo $fname | cut -f1 -d'.'`
+
+ if [ -z ${fname} ]; then
+ test_lib_error "verify_server_pid could not extract config name"
+ clean_exit 1
+ fi
+
+ # Now we can build the name:
+ pid_file="$KEA_PIDFILE_DIR/$fname.$bin_name.pid"
+
+ if [ ! -e ${pid_file} ]; then
+ printf "ERROR: PID file:[%s] does not exist\n" ${pid_file}
+ clean_exit 1
+ fi
+
+ # File exists, does its PID point to a live process?
+ pid=`cat ${pid_file}`
+ kill -0 ${pid}
+ if [ $? -ne 0 ]; then
+ printf "ERROR: PID file:[%s] exists but PID:[%d] does not\n" \
+ ${pid_file} ${pid}
+ clean_exit 1
+ fi
+
+ # Make the values accessible to the caller
+ _SERVER_PID="${pid}"
+ _SERVER_PID_FILE="${pid_file}"
+}
+
+# This test verifies that the binary is reporting its version properly.
+version_test() {
+ test_name=${1} # Test name
+
+ # Log the start of the test and print test name.
+ test_start ${test_name}
+
+ # Remove dangling Kea instances and remove log files.
+ cleanup
+
+ REPORTED_VERSION="`${bin_path}/${bin} --version 2>&1`"
+
+ if test "${REPORTED_VERSION}" == "${EXPECTED_VERSION}"; then
+ test_finish 0
+ else
+ printf "ERROR: Expected version ${EXPECTED_VERSION}, got ${REPORTED_VERSION}\n"
+ test_finish 1
+ fi
+}
+
+# This test verifies that the server is using logger variable
+# KEA_LOCKFILE_DIR properly (it should be used to point out to the directory,
+# where lockfile should be created. Also, "none" value means to not create
+# the lockfile at all).
+logger_vars_test() {
+ test_name=${1} # Test name
+
+ # Log the start of the test and print test name.
+ test_start ${test_name}
+ # Remove dangling Kea instances and remove log files.
+ cleanup
+
+ # Create bogus configuration file. We don't really want the server to start,
+ # just want it to log something and die. Empty config is an easy way to
+ # enforce that behavior.
+ create_config "{ }"
+ printf "Please ignore any config error messages.\n"
+
+ # Remember old KEA_LOCKFILE_DIR
+ KEA_LOCKFILE_DIR_OLD=${KEA_LOCKFILE_DIR}
+
+ # Set lockfile directory to current directory.
+ KEA_LOCKFILE_DIR=.
+
+ # Start Kea.
+ start_kea ${bin_path}/${bin}
+
+ # Wait for Kea to process the invalid configuration and die.
+ sleep 1
+
+ # Check if it is still running. It should have terminated.
+ get_pid ${bin}
+ if [ ${_GET_PIDS_NUM} -ne 0 ]; then
+ printf "ERROR: expected Kea process to not start. Found %d processes"
+ printf " running.\n" ${_GET_PIDS_NUM}
+
+ # Revert to the old KEA_LOCKFILE_DIR value
+ KEA_LOCKFILE_DIR=${KEA_LOCKFILE_DIR_OLD}
+ clean_exit 1
+ fi
+
+ if [ ! -f "./logger_lockfile" ]; then
+ printf "ERROR: Expect ${bin} to create logger_lockfile in the\n"
+ printf "current directory, but no such file exists.\n"
+
+ # Revert to the old KEA_LOCKFILE_DIR value
+ KEA_LOCKFILE_DIR=${KEA_LOCKFILE_DIR__OLD}
+ clean_exit 1
+ fi
+
+ # Remove the lock file
+ rm -f ./logger_lockfile
+
+ # Tell Kea to NOT create logfiles at all
+ KEA_LOCKFILE_DIR="none"
+
+ # Start Kea.
+ start_kea ${bin_path}/${bin}
+
+ # Wait for Kea to process the invalid configuration and die.
+ sleep 1
+
+ # Check if it is still running. It should have terminated.
+ get_pid ${bin}
+ if [ ${_GET_PIDS_NUM} -ne 0 ]; then
+ printf "ERROR: expected Kea process to not start. Found %d processes"
+ printf " running.\n" ${_GET_PIDS_NUM}
+
+ # Revert to the old KEA_LOCKFILE_DIR value
+ KEA_LOCKFILE_DIR=${KEA_LOCKFILE_DIR_OLD}
+
+ clean_exit 1
+ fi
+
+ if [ -f "./logger_lockfile" ]; then
+ printf "ERROR: Expect ${bin} to NOT create logger_lockfile in the\n"
+ printf "current directory, but the file exists."
+
+ # Revert to the old KEA_LOCKFILE_DIR value
+ KEA_LOCKFILE_DIR=${KEA_LOCKFILE_DIR_OLD}
+
+ clean_exit 1
+ fi
+
+ # Revert to the old KEA_LOCKFILE_DIR value
+ printf "Reverting KEA_LOCKFILE_DIR to ${KEA_LOCKFILE_DIR_OLD}\n"
+ KEA_LOCKFILE_DIR=${KEA_LOCKFILE_DIR_OLD}
+
+ test_finish 0
+}
+
+# This test verifies server PID file management
+# 1. It verifies that upon startup, the server creates a PID file
+# 2. It verifies the an attempt to start a second instance fails
+# due to pre-existing PID File/PID detection
+server_pid_file_test() {
+ local server_cfg="${1}"
+ local log_id="${2}"
+
+ # Log the start of the test and print test name.
+ test_start "${bin}.server_pid_file_test"
+ # Remove dangling DHCP4 instances and remove log files.
+ cleanup
+ # Create new configuration file.
+ create_config "${CONFIG}"
+ # Instruct server to log to the specific file.
+ set_logger
+ # Start server
+ start_kea ${bin_path}/${bin}
+ # Wait up to 20s for server to start.
+ wait_for_kea 20
+ if [ ${_WAIT_FOR_KEA} -eq 0 ]; then
+ printf "ERROR: timeout waiting for %s to start.\n" ${bin}
+ clean_exit 1
+ fi
+
+ # Verify server is still running
+ verify_server_pid ${bin} ${CFG_FILE}
+
+ printf "PID file is [%s], PID is [%d]" ${_SERVER_PID_FILE} ${_SERVER_PID}
+
+ # Now try to start a second one
+ start_kea ${bin_path}/${bin}
+
+ wait_for_message 10 "${log_id}" 1
+ if [ ${_WAIT_FOR_MESSAGE} -eq 0 ]; then
+ printf "ERROR: Second %s instance started? PID conflict not reported.\n" ${bin}
+ clean_exit 1
+ fi
+
+ # Verify server is still running
+ verify_server_pid ${bin} ${CFG_FILE}
+
+ # All ok. Shut down the server and exit.
+ test_finish 0
+}