diff --git a/doctor.sh b/doctor.sh index 802bc37..a3b658e 100755 --- a/doctor.sh +++ b/doctor.sh @@ -121,6 +121,19 @@ if [[ -n ${WAYLAND_DISPLAY:-} ]]; then echo "running now" systemctl --user is-active -q macarchy-touchbar.service && ok "macarchy-touchbar" \ || bad "macarchy-touchbar not running (journalctl --user -u macarchy-touchbar)" + # A Touch Bar module that fails to load is otherwise SILENT: the daemon says + # so once, then runs happily without that widget -- no failed unit, no toast, + # and `status` does not list it. It is what a rename here costs every OTHER + # repo that ships a module (jarvis ships one, and is not even in REPOS), whose + # installed copy is a COPY and keeps importing the old package name. The + # daemon hot-reloads on the file change, so a failure can be repaired later in + # the same boot: only the LAST word on each module counts. + broken=$(journalctl --user -u macarchy-touchbar.service -b --no-pager 2>/dev/null \ + | sed -nE 's/.* module ([^ :]+) failed to load.*/FAIL \1/p; s/.* module ([^ :]+):.*/OK \1/p' \ + | awk '{ s[$2] = ($1 == "FAIL") } END { for (m in s) if (s[m]) print m }' | sort | tr '\n' ' ') + broken=${broken% } + [[ -z $broken ]] && ok "Touch Bar modules loaded" \ + || bad "Touch Bar module failed to load: $broken (re-run install.sh in the repo that ships it)" pgrep -f "macarchy-als daemon" >/dev/null && ok "macarchy-als" || bad "macarchy-als not running" pgrep -f "macarchy-pinch" >/dev/null && ok "macarchy-pinch" || bad "macarchy-pinch not running" # The tank remembers off across reboots (omarchy-aquarium-toggle:30, an diff --git a/tests/test_doctor_touchbar_modules.sh b/tests/test_doctor_touchbar_modules.sh new file mode 100755 index 0000000..27ad5a8 --- /dev/null +++ b/tests/test_doctor_touchbar_modules.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# tests/test_doctor_touchbar_modules.sh — the doctor's Touch Bar module check. +# +# A module that fails to load is the one macarchy breakage nothing else +# reports: the daemon logs it once and then runs without that widget, so the +# unit stays active, no toast fires, and the bar just quietly lacks a button. +# It is what a rename in macarchy-touchbar costs jarvis, which ships a module +# and is not even in REPOS. +# +# The branch that matters most is (b): the daemon hot-reloads on the file +# change, so a failure repaired later in the SAME boot must not be reported. +# Hermetic: temp HOME plus PATH stubs, no compositor and no Apple hardware. +set -uo pipefail +cd "$(dirname "$0")/.." + +TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT +export HOME="$TMP/home" XDG_STATE_HOME="$TMP/state" WAYLAND_DISPLAY=wayland-0 +mkdir -p "$HOME" "$TMP/bin" +export PATH="$TMP/bin:$PATH" + +fails=0 +check() { local name=$1; shift; if "$@"; then echo "ok $name"; else echo "FAIL $name"; fails=$((fails+1)); fi; } + +# Absent, not broken: no compositor, no tank, no units in a temp HOME. +for stub in pgrep omarchy-aquarium-toggle systemctl; do + printf '#!/bin/bash\nexit 1\n' > "$TMP/bin/$stub" +done +# journalctl replays whatever the case under test wrote. +printf '#!/bin/bash\ncat "$TMP_JOURNAL"\n' > "$TMP/bin/journalctl" +chmod +x "$TMP/bin"/* +export TMP_JOURNAL="$TMP/journal" + +line() { printf 'Sep 04 %s omachi macarchy-touchbar[4242]: [macarchy-touchbar %s] %s\n' "$1" "$1" "$2"; } + +# --- (a) a module failed and was never repaired ----------------------------- +{ line 22:29:40 "module core: core.button, core.label" + line 22:29:40 "module notifications: no widgets" + line 22:29:40 "module macarchy.jarvis failed to load: ModuleNotFoundError(\"No module named 'macarchy_dfr'\")" +} > "$TMP_JOURNAL" +out=$(./doctor.sh 2>&1) +check "(a) names the broken module" grep -q 'MISS.*macarchy.jarvis' <<<"$out" +check "(a) points at the fix" grep -q 'repo that ships it' <<<"$out" +check "(a) does not also say loaded" bash -c '! grep -q "ok.*Touch Bar modules loaded" <<<"$1"' _ "$out" + +# --- (b) failed, then repaired by a hot-reload in the same boot ------------- +{ line 22:29:40 "module macarchy.jarvis failed to load: ModuleNotFoundError(\"No module named 'macarchy_dfr'\")" + line 23:30:05 "module core: core.button, core.label" + line 23:30:05 "module macarchy.jarvis: macarchy.jarvis.fish" +} > "$TMP_JOURNAL" +out=$(./doctor.sh 2>&1) +check "(b) repaired module is not a miss" bash -c '! grep -q "MISS.*macarchy.jarvis" <<<"$1"' _ "$out" +check "(b) reports modules loaded" grep -q 'Touch Bar modules loaded' <<<"$out" + +# --- (c) a healthy boot, including a module with no widgets ----------------- +{ line 23:30:27 "module core: core.button, core.label" + line 23:30:27 "module notifications: no widgets" + line 23:30:27 "module macarchy.jarvis: macarchy.jarvis.fish" +} > "$TMP_JOURNAL" +out=$(./doctor.sh 2>&1) +check "(c) reports modules loaded" grep -q 'Touch Bar modules loaded' <<<"$out" +check "(c) no module miss" bash -c '! grep -q "Touch Bar module failed" <<<"$1"' _ "$out" + +# --- (d) no journal at all (daemon never ran) ------------------------------- +: > "$TMP_JOURNAL" +out=$(./doctor.sh 2>&1) +check "(d) silence is not a miss" bash -c '! grep -q "Touch Bar module failed" <<<"$1"' _ "$out" + +(( fails == 0 )) && echo "all ok" || echo "$fails failed" +exit $(( fails > 0 ))