feat: the menu suite (R1.1-R1.6, R1.10) and one shared log Konsole for every test run

Scripted menu input and Steamify's own status functions, journals free of duplicates,
--backend status as JSON, an older item shown as (update). The test scripts append to
$TEST_LOG and share one Konsole (common.sh view_start) instead of opening one each;
vmsuite.sh streams its output (sed -u). 36 checks pass.
This commit is contained in:
theupriser committed 2026-09-29 13:53:35 +02:00
1 parent ea1207580f
commit fcffceb941
7 files changed
+62 -19

No files matched your search

+1 -1
View File
@@ -63,7 +63,7 @@ and wait with an until-loop on the log, e.g.
- Refuses an existing `disk.qcow2` without `--force` (asks YES), and a
running VM (port 2222).
- Never edit `vminstall.sh` while it runs: bash reads it as it goes.
- Never edit a script in place while it runs (bash reads it as it goes; Python `open(p,"w")` and editors that rewrite do this). `sed -i` or writing a copy and `mv` swaps the file: the running one keeps its old copy.
- Don't match your own wait loop with `pgrep -f`/`pkill -f` on a pattern that
is part of that loop's command line.
- Mirror 404s during the install are normal for an older ISO (pacman moves
+1 -1
View File
@@ -39,7 +39,7 @@ R2.2 (first desktop login look), H-Real (real Steam Machine).
- [ ] S1. Framework: `scripts/vmtest.sh` takes suites, resets the VM per block, tallies PASS/FAIL/SKIP,
prints the skipped manual rows; move the loader matrix under suite `boot`
- [x] S2. Suite `cli` (55 checks pass): G1-G3, F1-F7 (exit codes, `features.state`, boot-desktop unit)
- [ ] S3. Suite `menu`: R1.1-R1.6, R1.10 with scripted menu input (`vmrun.sh`) and `vmstate.sh` asserts
- [x] S3. Suite `menu` (36 checks pass): R1.1-R1.6, R1.10 with scripted menu input (`vmrun.sh`) and `vmstate.sh` asserts
- [ ] S4. Suite `hw`: H1, H3 (`WIZARD_BIOS_DRY_RUN=1`), H4, H5, R1.7 (`vmcec.sh --no-sleep`)
- [ ] S5. Suite `installer`: R2.1 (`vminstallsim.sh`)
- [ ] S6. R1.8 toggle matrix and R1.9 reboot checks (from the skill), as suite `toggles`
+10
View File
@@ -19,3 +19,13 @@ if [[ -z "${VM_SSH_KEY:-}" && -f "$VM_DIR/ssh-key" ]]; then VM_SSH_KEY="$(cat "$
[[ -n "${VM_SSH_KEY:-}" ]] && VM_SSH_OPTS+=(-i "$VM_SSH_KEY" -o IdentitiesOnly=yes)
vm_ssh() { ssh -p "$VM_PORT" "${VM_SSH_OPTS[@]}" "$VM_USER@$VM_HOST" "$@"; }
vm_scp() { scp -q -P "$VM_PORT" "${VM_SSH_OPTS[@]}" "$@"; }
# One Konsole for every test run: it follows $TEST_LOG, which the test scripts append to.
# Started only when there is a desktop, the run is headless and no such window exists.
TEST_LOG="${TEST_LOG:-$HOME/vms/test.log}"
view_start() {
[[ -n "${VM_HEADLESS:-}" && -z "${CI:-}" && -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] && command -v konsole >/dev/null || return 0
systemctl --user is-active --quiet vmtest-view 2>/dev/null && return 0
mkdir -p "$(dirname "$TEST_LOG")"; touch "$TEST_LOG"
systemd-run --user -q --collect --unit=vmtest-view konsole --hold -e tail -n 60 -F "$TEST_LOG" >/dev/null 2>&1 || true
}
Executable → Regular
+3 -5
View File
@@ -42,14 +42,12 @@ stop_vm() {
}
start_vm() { stop_vm; cp "$repo/run.sh" "$VM_DIR/run.sh"; (cd "$VM_DIR" && REPO="${REPO:-$repo/../steamify-cachyos}" setsid nohup ./run.sh --fremont > vm.log 2>&1 &); }
reboot_vm() { gssh 'sudo systemctl reboot' >/dev/null 2>&1; sleep 25; waitssh; }
# Headless on a desktop: a Konsole following the log (vmtest.sh opens one for all loaders; CI has no desktop).
if [[ -n "${VM_HEADLESS:-}" && -z "${CI:-}${VMTEST_NO_VIEW:-}" && -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] && command -v konsole >/dev/null; then
systemd-run --user -q --collect --unit="vmtest-view-$loader-$$" konsole --hold -e tail -n +1 -F "$log" >/dev/null 2>&1 || true
fi
view_start # one shared Konsole (common.sh)
# The guest checks print PASS/FAIL lines; the summary at the end counts them in the log.
check() { cat; }
{
printf '\n===== vmbootloadertest.sh %s (%s) =====\n' "$loader" "$(date +%T)"
if $install; then
step "install $loader VM in $VM_DIR"
stop_vm
@@ -112,7 +110,7 @@ b="$(gssh uname -r)"
step "DONE"
stop_vm
} 2>&1 | tee "$log" | sed 's/\x1b\[[0-9;]*m//g'
} 2>&1 | tee "$log" | tee -a "$TEST_LOG" | sed 's/\x1b\[[0-9;]*m//g'
fails="$(grep -c '^FAIL' "$log")"
echo; echo "== $loader: $(grep -c '^PASS' "$log") passed, $fails failed (log: $log)"
grep '^FAIL' "$log"
Executable → Regular
+4 -6
View File
@@ -17,18 +17,16 @@ dir="$repo/share/vmtest/$suite"
[[ -d "$dir" ]] || { echo "No suite $suite (folders in share/vmtest/)" >&2; exit 2; }
. "$here/common.sh"
log="$VM_DIR.$suite.log"
# Headless on a desktop: a Konsole following the log (CI has no desktop; vmtest.sh opens its own).
if [[ -n "${VM_HEADLESS:-}" && -z "${CI:-}${VMTEST_NO_VIEW:-}" && -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] && command -v konsole >/dev/null; then
systemd-run --user -q --collect --unit="vmsuite-view-$suite-$$" konsole --hold -e tail -n +1 -F "$log" >/dev/null 2>&1 || true
fi
view_start # one shared Konsole (common.sh), headless on a desktop
{
printf '\n===== vmsuite.sh %s (%s) =====\n' "$suite" "$(date +%T)"
for block in "$dir"/*.sh; do
[[ -z "${ONLY:-}" || "$(basename "$block")" == "$ONLY"* ]] || continue # ONLY=50: just that block
printf '\n##### %s %s\n' "$(date +%T)" "$(basename "$block" .sh)"
"$here/vmreset.sh" --fremont > /tmp/vmsuite-reset.out 2>&1 || { echo "FAIL vmreset.sh failed: $(tail -n 1 /tmp/vmsuite-reset.out)"; continue; }
cat "$repo/share/vmtest/prelude.sh" "$block" | vm_ssh -o ConnectTimeout=6 -o LogLevel=ERROR bash -s 2>&1 | sed 's/\x1b\[[0-9;]*m//g'
cat "$repo/share/vmtest/prelude.sh" "$block" | vm_ssh -o ConnectTimeout=6 -o LogLevel=ERROR bash -s 2>&1 | sed -u 's/\x1b\[[0-9;]*m//g'
done
} 2>&1 | tee "$log"
} 2>&1 | tee "$log" | tee -a "$TEST_LOG"
fails="$(grep -c '^FAIL' "$log")"
echo; echo "== $suite: $(grep -c '^PASS' "$log") passed, $fails failed, $(grep -c '^SKIP' "$log") skipped (log: $log)"
grep '^FAIL' "$log"
Executable → Regular
+1 -6
View File
@@ -27,12 +27,7 @@ for l in $advertised; do
[[ " $tested " == *" $l "* ]] || { echo "FAIL the ISO advertises $l, but there is no test for it (scripts/vmbootloadertest.sh)"; missing=$((missing + 1)); }
done
total=$missing
# No human is needed: headless. One Konsole for all the logs (the loader scripts open none).
export VMTEST_NO_VIEW=1
if [[ -z "$window" && -z "${CI:-}" && -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ]] && command -v konsole >/dev/null; then
logs=(); for l in "${loaders[@]}"; do logs+=("$HOME/vms/bl-$l.test.log"); done
systemd-run --user -q --collect --unit="vmtest-view-$$" konsole --hold -e tail -n +1 -F "${logs[@]}" >/dev/null 2>&1 || true
fi
# No human is needed: headless; the scripts share one Konsole (common.sh, $TEST_LOG).
for l in "${loaders[@]}"; do
"$here/vmbootloadertest.sh" "$l" $install $window > "/tmp/vmtest-$l.out" 2>&1; rc=$?
sed -n '/^== /,$p' "/tmp/vmtest-$l.out"
+42
View File
@@ -0,0 +1,42 @@
# R1.1-R1.6, R1.10: the menu on an existing desktop, driven with scripted input (each row builds on the last).
menu() { printf "$1" | bash /mnt/steamify.sh 2>&1 | sed 's/\x1b\[[0-9;]*m//g'; }
# R1.1: first-run ticks: everything but Boot into desktop and BIOS
out=$(menu 'q\n')
for n in 1 3 4 5 6 7 8 9 10; do grep -qE "^ +$n +[a-z-]+ +\[x\]" <<< "$out" && pass "R1.1 row $n ticked" || fail "R1.1 row $n not ticked"; done
grep -qE "^ +11 .*\[ \]" <<< "$out" && pass "R1.1 Update BIOS not ticked" || fail "R1.1 Update BIOS ticked"
grep -q "Boot into: \[gamescope\]" <<< "$out" && pass "R1.1 boots into gamescope by default" || fail "R1.1 boot default is not gamescope"
# R1.2: everything OK, back in the menu with all on
out=$(menu '\ny\nm\nq\nn\n')
grep -q '^\[ERROR\]' <<< "$out" && fail "R1.2 errors: $(grep -m1 '^\[ERROR\]' <<< "$out")" || pass "R1.2 no errors"
grep -q "^\[OK\]" <<< "$out" && pass "R1.2 applied (the run printed [OK] lines)" || fail "R1.2 printed no [OK] line"
expect_on gaming theme glyphs single launcher notify cec machine poweroff
# R1.3: the state (what vmstate.sh prints)
[[ "$(current_display_manager)" == sddm ]] && [[ -f /etc/sddm.conf.d/10-gamescope-autologin.conf ]] && pass "R1.3 SDDM with autologin" || fail "R1.3 no SDDM autologin"
n=$(compgen -G "/sys/class/leds/valve-leds*" | wc -l); [[ $n -eq 17 ]] && pass "R1.3 17 LED nodes" || fail "R1.3 $n LED nodes"
own=$(stat -c %U /sys/class/leds/valve-leds*/brightness 2>/dev/null | sort -u | tr '\n' ' '); [[ "$own" == "$(id -un) " ]] && pass "R1.3 LEDs owned by the user" || fail "R1.3 LED owner: $own"
[[ $(dkms status | grep -c ': installed') -ge $((3 * $(ls /usr/lib/modules | wc -w))) ]] && pass "R1.3 DKMS installed for every kernel" || fail "R1.3 DKMS: $(dkms status | tr '\n' ';')"
systemctl is-active --quiet steamos-manager && pass "R1.3 steamos-manager active" || systemctl --user is-active --quiet steamos-manager && pass "R1.3 steamos-manager active (user)" || fail "R1.3 steamos-manager not active"
# R1.4: nothing to do
out=$(menu '\nq\n'); grep -qi "already the way you want it" <<< "$out" && pass "R1.4 already the way you want it" || fail "R1.4 message missing"
# R1.5: re-apply: no errors, no duplicates in the journals
out=$(menu 'a\ny\nm\nq\nn\n')
grep -q '^\[ERROR\]' <<< "$out" && fail "R1.5 errors: $(grep -m1 '^\[ERROR\]' <<< "$out")" || pass "R1.5 re-apply without errors"
dup=""; for f in ~/.local/state/steamify/*; do [ -f "$f" ] && d=$(cut -f1-3 "$f" | sort | uniq -d) && [ -n "$d" ] && dup+="$(basename "$f"): $d; "; done
[[ -z "$dup" ]] && pass "R1.5 no duplicates in the journals" || fail "R1.5 DUPLICATES $dup"
# R1.6: --backend status
ver=$(sed -n 's/^VERSION=//p' /mnt/steamify.sh | head -n 1)
js=$(bash /mnt/steamify.sh --backend status 2>/dev/null)
python3 - "$js" "$ver" <<'PY'
import json, sys
def r(ok, m): print(("PASS " if ok else "FAIL ") + m)
try:
d = json.loads(sys.argv[1]); r(True, "R1.6 --backend status is valid JSON")
except Exception as e:
r(False, f"R1.6 --backend status is not JSON: {e}"); sys.exit()
r(sys.argv[2] in json.dumps(d), f"R1.6 the JSON has the current version {sys.argv[2]}")
PY
# R1.10: an item older in features.state shows as an update, and the run brings it up to date
f=~/.local/state/steamify/features.state
[[ -f "$f" ]] && sed -i 's/^cec=.*/cec=2.1.0/' "$f" && grep -q '^cec=2.1.0' "$f" && pass "R1.10 cec set to 2.1.0" || fail "R1.10 cannot set cec older in $f"
out=$(menu 'q\n'); grep -q "HDMI-CEC.*(update)" <<< "$out" && pass "R1.10 the menu shows HDMI-CEC (update)" || fail "R1.10 no (update) on HDMI-CEC"
out=$(menu '\ny\nm\nq\nn\n'); grep -q '^cec=2.1.0' "$f" && fail "R1.10 cec still 2.1.0 after the run" || pass "R1.10 cec brought up to date"