wren-linux / tools / test-console.sh
#!/bin/bash
# Checks the console-only pieces: the ~/.profile autostart swap (sway <-> tmux),
# the tmux bar text of bin/sway-status, and bin/console-click with a pretend
# tmux. Changes nothing outside a temp folder. Run by test.sh, or:
# bash tools/test-console.sh
# shellcheck disable=SC2016 # the inner bash expands its own variables
HERE=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
T=$(mktemp -d) || { echo " FAIL couldn't make a temp folder (is /tmp full?)"; exit 1; }
trap 'rm -rf "$T"' EXIT
fails=0
check() { # DESCRIPTION CONDITION-COMMAND...
local what=$1
shift
if "$@" >/dev/null 2>&1; then printf ' ok %s\n' "$what"; else printf ' FAIL %s\n' "$what"; fails=$((fails + 1)); fi
}
not() { ! "$@"; }
export HOME=$T/home
mkdir -p "$HOME"
swap() { bash -c ". '$HERE/lib/core.sh'; profile_autostart $1" >/dev/null 2>&1; }
swap sway
check "sway autostart is written" grep -q 'Wren Linux autostart >>>' "$HOME/.profile"
swap console
swap console
check "console-only sets the mode to console" grep -qx console "$HOME/.config/wren/login"
check "twice leaves one block" test "$(grep -c 'Wren Linux autostart >>>' "$HOME/.profile")" = 1
swap sway
check "removing it sets sway again" grep -qx sway "$HOME/.config/wren/login"
check "login_mode reads it" test "$(bash -c ". '$HERE/lib/core.sh'; login_mode")" = sway
# the block's loop: a pretend tmux/sway on a pretend tty; changing the mode while one runs starts the other
mkdir -p "$T/lb"
printf '#!/bin/sh\necho /dev/tty1\n' >"$T/lb/tty"
printf '#!/bin/sh\necho sway >>%s/ran; echo console >%s/home/.config/wren/login\n' "$T" "$T" >"$T/lb/env"
printf '#!/bin/sh\necho tmux >>%s/ran\n' "$T" >"$T/lb/tmux"
chmod +x "$T"/lb/*
rm -f "$T/ran"
swap sway
sed -n '/^case "\$(tty/,/^esac/p' "$HOME/.profile" | sed 's|/dev/tty\[0-9\]\*|*|' >"$T/block.sh"
PATH=$T/lb:$PATH bash -c 'unset WAYLAND_DISPLAY TMUX; . "$1"' _ "$T/block.sh" >/dev/null 2>&1
check "ending sway after the mode changed to console starts tmux" test "$(cat "$T/ran")" = "$(printf 'sway\ntmux')"
# Ending sway with no change: the shell stays (a login prompt or autologin would
# start sway again); ending tmux with no change logs out
printf '#!/bin/sh\necho sway >>%s/ran\n' "$T" >"$T/lb/env"
rm -f "$T/ran"; swap sway
sed -n '/^case "\$(tty/,/^esac/p' "$HOME/.profile" | sed 's|/dev/tty\[0-9\]\*|*|' >"$T/block.sh"
printf '#!/bin/sh\nexit 0\n' >"$T/lb/su"; chmod +x "$T/lb/su"
out=$(PATH=$T/lb:$PATH bash -c 'unset WAYLAND_DISPLAY TMUX; . "$1"; echo still-here' _ "$T/block.sh" 2>&1)
check "exiting sway (mode unchanged) leaves you at the shell, saying how to start it again" \
bash -c 'grep -qx still-here <<<"$1" && grep -q "Start it again: sway" <<<"$1"' _ "$out"
# sway dying (a crash, out of memory, the secure attention key): it may have been locked, so
# no open shell, and with autologin no fresh sway, without your password
MARK=$HOME/.local/state/wren/sway-running
printf '#!/bin/sh\necho su >>%s/ran; n=$(cat %s/su-fails 2>/dev/null || echo 0); [ "$n" = 0 ] || { echo $((n - 1)) >%s/su-fails; exit 1; }\n' "$T" "$T" "$T" >"$T/lb/su"
printf '#!/bin/sh\n[ -s %s/sway-rc ] || exit 0; rc=$(head -n1 %s/sway-rc); sed -i 1d %s/sway-rc; echo "sway $rc" >>%s/ran; exit "$rc"\n' "$T" "$T" "$T" "$T" >"$T/lb/env"
chmod +x "$T/lb/su"
bl() { PATH=$T/lb:$PATH timeout 20 bash -c 'unset WAYLAND_DISPLAY TMUX; . "$1"; echo still-here' _ "$T/block.sh" 2>&1; }
swap sway
sed -n '/^case "\$(tty/,/^esac/p' "$HOME/.profile" | sed 's|/dev/tty\[0-9\]\*|*|' >"$T/block.sh"
check "a clean end leaves no mark" test ! -e "$MARK"
rm -f "$T/ran"; printf '0\n' >"$T/sway-rc"; out=$(bl)
check "exiting sway on purpose: the password first (it may have been locked), then the shell" bash -c '[ "$(paste -sd" " "$1")" = "sway 0 su" ] && grep -qx still-here <<<"$2" && [[ $2 != *still-here*"password"* ]]' _ "$T/ran" "$out"
rm -f "$T/ran"; printf '0\n' >"$T/sway-rc"; echo 2 >"$T/su-fails"; out=$(bl)
check "...a wrong password asks again, and gives no shell before the right one" bash -c '[ "$(paste -sd" " "$1")" = "sway 0 su su su" ] && grep -qx still-here <<<"$2"' _ "$T/ran" "$out"
check "...and no mark" test ! -e "$MARK"
# a run that fails only after a while: (date says 20 seconds went by)
printf '#!/bin/sh\nn=$(cat %s/clock 2>/dev/null || echo 1000); echo $((n + 20)) >%s/clock; echo $n\n' "$T" "$T" >"$T/lb/date"
chmod +x "$T/lb/date"
rm -f "$T/ran"; printf '139\n0\n' >"$T/sway-rc"; echo 2 >"$T/su-fails"; out=$(bl)
check "sway crashes: the password comes first, as often as it's wrong, then sway starts again" \
test "$(paste -sd' ' "$T/ran")" = "sway 139 su su su sway 0 su"
check "...it says why" grep -q 'stopped unexpectedly' <<<"$out"
check "...and no open shell before the password" bash -c '[[ $1 != *still-here*stopped* ]]' _ "$out"
# killed along with the shell (the secure attention key): autologin only starts this block again
rm -f "$T/ran"; printf '0\n' >"$T/sway-rc"; cat /proc/sys/kernel/random/boot_id >"$MARK"; out=$(bl)
check "a login after sway was killed, same boot: the password first" test "$(paste -sd' ' "$T/ran")" = "su sway 0 su"
rm -f "$T/ran"; printf '0\n' >"$T/sway-rc"; echo another-boot >"$MARK"; out=$(bl)
check "a mark from another boot (a power cut): no password before sway starts (one when it ends)" test "$(paste -sd' ' "$T/ran")" = "sway 0 su"
# sway can't start at all: after the password, the shell, to see why
printf '#!/bin/sh\necho 1000\n' >"$T/lb/date"
rm -f "$T/ran"; printf '1\n1\n1\n' >"$T/sway-rc"; out=$(bl)
check "sway fails at once: the password, then the shell to see why" bash -c '[ "$(paste -sd" " "$1")" = "sway 1 su" ] && grep -qx still-here <<<"$2" && grep -q "keeps failing" <<<"$2"' _ "$T/ran" "$out"
rm -f "$T/lb/date" "$T/lb/su" "$MARK"
printf '#!/bin/sh\necho sway >>%s/ran\n' "$T" >"$T/lb/env"
check "the magic keys are off: the secure attention key would end a locked sway" grep -qx 'kernel.sysrq = 0' "$HERE/data/sysctl-hardening.conf"
check "an update writes the block again, if it's there" grep -q 'profile_autostart "$(login_mode)"' "$HERE/parts/core-commands.sh"
swap console
out=$(PATH=$T/lb:$PATH bash -c 'unset WAYLAND_DISPLAY TMUX; . "$1"; echo still-here' _ "$T/block.sh" 2>&1)
check "...while leaving tmux (mode unchanged) logs out, as before" not grep -qx still-here <<<"$out"
swap sway
# extras/console-only.sh itself, in a copy of Wren Linux with a pretend sudo, swaymsg
# and sleep, and the base's tmux part stubbed out
R=$T/r
mkdir -p "$R/extras" "$R/parts" "$T/cb"
sed 's|^export PATH=.*|export PATH="$CONSOLE_TEST_PATH"|' "$HERE/lib.sh" >"$R/lib.sh"
for f in pins.sh packages.sh lib data docs bin; do ln -s "$HERE/$f" "$R/$f"; done
cp "$HERE/extras/console-only.sh" "$R/extras/"
printf 'mkdir -p "$HOME/.config/tmux"; : >"$HOME/.config/tmux/tmux.conf"\n' >"$R/parts/console-tmux.sh"
printf '#!/bin/sh\n[ "$1" = -v ] && exit 0\n' >"$T/cb/sudo"
printf '#!/bin/sh\necho "swaymsg $*" >>"%s/sway-calls"\n' "$T" >"$T/cb/swaymsg"
printf '#!/bin/sh\n' >"$T/cb/sleep"
chmod +x "$T"/cb/*
export CONSOLE_TEST_PATH="$T/cb:$PATH"
co() { : >"$T/sway-calls"; WAYLAND_DISPLAY=wayland-1 WREN_LOGIN_LOOP=1 bash "$R/extras/console-only.sh" "$@" >/dev/null 2>&1; }
found() { (cd "$R" && bash -c '. ./lib.sh; script_found extras/console-only.sh'); }
rm -rf "$HOME/.config"; swap sway
mkdir -p "$HOME/.config/tmux"; : >"$HOME/.config/tmux/tmux.conf"
check "console-only: the base's tmux config alone doesn't count as it being set up" test -z "$(found)"
co
check "set up from inside sway: the login is tmux, and sway is left" bash -c 'grep -qx console "$1" && grep -qx "swaymsg exit" "$2"' _ "$HOME/.config/wren/login" "$T/sway-calls"
check "...and it counts as set up" test -n "$(found)"
co
check "run again (as update.sh does) from a sway started by hand: sway stays" not grep -q 'swaymsg exit' "$T/sway-calls"
co --remove
check "--remove: no longer counted as set up, and the login is sway" bash -c '[ -z "$1" ] && grep -qx sway "$2"' _ "$(found)" "$HOME/.config/wren/login"
# a removal cut off half way once left the login on tmux, the extra counted as
# gone: the login goes back to sway first, the mark last
check "...the login goes back to sway before the mark goes (cut off, --remove again finishes it)" \
python3 -I -c 'import sys; s = open(sys.argv[1]).read(); r = s.index("= --remove ]"); a = s.index("profile_autostart sway", r); m = s.index("rm -f \"$MARK\"", r); assert a < m' "$HERE/extras/console-only.sh"
bar=$(sh "$HERE/bin/sway-status" --tmux)
check "the tmux bar starts with the Wren menu range" bash -c '[[ $1 == "#[range=user|menu]Wren Menu#[norange]"* ]]' _ "$bar"
check "...and has a date item" bash -c '[[ $1 == *"#[range=user|date]"* ]]' _ "$bar"
mkdir -p "$T/bin" "$HOME/.local/bin"
printf '#!/bin/sh\necho "$@" >>%s/calls\n' "$T" >"$T/bin/tmux"
chmod +x "$T/bin/tmux"
printf '#!/bin/sh\necho "volume $@" >>%s/calls\n' "$T" >"$HOME/.local/bin/volume"
chmod +x "$HOME/.local/bin/volume"
PATH=$T/bin:$PATH sh "$HERE/bin/console-click" menu 1 c0
check "a click on Wren Menu opens the menu in a pop-up" grep -q 'display-popup -c c0 -E -w 72% -h 85% .*wren-menu --tui' "$T/calls"
PATH=$T/bin:$PATH sh "$HERE/bin/console-click" vol 4 c0
check "scrolling vol up raises the volume" grep -qx 'volume up' "$T/calls"
check "the config loads the console file only without sway" grep -q "if-shell '\[ -z \"\$WAYLAND_DISPLAY\" \]' 'source-file ~/.config/tmux/console.conf'" "$HERE/data/tmux.conf"
check "Alt+3 and Alt+Shift+3 are bound" bash -c 'grep -q "M-3 " "$1" && grep -q "M-#" "$1"' _ "$HERE/data/tmux-console.conf"
check "Alt+w, volume and brightness keys are bound" bash -c 'grep -q "M-w " "$1" && grep -q "M-= " "$1" && grep -q "M-\. " "$1"' _ "$HERE/data/tmux-console.conf"
[ "$fails" -eq 0 ] || { echo "$fails failed"; exit 1; }