#!/bin/sh

# Copyright (C) 2017-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

# Test suite for Dhcp6
test_suite="dhcp6"

# Path to the temporary configuration file.
# shellcheck disable=SC2034
# SC2034: ... appears unused. Verify use (or export if used externally).
# reason: used in dhcp_test_lib.sh.in
CFG_FILE="@abs_top_builddir@/src/bin/shell/tests/test_config.json"

# Path to the Kea lease file.
export KEA_DHCP_DATA_DIR="@abs_top_builddir@/src/bin/shell/tests"
LEASE_FILE="@abs_top_builddir@/src/bin/shell/tests/test_leases.csv"

# Path to the Dhcp6 Server log file.
export KEA_LOG_FILE_DIR="@abs_top_builddir@/src/bin/shell/tests"
LOG_FILE="@abs_top_builddir@/src/bin/shell/tests/test.log"

# Dhcp6 Server configuration to be stored in the configuration file.
# todo: use actual configuration once we support it.
CONFIG="{
    \"Dhcp6\":
    {
        \"control-sockets\": [
        {
            \"socket-type\": \"http\",
            \"socket-address\": \"127.0.0.1\",
            \"socket-port\": 8081
        }
        ],
        \"interfaces-config\": {
           \"interfaces\": [ ]
        },
        \"server-id\": {
          \"type\": \"LLT\",
          \"persist\": false
        },
        \"preferred-lifetime\": 3000,
        \"valid-lifetime\": 4000,
        \"renew-timer\": 1000,
        \"rebind-timer\": 2000,
        \"lease-database\":
        {
            \"type\": \"memfile\",
            \"name\": \"$LEASE_FILE\",
            \"persist\": true,
            \"lfc-interval\": 0
        },
        \"subnet6\": [
        {
            \"id\": 1,
            \"subnet\": \"2001:db8:1::/64\",
            \"pools\": [ { \"pool\": \"2001:db8:1::10-2001:db8:1::100\" } ]
        } ],
        \"ddns-qualifying-suffix\": \"\",
        \"dhcp-ddns\": {
            \"enable-updates\": true
        },
        \"loggers\": [
        {
            \"name\": \"kea-dhcp6\",
            \"output-options\": [
                {
                    \"output\": \"$LOG_FILE\"
                }
            ],
            \"severity\": \"DEBUG\"
        }
        ]
    }
}"

# In these tests we need to use two binaries: Dhcp6 Server and Kea shell.
# Using bin and bin_path would be confusing, so we omit defining bin
# and bin_path on purpose.
dhcp6_bin="kea-dhcp6"
dhcp6_bin_path="@abs_top_builddir@/src/bin/dhcp6"

shell_bin="kea-shell"
shell_bin_path="@abs_top_builddir@/src/bin/shell"

tmpfile_path="@abs_top_builddir@/src/bin/shell/tests"

# 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 Dhcp6 Server is shut down gracefully when it
# receives a SIGINT or SIGTERM signal.
shell_command_test() {
    test_name=${1}  # Test name
    cmd=${2}        # Command to be sent
    exp_rsp=${3}    # Expected response
    params=${4}     # Any extra parameters

    # Setup phase: start Dhcp6.

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

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

    # Instruct Dhcp6 Server to log to the specific file.
    set_logger
    # Start Dhcp6 Server.
    start_kea ${dhcp6_bin_path}/${dhcp6_bin}
    # Wait up to 20s for Dhcp6 Server to start.
    wait_for_kea 20
    if [ "${_WAIT_FOR_KEA}" -eq 0 ]; then
        printf "ERROR: timeout waiting for Dhcp6 Server 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 "${dhcp6_bin}"
    if [ "${_GET_PIDS_NUM}" -ne 1 ]; then
        printf "ERROR: expected one Dhcp6 Server 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

    # Main test phase: send command, check response.
    tmp="echo \"${params}\" | ${shell_bin_path}/${shell_bin} --host \
 127.0.0.1 --port 8081 ${cmd} > ${tmpfile_path}/shell-stdout.txt"
    echo "Executing kea-shell ($tmp)"

    echo "${params}" | ${shell_bin_path}/${shell_bin} --host 127.0.0.1 \
 --port 8081 "${cmd}" > ${tmpfile_path}/shell-stdout.txt
    shell_exit_code=$?

    # Check the exit code
    if [ "${shell_exit_code}" -ne 0 ]; then
        echo "ERROR:" \
        "kea-shell returned ${shell_exit_code} exit code, expected 0."
    else
        echo "kea-shell returned ${shell_exit_code} exit code as expected."
    fi

    # Now check the response
    rm -f ${tmpfile_path}/shell-expected.txt
    printf '%s\n' "${exp_rsp}" > ${tmpfile_path}/shell-expected.txt
    diff ${tmpfile_path}/shell-stdout.txt ${tmpfile_path}/shell-expected.txt
    diff_code=$?
    if [ "${diff_code}" -ne 0 ]; then
        echo "ERROR:" \
        "content returned is different than expected." \
        "See ${tmpfile_path}/shell-*.txt"
        echo "EXPECTED:"
        cat ${tmpfile_path}/shell-expected.txt
        echo "ACTUAL RESULT:"
        cat ${tmpfile_path}/shell-stdout.txt
        clean_exit 1
    else
        echo "Content returned by kea-shell meets expectation."
        rm ${tmpfile_path}/shell-*.txt
    fi
    # Main test phase ends.

    # Cleanup phase: shutdown Dhcp6
    # Send SIGTERM signal to Dhcp6 Server
    send_signal 15 ${dhcp6_bin}

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

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

    test_finish 0
}

# 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_suite}-${test_name}"

    REPORTED_VERSION=$(${shell_bin_path}/${shell_bin} -v)

    if test "${REPORTED_VERSION}" = "${EXPECTED_VERSION}"; then
        test_finish 0
    else
        echo "ERROR:" \
        "Expected version ${EXPECTED_VERSION}, got ${REPORTED_VERSION}"
        test_finish 1
    fi
}

version_test "shell.version"
shell_command_test "shell.list-commands" "list-commands" \
    "[ { \"arguments\": [ \"build-report\", \"config-backend-pull\", \"config-get\", \"config-hash-get\", \"config-reload\", \"config-set\", \"config-test\", \"config-write\", \"dhcp-disable\", \"dhcp-enable\", \"leases-reclaim\", \"list-commands\", \"server-tag-get\", \"shutdown\", \"statistic-get\", \"statistic-get-all\", \"statistic-remove\", \"statistic-remove-all\", \"statistic-reset\", \"statistic-reset-all\", \"statistic-sample-age-set\", \"statistic-sample-age-set-all\", \"statistic-sample-count-set\", \"statistic-sample-count-set-all\", \"status-get\", \"subnet6-select-test\", \"version-get\" ], \"result\": 0 } ]" ""
shell_command_test "shell.bogus" "give-me-a-beer" \
"[ { \"result\": 2, \"text\": \"'give-me-a-beer' command not supported.\" } ]" ""
shell_command_test "shell.empty-config-test" "config-test" \
    "[ { \"result\": 1, \"text\": \"Missing mandatory 'arguments' parameter.\" } ]" ""
shell_command_test "shell.no-app-config-test" "config-test" \
    "[ { \"result\": 1, \"text\": \"Missing mandatory 'Dhcp6' parameter.\" } ]" \
    "\"FooBar\": { }"
shell_command_test "shell.no-map-config-test" "config-test" \
    "[ { \"result\": 1, \"text\": \"'Dhcp6' parameter expected to be a map.\" } ]" \
    "\"Dhcp6\": [ ]"
shell_command_test "shell.bad-value-config-test" "config-test" \
    "[ { \"result\": 1, \"text\": \"out of range value 80000 specified for parameter 'socket-port' (<string>:1:116)\" } ]" \
    "\"Dhcp6\": { \"control-sockets\": [ { \"socket-type\": \"http\", \"socket-port\": 80000 } ] }"
