#!/bin/sh

# Copyright (C) 2018-2025 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/.

# Exit with error if commands exit with non-zero and if undefined variables are
# used.
set -eu

# Path to the temporary configuration file.
CFG_FILE="@abs_top_builddir@/src/bin/netconf/tests/shtests/test_config.json"
# Path to the Kea log file.
export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/netconf/tests/shtests"
LOG_FILE="@abs_top_builddir@/src/bin/netconf/tests/shtests/test.log"

# Kea-netconf configuration to be stored in the configuration file.
CONFIG="{
    \"Netconf\":
    {
        \"managed-servers\":
        {
            \"dhcp4\":
            {
                \"comment\": \"simply use defaults...\"
            }
        },
        \"loggers\": [
        {
            \"name\": \"kea-netconf\",
            \"output-options\": [
                {
                    \"output\": \"$LOG_FILE\"
                }
            ],
            \"severity\": \"INFO\"
        }
        ]
    }
}"

# Invalid configuration (syntax error) to check that Kea can check syntax.
CONFIG_BAD_SYNTAX="{
    \"Netconf\":
    {
        \"boot-update\": BOGUS
    }
}"

# Invalid configuration (invalid url) to check that Kea can check syntax.
CONFIG_BAD_VALUE="{
    \"Netconf\":
    {
        \"managed-servers\":
        {
            \"dhcp4\":
            {
                \"control-socket\":
                {
                    \"socket-type\": \"http\",
                    \"socket-url\": \"BOGUS\"
                }
            }
        }
    }
}"

# Set the location of the executable.
bin="kea-netconf"
bin_path="@abs_top_builddir@/src/bin/netconf"

# Import common test library.
# shellcheck source=src/lib/testutils/dhcp_test_lib.sh.in
. "@abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh"

# This test verifies that help can be printed out.
usage_test() {
    local test_name="${1}"
    local parameter="${2}"
    local expected_code="${3}"

    # Log the start of the test and print test name.
    test_start "${test_name}"

    # Create correct configuration file.
    create_config "${CONFIG}"

    # Check it
    printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\""
    run_command \
        "${bin_path}/${bin}" "${parameter}"
    if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
        printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
        clean_exit 1
    fi
    test_finish 0
}

# This test verifies that no argument is not reported as a PID file error.
no_argument_test() {
    local test_name="${1}"
    local expected_code="${2}"

    # Log the start of the test and print test name.
    test_start "${test_name}"

    # Check it
    printf "Running command %s.\n" "\"${bin_path}/${bin}\""
    run_command \
        "${bin_path}/${bin}"
    if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
        printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
        clean_exit 1
    fi
    test_finish 0
}

# This test verifies that syntax checking works properly. This function
# requires 3 parameters:
# test_name
# config - string with a content of the config (will be written to a file)
# expected_code - expected exit code returned by kea (0 - success, 1 - failure)
syntax_check_test() {
    local test_name="${1}"
    local config="${2}"
    local expected_code="${3}"

    # Log the start of the test and print test name.
    test_start "${test_name}"
    # Create correct configuration file.
    create_config "${config}"
    # Check it
    printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\""
    run_command \
        "${bin_path}/${bin}" -t "${CFG_FILE}"
    if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
        printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
        clean_exit 1
    fi
    test_finish 0
}

# This test verifies that Netconf Agent 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}"
    # Create new configuration file.
    create_config "${CONFIG}"
    # Instruct Netconf Agent to log to the specific file.
    set_logger
    # Start Netconf Agent.
    start_kea "${bin_path}/${bin}"
    # Wait up to 20s for Netconf Agent to start.
    wait_for_kea 20
    if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
        printf "ERROR: timeout waiting for Netconf Agent 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 Netconf Agent 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 been configured %s time(s), but exactly 1 was expected.\n" "${_GET_RECONFIGS}"
        clean_exit 1
    else
        printf "Server successfully configured.\n"
    fi

    # Send signal to Netconf Agent (SIGTERM, SIGINT etc.)
    send_signal "${signum}" "${bin}"

    # Now wait for process to log that it is exiting.
    wait_for_message 10 "DCTL_SHUTDOWN" 1
    if [ "${_WAIT_FOR_MESSAGE}" -eq 0 ]; then
        printf "ERROR: Netconf Agent did not log shutdown.\n"
        clean_exit 1
    fi

    # Make sure the server is down.
    wait_for_server_down 5 "${bin}"
    assert_eq 1 "${_WAIT_FOR_SERVER_DOWN}" \
        "Expected wait_for_server_down return %d, returned %d"

    test_finish 0
}

version_test "netconf.version"
usage_test "netconf.invalid-param" "-f" 1
usage_test "netconf.dash-h" "-h" 1
usage_test "netconf.dash-v" "-v" 0
no_argument_test "netconf.no-argument" 1
shutdown_test "netconf.sigterm_test" 15
shutdown_test "netconf.sigint_test" 2
logger_vars_test "netconf.variables"
syntax_check_test "netconf.syntax_check_success" "${CONFIG}" 0
syntax_check_test "netconf.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1
syntax_check_test "netconf.syntax_check_bad_values" "${CONFIG_BAD_VALUE}" 1
