# Shared helpers for the ntpd-rs autopkgtests.
#
# ntpd-rs ships the following binaries and units:
#   /usr/bin/ntp-daemon            (ntpd-rs.service)
#   /usr/bin/ntp-ctl
#   /usr/bin/ntp-metrics-exporter  (ntpd-rs-metrics.service)
# The default configuration lives in /etc/ntpd-rs/ntp.toml and exposes an
# observation socket in /run/ntpd-rs/observe.

NTPD_RS_CONFIG="/etc/ntpd-rs/ntp.toml"
NTPD_RS_SERVICE="ntpd-rs.service"
NTPD_RS_METRICS_SERVICE="ntpd-rs-metrics.service"
NTPD_RS_OBSERVE_SOCKET="/run/ntpd-rs/observe"
NTPD_RS_METRICS_ENDPOINT="127.0.0.1:9975"

# Binaries shipped by the packages.
NTPD_RS_DAEMON_BIN="/usr/bin/ntp-daemon"
NTPD_RS_CTL_BIN="/usr/bin/ntp-ctl"
NTPD_RS_METRICS_BIN="/usr/bin/ntp-metrics-exporter"

# Offline configuration used to keep the tests fully self-contained.
NTPD_RS_OFFLINE_CONFIG="/etc/ntpd-rs/ntp-autopkgtest-offline.toml"
NTPD_RS_DROPIN_DIR="/etc/systemd/system/${NTPD_RS_SERVICE}.d"

# Point the packaged ntpd-rs.service at the offline configuration via a systemd
# drop-in.
__install_offline_config() {
    cat > "${NTPD_RS_OFFLINE_CONFIG}" <<EOF
[observability]
log-level = "info"
observation-path = "${NTPD_RS_OBSERVE_SOCKET}"
EOF
    mkdir -p "${NTPD_RS_DROPIN_DIR}"
    cat > "${NTPD_RS_DROPIN_DIR}/10-autopkgtest-offline.conf" <<EOF
[Service]
ExecStart=
ExecStart=/usr/bin/ntp-daemon -c ${NTPD_RS_OFFLINE_CONFIG}

[Unit]
ConditionVirtualization=
EOF
    systemctl daemon-reload
}

__show_logs() {
    lines=100
    echo "## Something failed, gathering logs"
    echo
    echo "## Last ${lines} of dmesg:"
    dmesg -T | tail -n ${lines} || :
    echo
    echo "## Last ${lines} of the ntpd-rs journal:"
    journalctl -n ${lines} --full -u "${NTPD_RS_SERVICE}" || :
    echo
    echo "## Last ${lines} of the ntpd-rs-metrics journal:"
    journalctl -n ${lines} --full -u "${NTPD_RS_METRICS_SERVICE}" || :
    echo
    echo "## Content of /etc/ntpd-rs/"
    find /etc/ntpd-rs -ls || :
}

__cleanup() {
    result=$?
    set +e
    if [ ${result} -ne 0 ]; then
        __show_logs
    fi
    rm -f "${NTPD_RS_OFFLINE_CONFIG}"
    rm -rf "${NTPD_RS_DROPIN_DIR}"
    systemctl daemon-reload
}

__test_fail() {
    printf 'FAIL\n' >&2
    return 1
}

__test_ok() {
    printf 'OK\n'
    return 0
}

__test_skip() {
    [ -n "$1" ] && printf 'SKIP: (%s)\n' "$1" || printf 'SKIP\n'
    exit 77
}

__restart_ntpd_rs() {
    systemctl restart "${NTPD_RS_SERVICE}" || return 1
    systemctl is-active --quiet "${NTPD_RS_SERVICE}"
}

# Wait up to ~30s for the observation socket to appear.
__wait_for_observe_socket() {
    for _ in $(seq 1 30); do
        [ -S "${NTPD_RS_OBSERVE_SOCKET}" ] && return 0
        sleep 1
    done
    return 1
}

# Print the value (last field) of the first Prometheus sample line matching the
# extended regex $1, read from stdin. Prints nothing when there is no match.
__metric_value() {
    awk -v re="$1" '$0 ~ re { print $NF; exit }'
}

# Succeed when the numeric argument $1 is strictly greater than zero.
__is_positive() {
    awk -v v="$1" 'BEGIN { exit !(v + 0 > 0) }'
}

# Poll "ntp-ctl status -f prometheus" for the given config ($1) until a sample
# whose line matches the regex ($2) reports a strictly positive value, or until
# the attempts are exhausted. $3 = max tries (default 30), $4 = sleep seconds
# between tries (default 2).
__wait_for_positive_metric() {
    cfg="$1"
    re="$2"
    tries="${3:-30}"
    nap="${4:-2}"
    i=0
    while [ "${i}" -lt "${tries}" ]; do
        val=$(ntp-ctl status -f prometheus -c "${cfg}" 2>/dev/null \
            | __metric_value "${re}")
        if [ -n "${val}" ] && __is_positive "${val}"; then
            return 0
        fi
        i=$((i + 1))
        sleep "${nap}"
    done
    return 1
}
