mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 20:34:02 +01:00
412 lines -> 135, with the nine functions in lib/music_detect.sh (133), lib/music_monitor.sh (91) and lib/music_status.sh (85). find_music_services and kill_music_services stay together: the first writes MUSIC_FOUND_PROCESS/MUSIC_FOUND_WINDOW and the second reads them, so splitting between them would thread mutable state across files. The test suite caught what the static checks could not. The harness copies the script into a temp worktree to stub common.sh, and copied exactly one file -- so after the split every source line failed and the script died before any behaviour under test ran. Teaching it to copy lib/ too is a harness fix under decision 8: no assertion changed, the same five checks run, exit 0 before and after. bash -n also earned its keep: the first splice dropped notify_user's closing brace, and shellcheck reported that only as SC1094 "parsing of sourced file failed" against the entry. One rename, not a suppression: monitor_loop's local `music_services` became `active_services` after shellcheck flagged SC2153 against the MUSIC_SERVICES config array now visible in the same file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
177 lines
5.6 KiB
Bash
Executable File
177 lines
5.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Regression tests for the music parallelism daemon's polling cadence.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
|
REPO_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd)
|
|
TARGET_SCRIPT="$REPO_DIR/scripts/periodic_background/digital_wellbeing/music_parallelism.sh"
|
|
|
|
fail() {
|
|
printf 'FAIL: %s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
assert_equals() {
|
|
local expected="$1"
|
|
local actual="$2"
|
|
local context="$3"
|
|
if [[ "$expected" != "$actual" ]]; then
|
|
fail "$context (expected: '$expected', actual: '$actual')"
|
|
fi
|
|
}
|
|
|
|
TMP_DIR=$(mktemp -d)
|
|
cleanup() {
|
|
rm -rf "$TMP_DIR"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
WORKTREE="$TMP_DIR/worktree"
|
|
BIN_DIR="$TMP_DIR/bin"
|
|
|
|
# Mirror the script's real position inside the worktree instead of hardcoding
|
|
# it. music_parallelism.sh sources its library as $SCRIPT_DIR/../../lib/common.sh,
|
|
# so the copy must sit at the same depth below the repo root or that path
|
|
# resolves outside the worktree. When it did, the script silently fell back to
|
|
# the real /usr/local/lib/common.sh and the stub below was never used — the
|
|
# tests then measured the live system and failed as if the daemon were wrong.
|
|
# Deriving the path keeps this correct across future reorganisations.
|
|
TARGET_REL="${TARGET_SCRIPT#"$REPO_DIR"/}"
|
|
if [[ "$TARGET_REL" == "$TARGET_SCRIPT" ]]; then
|
|
fail "TARGET_SCRIPT ($TARGET_SCRIPT) is not below REPO_DIR ($REPO_DIR)"
|
|
fi
|
|
WORKTREE_SCRIPT="$WORKTREE/$TARGET_REL"
|
|
# The library lives at <repo>/scripts/lib/common.sh; keep it relative to the
|
|
# same root rather than assuming how deep the script itself is nested.
|
|
WORKTREE_LIB="$WORKTREE/scripts/lib/common.sh"
|
|
|
|
mkdir -p "$(dirname "$WORKTREE_SCRIPT")" "$(dirname "$WORKTREE_LIB")" "$BIN_DIR"
|
|
cp "$TARGET_SCRIPT" "$WORKTREE_SCRIPT"
|
|
|
|
# The script sources its own libs from $SCRIPT_DIR/lib/. They must travel into
|
|
# the worktree beside it, or every source line fails and the script exits before
|
|
# any behaviour under test runs.
|
|
cp -r "$(dirname "$TARGET_SCRIPT")/lib" "$(dirname "$WORKTREE_SCRIPT")/lib"
|
|
|
|
# Fail loudly if the copy cannot reach the stub, rather than letting the script
|
|
# fall through to the real library and produce a misleading behavioural failure.
|
|
STUB_FROM_SCRIPT="$(dirname "$WORKTREE_SCRIPT")/../../lib/common.sh"
|
|
if [[ "$(realpath -m "$STUB_FROM_SCRIPT")" != "$(realpath -m "$WORKTREE_LIB")" ]]; then
|
|
fail "worktree layout drift: script at $WORKTREE_SCRIPT resolves ../../lib/common.sh to $(realpath -m "$STUB_FROM_SCRIPT"), not the stub at $WORKTREE_LIB"
|
|
fi
|
|
|
|
cat >"$WORKTREE_LIB" <<'EOF'
|
|
#!/bin/bash
|
|
|
|
# Records that the stub — not the real installed common.sh — was sourced.
|
|
if [[ -n ${MUSIC_PARALLELISM_STUB_MARKER:-} ]]; then
|
|
printf 'sourced\n' >"$MUSIC_PARALLELISM_STUB_MARKER"
|
|
fi
|
|
|
|
FOCUS_APPS_WINDOWS=("Mock Focus App")
|
|
FOCUS_APPS_PROCESSES=("mock-focus-proc")
|
|
|
|
is_focus_app_running() {
|
|
if [[ ${MOCK_FOCUS_ACTIVE:-0} -eq 1 ]]; then
|
|
printf '%s\n' "Mock Focus App"
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
get_timestamp() {
|
|
printf '%s\n' "${MOCK_TIMESTAMP:-1000}"
|
|
}
|
|
|
|
log_message() {
|
|
:
|
|
}
|
|
EOF
|
|
chmod +x "$WORKTREE_LIB"
|
|
|
|
create_fake_proc_process() {
|
|
local proc_root="$1"
|
|
local pid="$2"
|
|
local name="$3"
|
|
mkdir -p "$proc_root/$pid"
|
|
printf '%s\n' "$name" >"$proc_root/$pid/comm"
|
|
}
|
|
|
|
run_case() {
|
|
local expected_wait="$1"
|
|
local focus_active="$2"
|
|
local music_proc_name="${3:-}"
|
|
local mode="${4:-instant}"
|
|
local wait_log="$TMP_DIR/wait.log"
|
|
local proc_root="$TMP_DIR/proc"
|
|
local stub_marker="$TMP_DIR/stub.marker"
|
|
|
|
: >"$wait_log"
|
|
rm -f "$stub_marker"
|
|
rm -rf "$proc_root"
|
|
mkdir -p "$proc_root"
|
|
|
|
if [[ -n $music_proc_name ]]; then
|
|
create_fake_proc_process "$proc_root" 4242 "$music_proc_name"
|
|
fi
|
|
|
|
PATH="$BIN_DIR:$PATH" \
|
|
MUSIC_PARALLELISM_TEST_WAIT_LOG="$wait_log" \
|
|
MUSIC_PARALLELISM_TEST_EXIT_AFTER_WAIT=1 \
|
|
MUSIC_PARALLELISM_STUB_MARKER="$stub_marker" \
|
|
XDOTOOL_LOG="${XDOTOOL_LOG:-}" \
|
|
PROC_ROOT="$proc_root" \
|
|
MOCK_FOCUS_ACTIVE="$focus_active" \
|
|
bash "$WORKTREE_SCRIPT" "$mode" \
|
|
>/dev/null 2>&1 || true
|
|
|
|
# Without this the script can source the real /usr/local/lib/common.sh and
|
|
# still "pass" or fail for reasons that have nothing to do with the daemon.
|
|
[[ -f "$stub_marker" ]] \
|
|
|| fail 'stubbed common.sh was not sourced — the script used a different library, so this run measured the live system rather than the mock'
|
|
|
|
assert_equals "$expected_wait" "$(<"$wait_log")" "music_parallelism.sh should pick the expected wait interval"
|
|
}
|
|
|
|
printf 'Checking stable-focus backoff uses the slower interval...\n'
|
|
run_case 15 1
|
|
|
|
printf 'Checking conflict handling uses the faster retry interval...\n'
|
|
run_case 5 1 spotify
|
|
|
|
printf 'Checking idle mode uses the idle interval...\n'
|
|
run_case 30 0
|
|
|
|
printf 'Checking conflict path avoids duplicate xdotool searches...\n'
|
|
xdotool_log="$TMP_DIR/xdotool.log"
|
|
: >"$xdotool_log"
|
|
XDOTOOL_LOG="$xdotool_log"
|
|
|
|
cat >"$BIN_DIR/xdotool" <<'EOF'
|
|
#!/bin/bash
|
|
printf '%s\n' "$1" >> "${XDOTOOL_LOG:?}"
|
|
if [[ ${1:-} == search ]]; then
|
|
exit 1
|
|
fi
|
|
if [[ ${1:-} == windowclose ]]; then
|
|
exit 0
|
|
fi
|
|
exit 0
|
|
EOF
|
|
chmod +x "$BIN_DIR/xdotool"
|
|
|
|
run_case 5 1 spotify
|
|
|
|
search_calls=$(grep -c '^search$' "$xdotool_log" 2>/dev/null || true)
|
|
assert_equals '1' "$search_calls" 'music_parallelism.sh should avoid duplicate xdotool search calls when process-only music is detected'
|
|
|
|
printf 'Checking monitor loop also avoids duplicate xdotool searches...\n'
|
|
: >"$xdotool_log"
|
|
run_case 15 1 spotify monitor
|
|
monitor_search_calls=$(grep -c '^search$' "$xdotool_log" 2>/dev/null || true)
|
|
assert_equals '1' "$monitor_search_calls" 'music_parallelism.sh monitor loop should avoid duplicate xdotool search calls when process-only music is detected'
|
|
|
|
printf 'music_parallelism.sh regression checks passed.\n'
|