#!/bin/bash
#
# Run gnulib tests under Syd.
#
# Copyright 2024 Ali Polatel <alip@chesswob.org>
#
# SPDX-License-Identifier: GPL-3.0

# TEST_LIMIT: Number of tests to run at a time.
# TEST_PATTERN: A Regex (PCRE) for tests to run.
test_pattern_set=false
case "$1" in
    '')
        TEST_LIMIT=4096
        TEST_PATTERN='.*'
        test_pattern_set=true
        ;;
    [0-9]*)
        TEST_LIMIT="${1}"
        TEST_PATTERN='.*'
        ;;
    *)
        TEST_LIMIT=250
        TEST_PATTERN="${1}"
        test_pattern_set=true
        ;;
esac

# A Regex (PCRE) for tests to skip.
# i586-only (compile) fails: backupfile, copy-file, exclude, mbsstr, nan, wctype.
# vma-prot: https://builds.sr.ht/~alip/job/1351977 TODO: Figure out why!
# physmem: Smashes the stack: https://builds.sr.ht/~alip/job/1395200 TODO: ditto!
# getloadavg: ditto: https://builds.sr.ht/~alip/job/1395813 TODO: ditto!
# localename-environ: config fails: configure.ac:41: error: possibly undefined macro: gl_LOCALE_MODULE_INDICATOR
# poll: racy test, fails randomly, passes most of the time: https://builds.sr.ht/~alip/job/1454355#task-test64
SKIP_PATTERN='(backupfile|bison|copy-file|datetime|exception|exclude|gettext|link-warning|localename-environ|mbsstr|nan|poll|printf|trapping|vma-prot|wctype|windows|^(array|java|uni)|-ieee$|(^(execinfo|getloadavg|gnumakefile|havelib|physmem|timevar)$))'

# Tests that have failed in the past.
# copy-file fails to compile on i586 so we skip it.
# linkat: https://builds.sr.ht/query/log/1402429/test32/log
# mkdir: https://builds.sr.ht/~alip/job/1286254
# posix_openpt: https://builds.sr.ht/~alip/job/126488
# readdir: no known fail but best to check everytime.
# rename: https://builds.sr.ht/~alip/job/1286933
# truncate: https://gitlab.exherbo.org/sydbox/sydbox/-/jobs/83046
# utimensat: https://builds.sr.ht/~alip/job/1257729
FAIL_HISTORY=(
    linkat
    mkdir
    posix_openpt
    readdir
    rename
    truncate
    utimensat
)
# Do not go over history, if user specified a test pattern.
$test_pattern_set && FAIL_HISTORY=()

# Make sure we don't trigger TPE.
umask 077

# Enable coredumps.
ulimit -c unlimited

# Force TTY output.
export SYD_FORCE_TTY=YesPlease

# Timeout is 10 minutes per-test,
# unless otherwise specified.
SYD_TEST_TIMEOUT=${SYD_TEST_TIMEOUT:-10m}

export SYD_LOG=${SYD_LOG:-info}
SYD="${CARGO_BIN_EXE_syd:-syd}"

set -ex
DIR="$(mktemp -d --tmpdir=/tmp syd-gnulib.XXXXX)"
set +ex

edo() {
    echo >&2 "-- $*"
    "$@"
}

run_test() {
    local name="$1"
    local tdir="$(readlink -f "${DIR}")"
    local tnam="$(echo "${name}" | sed -e 's|/|-|g')"
    [[ -n "${SYD_TEST_DMESG}" ]] && sudo dmesg -C

    echo >&2 "[*] Creating test directory..."
    ./gnulib-tool \
        --create-testdir "${name}" \
        --dir "${tdir}/${tnam}" >/dev/null 2>&1 || return $?

    pushd "${tdir}/${tnam}" &>/dev/null

    echo >&2 "[*] Running configure for test ${name}..."
    ./configure >/dev/null 2>&1 || return $?
    make -j >/dev/null 2>&1 || return $?

    edo \
        timeout -sKILL ${SYD_TEST_TIMEOUT} \
        "${SYD}" -ppaludis -m 'allow/all+/***' -mlock:on \
        -- make -j check
    r=$?

    if [[ $r == 0 ]]; then
        popd &>/dev/null
        rm -fr "${tdir}/${tnam}"
        return 0
    fi

    echo '--8<-- TEST LOG BEGIN -->8--'
    cat ./gltests/test-suite.log
    echo '-->8-- TEST LOG END   --8<--'

    if [[ -n "${SYD_TEST_DMESG}" ]]; then
        echo '--8<-- KERNEL LOG BEGIN -->8--'
        sudo dmesg
        echo '-->8-- KERNEL LOG END   --8<--'
    fi

    echo >&2 "[*] Keeping test directory of failed test ${name}: ${tdir}/${tnam}"
    #echo >&2 "[*] Rerunning failed test ${name} under strace..."
    #edo \
    #    timeout -sKILL ${SYD_TEST_TIMEOUT} \
    #    strace -f -s256 \
    #    "${SYD}" -ppaludis -m 'allow/all+/***' -mlock:on \
    #    -- make -j check >strace.log 2>&1

    popd &>/dev/null
    return $r
}

arg_depth='--depth 1'
if [[ -n "${GNULIB_HEAD}" ]]; then
    arg_depth=
fi
set -ex
pushd "${DIR}"
git clone ${arg_depth} https://github.com/coreutils/gnulib.git || exit 0
pushd gnulib
if [[ -n "${GNULIB_HEAD}" ]]; then
    git checkout "${GNULIB_HEAD}" || exit 127
fi
git rev-parse HEAD
sed -i \
    -e 's|"0.0.0.0"|"127.0.0.1"|' \
    tests/test-getsockname.c
set +x

PASS=0
FAIL=0
SKIP=0
TESTS=( $(./gnulib-tool --list | grep -P "${TEST_PATTERN}" | grep -vP "${SKIP_PATTERN}" | shuf ) )
CTEST=${#TESTS[@]}
NTEST=${TEST_LIMIT}
if [[ ${NTEST} -gt ${CTEST} ]]; then
    NTEST=${CTEST}
fi
TESTS=( "${FAIL_HISTORY[@]}" "${TESTS[@]:0:${NTEST}}" )
NTEST=${#TESTS[@]}

idx=0
for name in "${TESTS[@]}"; do
    : $(( idx++ ))
    echo >&2 -e "\033[92m*** $name ($idx of $NTEST: $PASS ok, $FAIL notok, $SKIP todo) ***\033[0m"
    if echo "${name}" | grep -qP "${SKIP_PATTERN}"; then
        echo "ok ${idx} - ${name} # TODO"
        : $(( SKIP++ ))
    elif run_test "${name}"; then
        echo "ok ${idx} - ${name}"
        : $(( PASS++ ))
    else
        echo "not ok ${idx} - ${name} - FAIL: $?"
        : $(( FAIL++ ))
        [[ -z "${SYD_TEST_QUICK}" ]] || break
    fi
done

echo "# $PASS tests passed."
echo "# $FAIL tests failed."
echo "# $SKIP tests skipped."
exit $FAIL
