dhcp_test_lib.sh.in 23.6 KB
Newer Older
1
# Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
2
#
3 4 5
# 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/.
6

7
# A list of Kea processes, mainly used by the cleanup functions.
8
KEA_PROCS="kea-dhcp4 kea-dhcp6 kea-dhcp-ddns kea-ctrl-agent"
9

10 11 12 13
### Logging functions ###

# Prints error message.
test_lib_error() {
14 15 16 17 18 19 20 21
    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

22 23 24 25
}

# Prints info message.
test_lib_info() {
26 27 28 29 30 31 32
    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
33 34 35 36
}

### Assertions ###

37 38 39 40 41
# 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".
42
assert_eq() {
43 44 45 46
    val1=${1}         # Reference value
    val2=${2}         # Tested value
    detailed_err=${3} # Detailed error format string
    # If nothing found, present an error an exit.
47 48 49 50 51 52 53
    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
}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
# 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
}

71 72 73 74 75 76
# 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() {
77 78 79
    pattern="${1}"      # Substring or awk pattern
    text="${2}"         # Text to be searched for substring
    detailed_err="${3}" # Detailed error format string
80 81 82 83 84 85 86 87 88 89 90
    # 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
}

Josh Soref's avatar
Josh Soref committed
91
# Begins a test by printing its name.
92
test_start() {
93 94 95 96 97
    TEST_NAME=${1}
    if [ -z ${TEST_NAME} ]; then
        test_lib_error "test_start requires test name as an argument"
        clean_exit 1
    fi
98 99 100
    printf "\nSTART TEST ${TEST_NAME}\n"
}

101
# Prints test result an cleans up after the test.
102
test_finish() {
103
    local exit_code=${1}  # Exit code to be returned by the exit function.
104 105 106 107
    if [ ${exit_code} -eq 0 ]; then
        cleanup
        printf "PASSED ${TEST_NAME}\n\n"
    else
108 109 110
        # 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
111 112 113 114 115 116 117 118
            printf "Log file dump:\n"
            cat ${LOG_FILE}
        fi
        cleanup
        printf "FAILED ${TEST_NAME}\n\n"
    fi
}

119 120 121
# Stores the configuration specified as a parameter in the configuration
# file which name has been set in the ${CFG_FILE} variable.
create_config() {
122
    local cfg="${1}"  # Configuration string.
123 124 125 126 127 128 129 130
    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
131
    printf "Creating Kea configuration file: %s.\n" ${CFG_FILE}
132
    printf "%b" ${cfg} > ${CFG_FILE}
133 134
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
# Stores the netconf configuration specified as a parameter in the
# configuration file which name has been set in the ${NETCONF_CFG_FILE}
# variable.
create_netconf_config() {
    local cfg="${1}"  # Configuration string.
    if [ -z ${NETCONF_CFG_FILE} ]; then
        test_lib_error "create_netconf_config requires NETCONF_CFG_FILE \
variable be set"
        clean_exit 1

    elif [ -z "${cfg}" ]; then
        test_lib_error "create_netconf_config requires argument holding a \
configuration"
        clean_exit 1
    fi
    printf "Creating Netconf configuration file: %s.\n" ${NETCONF_CFG_FILE}
    printf "%b" ${cfg} > ${NETCONF_CFG_FILE}
}

154 155 156
# Stores the keactrl configuration specified as a parameter in the
# configuration file which name has been set in the ${KEACTRL_CFG_FILE}
# variable.
157
create_keactrl_config() {
158
    local cfg="${1}" # Configuration string.
159 160 161 162 163 164 165 166 167 168
    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
169
    printf "Creating keactrl configuration file: %s.\n" ${KEACTRL_CFG_FILE}
170
    printf "%b" ${cfg} > ${KEACTRL_CFG_FILE}
171 172
}

173 174 175
# Sets Kea logger to write to the file specified by the global value
# ${LOG_FILE}.
set_logger() {
176
    if [ -z ${LOG_FILE} ]; then
Josh Soref's avatar
Josh Soref committed
177
        test_lib_error "set_logger requires LOG_FILE variable be set"
178 179
        clean_exit 1
    fi
180
    printf "Kea log will be stored in %s.\n" ${LOG_FILE}
181
    export KEA_LOGGER_DESTINATION=${LOG_FILE}
182 183
}

184
# PID file path is by default <kea-install-dir>/var/kea, but can be
Josh Soref's avatar
Josh Soref committed
185
# overridden by the environmental variable.
186 187 188 189 190
PID_FILE_PATH=@localstatedir@/@PACKAGE@/
if [ ! -z ${KEA_PIDFILE_DIR} ]; then
    PID_FILE_PATH="${KEA_PIDFILE_DIR}"
fi

191 192 193 194 195
# 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_PATH},
Francis Dupont's avatar
Francis Dupont committed
196
# and their names should match the following pattern:
197 198 199 200
# <cfg_file_name>.<proc_name>.pid. If the <cfg_file_name> is not
# specified a 'test_config' is used by default.
#
# Return value:
201
#   _GET_PID: holds a PID if process is running
202
#   _GET_PIDS_NUM: holds 1 if process is running, 0 otherwise
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
get_pid() {
    local proc_name=${1}     # Process name
    local cfg_file_name=${2} # Configuration file name without extension.

    # 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

    # PID file name includes server configuration file name. For most of
    # the tests it is 'test-config' (excluding .json extension). It is
    # possible to specify custom name if required.
    if [ -z ${cfg_file_name} ]; then
        cfg_file_name="test_config"
    fi

    # Get the absolute location of the PID file for the specified process
    # name.
    abs_pidfile_path="${PID_FILE_PATH}/${cfg_file_name}.${proc_name}.pid"
    _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
}

237 238 239 240 241 242
# 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.
243
kill_processes_by_name() {
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    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
}

259 260 261
# Returns the number of occurrences of the Kea log message in the log file.
# Return value:
#   _GET_LOG_MESSAGES: number of log message occurrences.
262
get_log_messages() {
263
    local msg="${1}"  # Message id, e.g. DHCP6_SHUTDOWN
264 265 266 267
    if [ -z ${msg} ]; then
        test_lib_error "get_log_messages require message identifier"
        clean_exit 1
    fi
268
    _GET_LOG_MESSAGES=0
269
    # If log file is not present, the number of occurrences is 0.
270
    if [ -s ${LOG_FILE} ]; then
271 272 273
        # 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 " ")
274
    fi
275 276 277 278
}

# Returns the number of server configurations performed so far. Also
# returns the number of configuration errors.
279 280 281
# Return values:
#   _GET_RECONFIGS: number of configurations so far.
#   _GET_RECONFIG_ERRORS: number of configuration errors.
282
get_reconfigs() {
Francis Dupont's avatar
Francis Dupont committed
283 284
    # Grep log file for CONFIG_COMPLETE occurrences. There should
    # be one occurrence per (re)configuration.
285 286
    _GET_RECONFIGS=$( grep -o CONFIG_COMPLETE ${LOG_FILE} | wc -w )
    # Grep log file for CONFIG_LOAD_FAIL to check for configuration
287
    # failures.
288
    _GET_RECONFIG_ERRORS=$( grep -o CONFIG_LOAD_FAIL ${LOG_FILE} | wc -w )
289 290 291 292 293
    # Remove whitespaces
    ${_GET_RECONFIGS##*[! ]}
    ${_GET_RECONFIG_ERRORS##*[! ]}
}

294
# Performs cleanup after test.
295
# It shuts down running Kea processes and removes temporary files.
296
# The location of the log file and the configuration files should be set
297
# in the ${LOG_FILE}, ${CFG_FILE} and ${KEACTRL_CFG_FILE} variables
Josh Soref's avatar
Josh Soref committed
298
# respectively, prior to calling this function.
299
cleanup() {
300 301 302 303 304 305

    # If there is no KEA_PROCS set, just return
    if [ -z "${KEA_PROCS}" ]; then
        return
    fi

306 307
    # KEA_PROCS holds the name of all Kea processes. Shut down each
    # of them if running.
308
    for proc_name in ${KEA_PROCS}
309
    do
310 311 312
        get_pid ${proc_name}
        # Shut down running Kea process.
        if [ ${_GET_PIDS_NUM} -ne 0 ]; then
Josh Soref's avatar
Josh Soref committed
313
            printf "Shutting down Kea process having pid %d.\n" ${_GET_PID}
314 315
            kill -9 ${_GET_PID}
        fi
316
    done
317

318 319 320 321 322 323 324
    # Kill any running LFC processes. Even though 'kea-lfc' creates PID
    # file we rather want to use 'pgrep' to find the process PID, because
    # kea-lfc execution is not controlled from the test and thus there
    # is possibility that process is already/still running but the PID
    # file doesn't exist for it. As a result, the process will not
    # be killed. This is not a problem for other processes because
    # tests control launching them and monitor when they are shut down.
325
    kill_processes_by_name "kea-lfc"
326

327 328
    # Remove temporary files.
    rm -rf ${LOG_FILE}
329
    rm -rf ${LOG_FILE}.lock
330 331 332
    # 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.
333 334 335
    if [ ! -z "${LEASE_FILE}" ]; then
        rm -rf ${LEASE_FILE}*
    fi
336
    rm -rf ${CFG_FILE}
337
    rm -rf ${KEACTRL_CFG_FILE}
338 339 340
}

# Exists the test in the clean way.
Josh Soref's avatar
Josh Soref committed
341
# It performs the cleanup and prints whether the test has passed or failed.
342 343
# If a test fails, the Kea log is dumped.
clean_exit() {
344
    exit_code=${1}  # Exit code to be returned by the exit function.
345 346 347 348
    case ${exit_code} in
        ''|*[!0-9]*)
            test_lib_error "argument passed to clean_exit must be a number" ;;
    esac
349 350
    # Print test result and perform a cleanup
    test_finish ${exit_code}
351
    exit ${exit_code}
352 353 354
}

# Starts Kea process in background using a configuration file specified
355
# in the global variable ${CFG_FILE}.
356
start_kea() {
357
    local bin=${1}
358 359 360 361 362 363
    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} &
364 365
}

366
# Waits with timeout for Kea to start.
Josh Soref's avatar
Josh Soref committed
367
# This function repeatedly checks if the Kea log file has been created
368
# and is non-empty. If it is, the function assumes that Kea has started.
369
# It doesn't check the contents of the log file though.
370 371 372 373
# 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.
374 375
# Return value:
#    _WAIT_FOR_KEA: 0 if Kea hasn't started, 1 otherwise
376
wait_for_kea() {
377 378 379 380 381 382 383
    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
384
    _WAIT_FOR_KEA=0
385
    test_lib_info "wait_for_kea " "skip-new-line"
386 387 388
    while [ ! -s ${LOG_FILE} ] && [ ${loops} -le ${timeout} ]; do
        printf "."
        sleep 1
389
        loops=$( expr $loops + 1 )
390 391 392 393 394 395 396 397 398 399 400 401 402
    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.
403 404 405
# 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.
406
# Return value:
Francis Dupont's avatar
Francis Dupont committed
407
#    _WAIT_FOR_MESSAGE: 0 if the message hasn't occurred, 1 otherwise.
408
wait_for_message() {
409
    local timeout=${1}     # Expected timeout value in seconds.
410
    local message="${2}"   # Expected message id.
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
    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.
436
    _WAIT_FOR_MESSAGE=0
437
    test_lib_info "wait_for_message ${message}: " "skip-new-line"
438
    # Check if log file exists and if we reached timeout.
439
    while [ ${loops} -le ${timeout} ]; do
440
        printf "."
441 442
        # Check if the message has been logged.
        get_log_messages ${message}
443
        if [ ${_GET_LOG_MESSAGES} -ge ${occurrences} ]; then
444
            printf "\n"
445
            _WAIT_FOR_MESSAGE=1
446 447 448 449
            return
        fi
        # Message not recorded. Keep going.
        sleep 1
450
        loops=$( expr ${loops} + 1 )
451 452 453 454 455
    done
    printf "\n"
    # Timeout.
}

456 457
# Waits for server to be down.
# Return value:
Francis Dupont's avatar
Francis Dupont committed
458
#    _WAIT_FOR_SERVER_DOWN: 1 if server is down, 0 if timeout occurred and the
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
#                             server is still running.
wait_for_server_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_server_down must be a number"
            clean_exit 1 ;;
    esac
    local loops=0 # Loops counter
    _WAIT_FOR_SERVER_DOWN=0
    test_lib_info "wait_for_server_down ${proc_name}: " "skip-new-line"
    while [ ${loops} -le ${timeout} ]; do
        printf "."
474
        get_pid ${proc_name}
475 476 477 478 479 480 481 482 483 484 485
        if [ ${_GET_PIDS_NUM} -eq 0 ]; then
            printf "\n"
            _WAIT_FOR_SERVER_DOWN=1
            return
        fi
        sleep 1
        loops=$( expr $loops + 1 )
    done
    printf "\n"
}

486 487
# Sends specified signal to the Kea process.
send_signal() {
488 489 490 491 492 493 494
    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 \
495
must be a number"
496 497 498 499 500 501 502
        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
503
    # Get Kea pid.
504
    get_pid ${proc_name}
505
    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
506 507
        printf "ERROR: expected one Kea process to be started.\
 Found %d processes started.\n" ${_GET_PIDS_NUM}
508
        clean_exit 1
509
    fi
510
    printf "Sending signal ${sig} to Kea process (pid=%s).\n" ${_GET_PID}
511
    # Actually send a signal.
512
    kill -${sig} ${_GET_PID}
513
}
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
# 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

536
    # Only the file name portion of the config file is used, try and
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
    # 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}"
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
569
# This test verifies that the binary is reporting its version properly.
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
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} -v`"

    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
}
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619

# 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.
620
    get_pid ${bin}
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
    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.
652
    get_pid ${bin}
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    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
}
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724

# 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
}