#!/bin/sh
# Tests for guest/linux-base/provision/nucleic-modsetup.sh — the boot-time module setup whose silent
# failure once cost a whole base build (docs/LINUX_VM.md §Debugging a failed base build). Runs on any
# Linux/macOS shell: `uname`/`depmod`/`modprobe` are PATH shims and the module root is a tmpdir via
# NUCLEIC_MODROOT, so nothing touches the running system.
#
#   sh guest/linux-base/test/modsetup_test.sh
set -eu

here="$(cd "$(dirname "$0")" && pwd)"
script="$here/../provision/nucleic-modsetup.sh"
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT

REAL_REL="7.0.0-28-generic"
TAGGED_REL="7.0.0-28-generic-naros26.07"

# --- PATH shims ---------------------------------------------------------------------------------
mkdir -p "$work/bin"
# naros-identity semantics: `uname -r` reports the tagged release; NAROS_UNAME_PASSTHROUGH=1
# reveals the real one. UNAME_MODE=plain models a stock (untagged) rootfs.
cat > "$work/bin/uname" <<EOF
#!/bin/sh
if [ "\${UNAME_MODE:-tagged}" = plain ] || [ -n "\${NAROS_UNAME_PASSTHROUGH:-}" ]; then
    echo "$REAL_REL"
else
    echo "$TAGGED_REL"
fi
EOF
cat > "$work/bin/depmod" <<EOF
#!/bin/sh
echo "depmod \$*" >> "$work/calls"
exit "\${DEPMOD_EXIT:-0}"
EOF
cat > "$work/bin/modprobe" <<EOF
#!/bin/sh
echo "modprobe \$*" >> "$work/calls"
case "\$1" in vmw_vsock_virtio_transport) exit "\${MODPROBE_VSOCK_EXIT:-0}";; esac
exit "\${MODPROBE_OTHER_EXIT:-0}"
EOF
chmod +x "$work/bin/uname" "$work/bin/depmod" "$work/bin/modprobe"
export PATH="$work/bin:$PATH"

run() { : > "$work/calls"; out="$(sh "$script" 2>&1)"; }
fail() { echo "FAIL: $1"; echo "--- output:"; echo "$out"; echo "--- calls:"; cat "$work/calls" 2>/dev/null; exit 1; }
pass=0

# --- 1. tagged uname, modules under the real release → alias created, depmod on tagged ----------
export NUCLEIC_MODROOT="$work/m1"
mkdir -p "$NUCLEIC_MODROOT/$REAL_REL"
run
[ "$(readlink "$NUCLEIC_MODROOT/$TAGGED_REL")" = "$NUCLEIC_MODROOT/$REAL_REL" ] \
    || fail "tagged alias not created (the naros-identity race fix)"
grep -q "depmod $TAGGED_REL" "$work/calls" || fail "depmod not run for the tagged release"
grep -q "modprobe vmw_vsock_virtio_transport" "$work/calls" || fail "vsock transport not probed"
echo "$out" | grep -q "vsock transport loaded" || fail "no vsock success report"
pass=$((pass + 1))

# --- 2. alias already present (identity unit won the race) → left alone, still depmod ------------
run
grep -q "depmod $TAGGED_REL" "$work/calls" || fail "depmod skipped when alias pre-exists"
pass=$((pass + 1))

# --- 3. untagged rootfs (uname == passthrough) → no alias needed, depmod on the real release -----
export NUCLEIC_MODROOT="$work/m3" UNAME_MODE=plain
mkdir -p "$NUCLEIC_MODROOT/$REAL_REL"
run
[ ! -L "$NUCLEIC_MODROOT/$TAGGED_REL" ] || fail "alias created on an untagged rootfs"
grep -q "depmod $REAL_REL" "$work/calls" || fail "depmod not run on an untagged rootfs"
unset UNAME_MODE
pass=$((pass + 1))

# --- 4. no module directory at all → loud ERROR, exit 0, no depmod ------------------------------
export NUCLEIC_MODROOT="$work/m4"
mkdir -p "$NUCLEIC_MODROOT"
run
echo "$out" | grep -q "ERROR: no module directory" || fail "missing-modules case not reported"
grep -q depmod "$work/calls" && fail "depmod run despite missing module dir"
pass=$((pass + 1))

# --- 5. primary vsock transport fails → falls back to the plain vsock module ---------------------
export NUCLEIC_MODROOT="$work/m5" MODPROBE_VSOCK_EXIT=1
mkdir -p "$NUCLEIC_MODROOT/$REAL_REL"
run
grep -q "modprobe vsock" "$work/calls" || fail "no fallback to the plain vsock module"
unset MODPROBE_VSOCK_EXIT
pass=$((pass + 1))

# --- 6. depmod failure is reported, not swallowed ------------------------------------------------
export NUCLEIC_MODROOT="$work/m6" DEPMOD_EXIT=1
mkdir -p "$NUCLEIC_MODROOT/$REAL_REL"
run
echo "$out" | grep -q "WARN: depmod" || fail "depmod failure swallowed"
unset DEPMOD_EXIT
pass=$((pass + 1))

# --- 7. bootstrap/payload consistency: every static file the bootstrap copies is staged ----------
init="$here/../bootstrap/init"
for f in nucleic-modsetup.service nucleic-modsetup.sh nucleic-firstboot.service \
         nucleic-bootdebug.service nucleic-bootdebug.sh provision-linux-guest.sh; do
    grep -q "/mnt/prov/$f" "$init" || fail "bootstrap init does not install $f"
    [ -f "$here/../provision/$f" ] || fail "repo is missing guest/linux-base/provision/$f"
done
# …and the unit ExecStart paths point at where the bootstrap bakes the scripts.
grep -q "ExecStart=/usr/local/sbin/nucleic-modsetup.sh" "$here/../provision/nucleic-modsetup.service" \
    || fail "modsetup unit ExecStart mismatch"
grep -q "ExecStart=/usr/local/sbin/nucleic-bootdebug.sh" "$here/../provision/nucleic-bootdebug.service" \
    || fail "bootdebug unit ExecStart mismatch"
grep -q "StartLimitIntervalSec=0" "$here/../../nucleic-linux-agent/systemd/nucleic-linux-agent.service" \
    || fail "agent unit is missing StartLimitIntervalSec=0 (start-limit-hit regression)"
pass=$((pass + 1))

echo "OK: $pass test groups passed"
