Building the package showed what reading the tree did not: classroom-dvd still calls classroom-window, classroom-mqtt still calls classroom-notify, and the DVD overlay still imports the icon and stylesheet helpers the dock shared. They go back in, and the write-up now counts what was actually removed rather than what could be. Co-Authored-By: Claude Opus 5 <[email protected]>
309 lines
9.6 KiB
Bash
Executable File
309 lines
9.6 KiB
Bash
Executable File
#!/bin/bash
|
|
set -uo pipefail
|
|
|
|
# Tests the session resolution in classroom-notify-test.
|
|
#
|
|
# The compositor is stood in for by a real background process started with a known
|
|
# environment, so /proc/<pid>/environ is genuine rather than mocked. id,
|
|
# pgrep, runuser and notify-send are shimmed onto PATH so every branch
|
|
# can be reached from an ordinary account.
|
|
#
|
|
# tests/test-classroom-notify-test.sh
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
SCRIPT="$ROOT/scripts/classroom-notify"
|
|
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"; kill "${FAKE_SESSION_PID:-}" 2>/dev/null' EXIT
|
|
|
|
passed=0
|
|
failed=0
|
|
|
|
check() {
|
|
local label="$1" expected="$2" actual="$3"
|
|
|
|
if [[ "$actual" == *"$expected"* ]]; then
|
|
echo " ok $label"
|
|
passed=$((passed + 1))
|
|
else
|
|
echo " FAIL $label"
|
|
echo " expected to contain: $expected"
|
|
echo " got: $actual"
|
|
failed=$((failed + 1))
|
|
fi
|
|
}
|
|
|
|
check_absent() {
|
|
local label="$1" unexpected="$2" actual="$3"
|
|
|
|
if [[ "$actual" != *"$unexpected"* ]]; then
|
|
echo " ok $label"
|
|
passed=$((passed + 1))
|
|
else
|
|
echo " FAIL $label"
|
|
echo " expected NOT to contain: $unexpected"
|
|
echo " got: $actual"
|
|
failed=$((failed + 1))
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------- shims
|
|
|
|
mkdir -p "$WORK/bin"
|
|
|
|
cat > "$WORK/bin/id" <<'SHIM'
|
|
#!/bin/bash
|
|
if [[ "${1:-}" == "-u" && -n "${2:-}" ]]; then
|
|
echo "$FAKE_CLASSROOM_UID"
|
|
exit 0
|
|
fi
|
|
if [[ "${1:-}" == "-u" ]]; then
|
|
echo "$FAKE_CURRENT_UID"
|
|
exit 0
|
|
fi
|
|
exec /usr/bin/id "$@"
|
|
SHIM
|
|
|
|
cat > "$WORK/bin/pgrep" <<'SHIM'
|
|
#!/bin/bash
|
|
case "${!#}" in
|
|
kwin_wayland)
|
|
[[ -n "${FAKE_SESSION_PID:-}" ]] || exit 1
|
|
echo "$FAKE_SESSION_PID"
|
|
;;
|
|
plasmashell)
|
|
[[ "${FAKE_SHELL:-1}" == "1" ]] || exit 1
|
|
echo 4242
|
|
;;
|
|
*)
|
|
exit 1
|
|
;;
|
|
esac
|
|
SHIM
|
|
|
|
cat > "$WORK/bin/runuser" <<'SHIM'
|
|
#!/bin/bash
|
|
echo "runuser $*" >> "$RUNUSER_LOG"
|
|
shift 2
|
|
[[ "${1:-}" == "--" ]] && shift
|
|
exec "$@"
|
|
SHIM
|
|
|
|
cat > "$WORK/bin/notify-send" <<'SHIM'
|
|
#!/bin/bash
|
|
{
|
|
echo "args: $*"
|
|
echo "XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-}"
|
|
echo "DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS:-}"
|
|
echo "WAYLAND_DISPLAY=${WAYLAND_DISPLAY:-}"
|
|
} >> "$NOTIFY_LOG"
|
|
SHIM
|
|
|
|
chmod +x "$WORK/bin"/*
|
|
|
|
export PATH="$WORK/bin:$PATH"
|
|
export NOTIFY_LOG="$WORK/notify.log"
|
|
export RUNUSER_LOG="$WORK/runuser.log"
|
|
export FAKE_CLASSROOM_UID=4000
|
|
export FAKE_CURRENT_UID=4000
|
|
|
|
RUNTIME="$WORK/run"
|
|
mkdir -p "$RUNTIME"
|
|
|
|
# A real unix socket, because the script checks the bus is actually there.
|
|
python3 -c 'import socket, sys; socket.socket(socket.AF_UNIX).bind(sys.argv[1])' \
|
|
"$RUNTIME/bus"
|
|
|
|
run() {
|
|
: > "$NOTIFY_LOG"
|
|
: > "$RUNUSER_LOG"
|
|
"$SCRIPT" "$@" 2>&1
|
|
}
|
|
|
|
start_fake_session() {
|
|
env "$@" sleep 300 &
|
|
FAKE_SESSION_PID=$!
|
|
export FAKE_SESSION_PID
|
|
# Give the exec time to land so /proc/<pid>/environ is populated.
|
|
while [[ ! -r "/proc/$FAKE_SESSION_PID/environ" ]]; do sleep 0.05; done
|
|
}
|
|
|
|
stop_fake_session() {
|
|
[[ -n "${FAKE_SESSION_PID:-}" ]] && kill "$FAKE_SESSION_PID" 2>/dev/null
|
|
wait "${FAKE_SESSION_PID:-}" 2>/dev/null
|
|
unset FAKE_SESSION_PID
|
|
}
|
|
|
|
unset WAYLAND_DISPLAY DBUS_SESSION_BUS_ADDRESS
|
|
|
|
# --------------------------------------------- 1. resolve from environ
|
|
|
|
echo "1. resolves the session from the compositor's environment"
|
|
|
|
start_fake_session \
|
|
XDG_RUNTIME_DIR="$RUNTIME" \
|
|
DBUS_SESSION_BUS_ADDRESS="unix:path=$RUNTIME/bus" \
|
|
WAYLAND_DISPLAY=wayland-7
|
|
|
|
out="$(run)"
|
|
check "reports delivery to the classroom session" "Sent normal notification to the classroom desktop session" "$out"
|
|
|
|
log="$(cat "$NOTIFY_LOG")"
|
|
check "runtime dir taken from the compositor" "XDG_RUNTIME_DIR=$RUNTIME" "$log"
|
|
check "bus address taken from the compositor" "DBUS_SESSION_BUS_ADDRESS=unix:path=$RUNTIME/bus" "$log"
|
|
check "wayland display from the compositor" "WAYLAND_DISPLAY=wayland-7" "$log"
|
|
check "styling preserved" "--app-name=Ekklesia Classroom" "$log"
|
|
check "default sample title" "DVD Ready" "$log"
|
|
check "default sample body" "A disc is ready to play." "$log"
|
|
|
|
# ------------------------------------------------- 2. dry run reporting
|
|
|
|
echo "2. --dry-run reports the resolved session and sends nothing"
|
|
|
|
out="$(run --dry-run)"
|
|
check "shows the compositor pid" "compositor pid: $FAKE_SESSION_PID" "$out"
|
|
check "shows the runtime dir" "XDG_RUNTIME_DIR: $RUNTIME" "$out"
|
|
check "shows the wayland display" "WAYLAND_DISPLAY: wayland-7" "$out"
|
|
check_absent "nothing was sent" "args:" "$(cat "$NOTIFY_LOG")"
|
|
|
|
# ------------------------------------------------------ 3. urgency/args
|
|
|
|
echo "3. urgency and custom text still work"
|
|
|
|
out="$(run --critical "Parent Call" "Room 3 needs a parent.")"
|
|
log="$(cat "$NOTIFY_LOG")"
|
|
check "critical urgency passed" "--urgency=critical" "$log"
|
|
check "custom title passed" "Parent Call" "$log"
|
|
check "custom body passed" "Room 3 needs a parent." "$log"
|
|
|
|
# ------------------------------------------------ 4. root uses runuser
|
|
|
|
echo "4. root delivers as the classroom user"
|
|
|
|
FAKE_CURRENT_UID=0
|
|
out="$(run)"
|
|
check "runuser targets classroom" "runuser -u classroom --" "$(cat "$RUNUSER_LOG")"
|
|
check "notification still sent" "--app-name=Ekklesia Classroom" "$(cat "$NOTIFY_LOG")"
|
|
FAKE_CURRENT_UID=4000
|
|
|
|
# ------------------------------------ 5. unprivileged admin is told how
|
|
|
|
echo "5. an unprivileged administrator gets told what to do"
|
|
|
|
FAKE_CURRENT_UID=9999
|
|
out="$(run)"
|
|
check "explains it needs root" "run this as root (sudo classroom-notify)" "$out"
|
|
check_absent "nothing was sent" "args:" "$(cat "$NOTIFY_LOG")"
|
|
FAKE_CURRENT_UID=4000
|
|
|
|
# ------------------------------- 6. the shell must already be up
|
|
|
|
echo "6. refuses to let D-Bus start a notification service"
|
|
|
|
export FAKE_SHELL=0
|
|
out="$(run)"
|
|
check "explains the shell is not running" "the classroom shell is not running" "$out"
|
|
check_absent "nothing was sent" "args:" "$(cat "$NOTIFY_LOG")"
|
|
unset FAKE_SHELL
|
|
|
|
stop_fake_session
|
|
|
|
# --------------------------------- 7. display derived from the lock fd
|
|
|
|
echo "7. derives the display from the compositor's wayland lock when environ has none"
|
|
|
|
touch "$RUNTIME/wayland-9.lock"
|
|
env -u WAYLAND_DISPLAY \
|
|
XDG_RUNTIME_DIR="$RUNTIME" \
|
|
DBUS_SESSION_BUS_ADDRESS="unix:path=$RUNTIME/bus" \
|
|
bash -c "exec 9< '$RUNTIME/wayland-9.lock'; sleep 300" &
|
|
FAKE_SESSION_PID=$!
|
|
export FAKE_SESSION_PID
|
|
while [[ ! -r "/proc/$FAKE_SESSION_PID/fd/9" ]]; do sleep 0.05; done
|
|
|
|
out="$(run --dry-run)"
|
|
check "display derived from the lock" "WAYLAND_DISPLAY: wayland-9" "$out"
|
|
|
|
stop_fake_session
|
|
|
|
# ------------------------------------------- 8. no session at all
|
|
|
|
echo "8. says so clearly when no classroom session is running"
|
|
|
|
out="$(run)"
|
|
check "explains there is no session" "no classroom desktop session is running" "$out"
|
|
check_absent "nothing was sent" "args:" "$(cat "$NOTIFY_LOG")"
|
|
|
|
# ------------------------------------- 9. falls back when environ is thin
|
|
|
|
echo "9. falls back to session defaults when the compositor's environment is unreadable"
|
|
|
|
start_fake_session XDG_RUNTIME_DIR="$RUNTIME"
|
|
|
|
out="$(run --dry-run)"
|
|
check "derives the bus from the runtime dir" \
|
|
"DBUS_SESSION_BUS_ADDRESS: unix:path=$RUNTIME/bus" "$out"
|
|
|
|
out="$(run)"
|
|
check "still delivers" "Sent normal notification to the classroom desktop session" "$out"
|
|
check "bus reached notify-send" "DBUS_SESSION_BUS_ADDRESS=unix:path=$RUNTIME/bus" \
|
|
"$(cat "$NOTIFY_LOG")"
|
|
|
|
stop_fake_session
|
|
|
|
# ------------------------------------------ 10. missing bus is explained
|
|
|
|
echo "10. explains a missing session bus instead of hanging"
|
|
|
|
MISSING="$WORK/empty"
|
|
mkdir -p "$MISSING"
|
|
start_fake_session XDG_RUNTIME_DIR="$MISSING"
|
|
|
|
out="$(run)"
|
|
check "names the missing socket" "bus socket $MISSING/bus does not exist" "$out"
|
|
check_absent "nothing was sent" "args:" "$(cat "$NOTIFY_LOG")"
|
|
|
|
stop_fake_session
|
|
|
|
# ----------------------------- 11. already inside the classroom session
|
|
|
|
echo "11. sends directly when already inside the classroom session"
|
|
|
|
# No compositor process to find: an in-session caller must not need one.
|
|
export WAYLAND_DISPLAY=wayland-4
|
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=$RUNTIME/bus"
|
|
export XDG_RUNTIME_DIR="$RUNTIME"
|
|
|
|
out="$(run)"
|
|
check "reports delivery to this session" "Sent normal notification to this session" "$out"
|
|
check "notification was sent" "--app-name=Ekklesia Classroom" "$(cat "$NOTIFY_LOG")"
|
|
check "inherits the session display" "WAYLAND_DISPLAY=wayland-4" "$(cat "$NOTIFY_LOG")"
|
|
check_absent "did not go through runuser" "runuser" "$(cat "$RUNUSER_LOG")"
|
|
|
|
out="$(run --dry-run)"
|
|
check "dry run names this session" "Would notify this session" "$out"
|
|
|
|
unset WAYLAND_DISPLAY DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR
|
|
|
|
# --------------------------------- 12. classroom-notify-test delegates
|
|
|
|
echo "12. the sample sender delegates to classroom-notify"
|
|
|
|
export WAYLAND_DISPLAY=wayland-4
|
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=$RUNTIME/bus"
|
|
export XDG_RUNTIME_DIR="$RUNTIME"
|
|
|
|
: > "$NOTIFY_LOG"
|
|
out="$("$ROOT/scripts/classroom-notify-test" 2>&1)"
|
|
check "sample still reports being sent" "Sent normal notification" "$out"
|
|
check "sample title unchanged" "DVD Ready" "$(cat "$NOTIFY_LOG")"
|
|
check "sample body unchanged" "A disc is ready to play." "$(cat "$NOTIFY_LOG")"
|
|
|
|
unset WAYLAND_DISPLAY DBUS_SESSION_BUS_ADDRESS XDG_RUNTIME_DIR
|
|
|
|
# ----------------------------------------------------------- summary
|
|
|
|
echo
|
|
echo "passed: $passed failed: $failed"
|
|
[[ "$failed" -eq 0 ]]
|