Files
omarchycn/test/shell.d/restart-shell-test.sh
T
David Heinemeier HanssonandClaude Fable 5 4a02da20d5 Relaunch the shell through Hyprland so restarts match boot conditions
Spawning quickshell directly from omarchy-restart-shell leaked transient
environment variables from the calling terminal, SSH connection, or
development tool into the fresh shell. Dispatch the launch through
Hyprland instead so it inherits the canonical session environment, same
as autostart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 12:44:09 -07:00

170 lines
5.7 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
test_tmp=$(mktemp -d)
restart_pid_one=""
restart_pid_two=""
cleanup() {
[[ -n $restart_pid_one ]] && kill "$restart_pid_one" 2>/dev/null || true
[[ -n $restart_pid_two ]] && kill "$restart_pid_two" 2>/dev/null || true
rm -rf "$test_tmp"
}
trap cleanup EXIT
wrapper_root="$test_tmp/wrapper-root"
wrapper_bin="$test_tmp/wrapper-bin"
mkdir -p "$wrapper_root/shell" "$wrapper_bin"
touch "$wrapper_root/shell/shell.qml"
cat >"$wrapper_bin/qs" <<'SH'
#!/bin/bash
[[ -n ${OMARCHY_TEST_QS_ARGS:-} ]] && printf '%s\n' "$*" >"$OMARCHY_TEST_QS_ARGS"
if [[ ${OMARCHY_TEST_QS_HANG:-0} == 1 ]]; then
sleep 5
else
printf 'ok\n'
fi
SH
chmod +x "$wrapper_bin/qs"
wrapper_error=$(PATH="$wrapper_bin:$PATH" \
OMARCHY_PATH="$wrapper_root" \
OMARCHY_SHELL_IPC_TIMEOUT=0.1s \
OMARCHY_TEST_QS_HANG=1 \
"$ROOT/bin/omarchy-shell" shell ping 2>&1) && fail "hung shell IPC returns a failure"
[[ $wrapper_error == "omarchy-shell is not responding" ]] || fail "hung shell IPC reports that the shell is unresponsive" "$wrapper_error"
pass "shell IPC calls time out when Quickshell is unresponsive"
wrapper_args="$test_tmp/wrapper-args"
PATH="$wrapper_bin:$PATH" \
OMARCHY_PATH="$wrapper_root" \
OMARCHY_TEST_QS_ARGS="$wrapper_args" \
"$ROOT/bin/omarchy-shell" shell ping >/dev/null
grep -F -- 'ipc -n -p' "$wrapper_args" >/dev/null || fail "shell IPC targets the newest live Quickshell instance"
pass "shell IPC targets the newest live Quickshell instance"
restart_root="$test_tmp/restart-root"
restart_bin="$restart_root/bin"
restart_state="$test_tmp/restart-pids"
restart_log="$test_tmp/restart.log"
restart_env_log="$test_tmp/restart-env.log"
dispatch_log="$test_tmp/dispatch.log"
ipc_log="$test_tmp/ipc.log"
runtime_dir="$test_tmp/runtime"
mkdir -p "$restart_root/shell" "$restart_bin" "$runtime_dir"
touch "$restart_root/shell/shell.qml"
ln -s "$ROOT/bin/omarchy-shell" "$restart_bin/omarchy-shell"
ln -s "$ROOT/bin/omarchy-cmd-missing" "$restart_bin/omarchy-cmd-missing"
cat >"$restart_bin/qs" <<'SH'
#!/bin/bash
printf '%s\n' "$*" >>"$OMARCHY_TEST_IPC_LOG"
case "$*" in
*'shell ping')
grep -Fx '303' "$OMARCHY_TEST_QS_STATE" >/dev/null && printf 'ok\n'
;;
esac
SH
cat >"$restart_bin/quickshell" <<'SH'
#!/bin/bash
printf '%s\n' "$*" >>"$OMARCHY_TEST_QS_LOG"
case " $* " in
*' kill -p '*)
pid=$(head -n 1 "$OMARCHY_TEST_QS_STATE")
[[ $pid =~ ^[0-9]+$ ]] || exit 1
kill "$pid" 2>/dev/null
while kill -0 "$pid" 2>/dev/null; do sleep 0.01; done
awk 'NR > 1' "$OMARCHY_TEST_QS_STATE" >"$OMARCHY_TEST_QS_STATE.next"
mv "$OMARCHY_TEST_QS_STATE.next" "$OMARCHY_TEST_QS_STATE"
;;
*' -n -p '*)
printf '%s\n' "${OMARCHY_TEST_TRANSIENT_ENV-unset}" >"$OMARCHY_TEST_QS_ENV_LOG"
printf '303\n' >"$OMARCHY_TEST_QS_STATE"
;;
esac
SH
cat >"$restart_bin/hyprctl" <<'SH'
#!/bin/bash
if [[ ${1:-} == "-j" && ${2:-} == "monitors" ]]; then
if [[ ${OMARCHY_TEST_SESSION_LOCKED:-0} == 1 ]]; then
printf '[{"activeWorkspace":{"name":"LOCK"}}]\n'
else
printf '[]\n'
fi
elif [[ ${1:-} == "dispatch" && ${2:-} == hl.dsp.exec_cmd* ]]; then
printf '%s\n' "${2:-}" >>"$OMARCHY_TEST_DISPATCH_LOG"
env -u OMARCHY_TEST_TRANSIENT_ENV quickshell -n -p "$OMARCHY_PATH/shell"
printf 'ok\n'
elif [[ ${1:-} == "dispatch" ]]; then
exit 1
fi
SH
chmod +x "$restart_bin/qs" "$restart_bin/quickshell" "$restart_bin/hyprctl"
sleep 30 &
restart_pid_one=$!
sleep 30 &
restart_pid_two=$!
printf '%s\n%s\n' "$restart_pid_one" "$restart_pid_two" >"$restart_state"
PATH="$restart_bin:$PATH" \
OMARCHY_PATH="$restart_root" \
XDG_RUNTIME_DIR="$runtime_dir" \
OMARCHY_TEST_QS_STATE="$restart_state" \
OMARCHY_TEST_QS_LOG="$restart_log" \
OMARCHY_TEST_QS_ENV_LOG="$restart_env_log" \
OMARCHY_TEST_DISPATCH_LOG="$dispatch_log" \
OMARCHY_TEST_IPC_LOG="$ipc_log" \
OMARCHY_TEST_TRANSIENT_ENV=leaked \
timeout 5 "$ROOT/bin/omarchy-restart-shell"
if kill -0 "$restart_pid_one" 2>/dev/null; then
fail "restart stops the first matching shell instance"
fi
if kill -0 "$restart_pid_two" 2>/dev/null; then
fail "restart stops duplicate matching shell instances"
fi
wait "$restart_pid_one" 2>/dev/null || true
wait "$restart_pid_two" 2>/dev/null || true
restart_pid_one=""
restart_pid_two=""
[[ $(<"$restart_state") == 303 ]] || fail "restart leaves exactly one fresh shell instance"
[[ $(grep -c '^-n -p ' "$restart_log") == 1 ]] || fail "restart launches one fresh shell process"
[[ $(<"$restart_env_log") == "unset" ]] || fail "restart uses the Hyprland session environment for the fresh shell"
grep -F 'hl.dsp.exec_cmd("quickshell -n -p $OMARCHY_PATH/shell")' "$dispatch_log" >/dev/null || fail "restart launches the fresh shell through Hyprland"
grep -F 'shell ping' "$ipc_log" >/dev/null || fail "restart waits for fresh shell IPC readiness"
pass "restart replaces duplicate shell instances"
: >"$restart_log"
printf '404\n' >"$restart_state"
locked_error=$(PATH="$restart_bin:$PATH" \
OMARCHY_PATH="$restart_root" \
XDG_RUNTIME_DIR="$runtime_dir" \
OMARCHY_TEST_SESSION_LOCKED=1 \
OMARCHY_TEST_QS_STATE="$restart_state" \
OMARCHY_TEST_QS_LOG="$restart_log" \
OMARCHY_TEST_DISPATCH_LOG="$dispatch_log" \
OMARCHY_TEST_IPC_LOG="$ipc_log" \
"$ROOT/bin/omarchy-restart-shell" 2>&1) && fail "restart refuses while the shell lock is active"
[[ $locked_error == "Refusing to restart Omarchy shell while the session is locked." ]] || fail "locked restart explains why it was refused" "$locked_error"
[[ $(<"$restart_state") == 404 ]] || fail "locked restart preserves the running shell"
[[ ! -s $restart_log ]] || fail "locked restart does not stop or launch Quickshell"
pass "restart preserves the shell while its lock is active"