dhcp_test_lib.sh.in 22.9 KB
Newer Older
Francis Dupont's avatar
Francis Dupont committed
1
# Copyright (C) 2014-2015,2017 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
}

91
92
# Begins a test by prining its name.
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
# Stores the keactrl configuration specified as a parameter in the
# configuration file which name has been set in the ${KEACTRL_CFG_FILE}
# variable.
138
create_keactrl_config() {
139
    local cfg="${1}" # Configuration string.
140
141
142
143
144
145
146
147
148
149
    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
150
    printf "Creating keactrl configuration file: %s.\n" ${KEACTRL_CFG_FILE}
151
    printf "%b" ${cfg} > ${KEACTRL_CFG_FILE}
152
153
}

154
155
156
# Sets Kea logger to write to the file specified by the global value
# ${LOG_FILE}.
set_logger() {
157
158
159
160
    if [ -z ${LOG_FILE} ]; then
        test_lib_error "set_logger requies LOG_FILE variable be set"
        clean_exit 1
    fi
161
    printf "Kea log will be stored in %s.\n" ${LOG_FILE}
162
    export KEA_LOGGER_DESTINATION=${LOG_FILE}
163
164
}

165
# PID file path is by default <kea-install-dir>/var/kea, but can be
Josh Soref's avatar
Josh Soref committed
166
# overridden by the environmental variable.
167
168
169
170
171
PID_FILE_PATH=@localstatedir@/@PACKAGE@/
if [ ! -z ${KEA_PIDFILE_DIR} ]; then
    PID_FILE_PATH="${KEA_PIDFILE_DIR}"
fi

172
173
174
175
176
# 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
177
# and their names should match the following pattern:
178
179
180
181
# <cfg_file_name>.<proc_name>.pid. If the <cfg_file_name> is not
# specified a 'test_config' is used by default.
#
# Return value:
182
#   _GET_PID: holds a PID if process is running
183
#   _GET_PIDS_NUM: holds 1 if process is running, 0 otherwise
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
}

218
219
220
221
222
223
# 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.
224
kill_processes_by_name() {
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    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
}

240
241
242
# Returns the number of occurrences of the Kea log message in the log file.
# Return value:
#   _GET_LOG_MESSAGES: number of log message occurrences.
243
get_log_messages() {
244
    local msg="${1}"  # Message id, e.g. DHCP6_SHUTDOWN
245
246
247
248
    if [ -z ${msg} ]; then
        test_lib_error "get_log_messages require message identifier"
        clean_exit 1
    fi
249
    _GET_LOG_MESSAGES=0
250
    # If log file is not present, the number of occurrences is 0.
251
    if [ -s ${LOG_FILE} ]; then
252
253
254
        # 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 " ")
255
    fi
256
257
258
259
}

# Returns the number of server configurations performed so far. Also
# returns the number of configuration errors.
260
261
262
# Return values:
#   _GET_RECONFIGS: number of configurations so far.
#   _GET_RECONFIG_ERRORS: number of configuration errors.
263
get_reconfigs() {
Francis Dupont's avatar
Francis Dupont committed
264
265
    # Grep log file for CONFIG_COMPLETE occurrences. There should
    # be one occurrence per (re)configuration.
266
267
    _GET_RECONFIGS=$( grep -o CONFIG_COMPLETE ${LOG_FILE} | wc -w )
    # Grep log file for CONFIG_LOAD_FAIL to check for configuration
268
    # failures.
269
    _GET_RECONFIG_ERRORS=$( grep -o CONFIG_LOAD_FAIL ${LOG_FILE} | wc -w )
270
271
272
273
274
    # Remove whitespaces
    ${_GET_RECONFIGS##*[! ]}
    ${_GET_RECONFIG_ERRORS##*[! ]}
}

275
# Performs cleanup after test.
276
# It shuts down running Kea processes and removes temporary files.
277
# The location of the log file and the configuration files should be set
278
279
# in the ${LOG_FILE}, ${CFG_FILE} and ${KEACTRL_CFG_FILE} variables
# recpectively, prior to calling this function.
280
cleanup() {
281
282
283
284
285
286

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

287
288
    # KEA_PROCS holds the name of all Kea processes. Shut down each
    # of them if running.
289
    for proc_name in ${KEA_PROCS}
290
    do
291
292
293
294
295
296
        get_pid ${proc_name}
        # Shut down running Kea process.
        if [ ${_GET_PIDS_NUM} -ne 0 ]; then
            printf "Shutting down Kea proccess having pid %d.\n" ${_GET_PID}
            kill -9 ${_GET_PID}
        fi
297
    done
298

299
300
301
302
303
304
305
    # 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.
306
    kill_processes_by_name "kea-lfc"
307

308
309
    # Remove temporary files.
    rm -rf ${LOG_FILE}
310
311
312
    # 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.
313
314
315
    if [ ! -z "${LEASE_FILE}" ]; then
        rm -rf ${LEASE_FILE}*
    fi
316
    rm -rf ${CFG_FILE}
317
    rm -rf ${KEACTRL_CFG_FILE}
318
319
320
}

# Exists the test in the clean way.
Josh Soref's avatar
Josh Soref committed
321
# It performs the cleanup and prints whether the test has passed or failed.
322
323
# If a test fails, the Kea log is dumped.
clean_exit() {
324
    exit_code=${1}  # Exit code to be returned by the exit function.
325
326
327
328
    case ${exit_code} in
        ''|*[!0-9]*)
            test_lib_error "argument passed to clean_exit must be a number" ;;
    esac
329
330
    # Print test result and perform a cleanup
    test_finish ${exit_code}
331
    exit ${exit_code}
332
333
334
}

# Starts Kea process in background using a configuration file specified
335
# in the global variable ${CFG_FILE}.
336
start_kea() {
337
    local bin=${1}
338
339
340
341
342
343
    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} &
344
345
}

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

436
437
# Waits for server to be down.
# Return value:
Francis Dupont's avatar
Francis Dupont committed
438
#    _WAIT_FOR_SERVER_DOWN: 1 if server is down, 0 if timeout occurred and the
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
#                             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 "."
454
        get_pid ${proc_name}
455
456
457
458
459
460
461
462
463
464
465
        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"
}

466
467
# Sends specified signal to the Kea process.
send_signal() {
468
469
470
471
472
473
474
    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 \
475
must be a number"
476
477
478
479
480
481
482
        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
483
    # Get Kea pid.
484
    get_pid ${proc_name}
485
    if [ ${_GET_PIDS_NUM} -ne 1 ]; then
486
487
        printf "ERROR: expected one Kea process to be started.\
 Found %d processes started.\n" ${_GET_PIDS_NUM}
488
        clean_exit 1
489
    fi
490
    printf "Sending signal ${sig} to Kea process (pid=%s).\n" ${_GET_PID}
491
    # Actually send a signal.
492
    kill -${sig} ${_GET_PID}
493
}
494

495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
# 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

516
    # Only the file name portion of the config file is used, try and
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
    # 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
549
# This test verifies that the binary is reporting its version properly.
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
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
}
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599

# 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.
600
    get_pid ${bin}
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
    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.
632
    get_pid ${bin}
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
    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
}
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
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

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