Add bounded Panama recovery actions
This commit is contained in:
@@ -75,15 +75,26 @@ fixture_dir="$(mktemp -d /tmp/panama-health.XXXXXX)"
|
||||
helper="$fixture_dir/panama-doctor"
|
||||
copy_bin="$fixture_dir/bin"
|
||||
copy_file="$fixture_dir/copied-report.json"
|
||||
repair_mode_file="$fixture_dir/repair-mode"
|
||||
repair_log="$fixture_dir/repair.log"
|
||||
notification_log="$fixture_dir/notifications.log"
|
||||
printf 'success\n' >"$repair_mode_file"
|
||||
printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
'printf "%s\n" "$*" >>"$PANAMA_HEALTH_REPAIR_LOG"' \
|
||||
'if [[ "$1" == "--json" ]]; then' \
|
||||
' sleep 0.2' \
|
||||
" printf '%s\\n' '$warning_snapshot'" \
|
||||
' exit 0' \
|
||||
'fi' \
|
||||
'if [[ "$1" == "--repair" && "$2" == "panama.caffeine" && "$3" == "--json" ]]; then' \
|
||||
' exit 0' \
|
||||
' sleep 0.25' \
|
||||
' case "$(cat "$PANAMA_HEALTH_REPAIR_MODE_FILE")" in' \
|
||||
' success) printf "{\"schemaVersion\":1,\"checkId\":\"panama.caffeine\",\"accepted\":true,\"exitCode\":0,\"message\":\"Duplicate inhibitors were released.\"}\\n"; exit 0 ;;' \
|
||||
' failed) printf "{\"schemaVersion\":1,\"checkId\":\"panama.caffeine\",\"accepted\":true,\"exitCode\":7,\"message\":\"Duplicate inhibitors could not be released.\"}\\n"; exit 7 ;;' \
|
||||
' mismatch) printf "{\"schemaVersion\":1,\"checkId\":\"desktop.vicinae\",\"accepted\":true,\"exitCode\":0,\"message\":\"Wrong row.\"}\\n"; exit 0 ;;' \
|
||||
' *) printf "not-json\\n"; exit 0 ;;' \
|
||||
' esac' \
|
||||
'fi' \
|
||||
'exit 2' >"$helper"
|
||||
chmod +x "$helper"
|
||||
@@ -91,9 +102,16 @@ mkdir -p "$copy_bin"
|
||||
printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
'/usr/bin/cat > "$PANAMA_HEALTH_COPY_FILE"' >"$copy_bin/wl-copy"
|
||||
chmod +x "$copy_bin/wl-copy"
|
||||
printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
'printf "%s\n" "$*" >>"$PANAMA_HEALTH_NOTIFICATION_LOG"' >"$copy_bin/notify-send"
|
||||
chmod +x "$copy_bin/wl-copy" "$copy_bin/notify-send"
|
||||
|
||||
run() { PATH="$copy_bin:$PATH" PANAMA_HEALTH_HELPER="$helper" PANAMA_HEALTH_COPY_FILE="$copy_file" qs -p "$harness" "$@"; }
|
||||
run() {
|
||||
PATH="$copy_bin:$PATH" PANAMA_HEALTH_HELPER="$helper" PANAMA_HEALTH_COPY_FILE="$copy_file" \
|
||||
PANAMA_HEALTH_REPAIR_MODE_FILE="$repair_mode_file" PANAMA_HEALTH_REPAIR_LOG="$repair_log" \
|
||||
PANAMA_HEALTH_NOTIFICATION_LOG="$notification_log" qs -p "$harness" "$@"
|
||||
}
|
||||
harness_pid=""
|
||||
|
||||
cleanup() {
|
||||
@@ -103,6 +121,8 @@ cleanup() {
|
||||
trap cleanup EXIT
|
||||
|
||||
PATH="$copy_bin:$PATH" PANAMA_HEALTH_HELPER="$helper" PANAMA_HEALTH_COPY_FILE="$copy_file" \
|
||||
PANAMA_HEALTH_REPAIR_MODE_FILE="$repair_mode_file" PANAMA_HEALTH_REPAIR_LOG="$repair_log" \
|
||||
PANAMA_HEALTH_NOTIFICATION_LOG="$notification_log" \
|
||||
qs -p "$harness" --daemonize >/dev/null
|
||||
for _ in $(seq 1 40); do
|
||||
run ipc show 2>/dev/null | rg -q '^target health-test$' && break
|
||||
@@ -165,25 +185,81 @@ done
|
||||
jq -e '.busy == false and .generation == ($before + 2) and .queuedRefresh == false' --argjson before "$before_generation" \
|
||||
>/dev/null <<<"$state" || fail "queued refresh did not run exactly once: $state"
|
||||
|
||||
printf 'success\n' >"$repair_mode_file"
|
||||
repair_generation="$(jq -r .generation <<<"$state")"
|
||||
[[ "$(run ipc call health-test repair panama.caffeine)" == "true" ]] \
|
||||
|| fail 'repairable check was refused'
|
||||
run ipc call health-test queue >/dev/null
|
||||
working_state="$(run ipc call health-test status)"
|
||||
jq -e '.repairingId == "panama.caffeine" and .queuedRefresh == true
|
||||
and (.checkStates[] | select(.id == "panama.caffeine") | .status) == "warning"' \
|
||||
>/dev/null <<<"$working_state" || fail "repair did not retain the degraded row while working: $working_state"
|
||||
for _ in $(seq 1 120); do
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.busy == false and .generation == ($before + 3)' --argjson before "$before_generation" \
|
||||
jq -e '.busy == false and .generation == ($before + 1) and .queuedRefresh == false' --argjson before "$repair_generation" \
|
||||
>/dev/null <<<"$state" && break
|
||||
sleep 0.1
|
||||
done
|
||||
jq -e '.busy == false and .generation == ($before + 3)' --argjson before "$before_generation" \
|
||||
>/dev/null <<<"$state" || fail "accepted repair did not trigger one rescan: $state"
|
||||
jq -e '.busy == false and .generation == ($before + 1) and .queuedRefresh == false
|
||||
and .lastRepair == {schemaVersion:1, checkId:"panama.caffeine", accepted:true, exitCode:0, message:"Duplicate inhibitors were released."}
|
||||
and (.checkStates[] | select(.id == "panama.caffeine") | .status) == "warning"' \
|
||||
--argjson before "$repair_generation" >/dev/null <<<"$state" \
|
||||
|| fail "accepted repair was trusted before exactly one observed rescan: $state"
|
||||
|
||||
# A syntactically valid command failure remains inline for Settings and still
|
||||
# receives exactly one observed rescan.
|
||||
printf 'failed\n' >"$repair_mode_file"
|
||||
failure_generation="$(jq -r .generation <<<"$state")"
|
||||
[[ "$(run ipc call health-test repair panama.caffeine)" == "true" ]] \
|
||||
|| fail 'second repairable check was refused'
|
||||
for _ in $(seq 1 120); do
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.busy == false and .generation == ($before + 1)' --argjson before "$failure_generation" \
|
||||
>/dev/null <<<"$state" && break
|
||||
sleep 0.1
|
||||
done
|
||||
jq -e '.lastRepair.checkId == "panama.caffeine"
|
||||
and .lastRepair.accepted == true and .lastRepair.exitCode == 7
|
||||
and .lastRepair.message == "Duplicate inhibitors could not be released."
|
||||
and .generation == ($before + 1)' --argjson before "$failure_generation" \
|
||||
>/dev/null <<<"$state" || fail "known repair failure was not retained inline: $state"
|
||||
[[ ! -e "$notification_log" || ! -s "$notification_log" ]] \
|
||||
|| fail 'Settings-originated repair emitted an external notification'
|
||||
|
||||
# A malformed or mismatched helper response is contained and cannot masquerade
|
||||
# as recovery; it also schedules only one scan.
|
||||
printf 'mismatch\n' >"$repair_mode_file"
|
||||
mismatch_generation="$(jq -r .generation <<<"$state")"
|
||||
[[ "$(run ipc call health-test repair panama.caffeine)" == "true" ]] \
|
||||
|| fail 'mismatch repair fixture was refused'
|
||||
for _ in $(seq 1 120); do
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.busy == false and .generation == ($before + 1)' --argjson before "$mismatch_generation" \
|
||||
>/dev/null <<<"$state" && break
|
||||
sleep 0.1
|
||||
done
|
||||
jq -e '.lastRepair.checkId == "panama.caffeine" and .lastRepair.accepted == false
|
||||
and .lastRepair.exitCode == 0 and .generation == ($before + 1)' \
|
||||
--argjson before "$mismatch_generation" >/dev/null <<<"$state" \
|
||||
|| fail "mismatched repair JSON escaped containment: $state"
|
||||
|
||||
[[ "$(run ipc call health-test repair unknown.check)" == "false" ]] \
|
||||
|| fail 'unknown check started a repair'
|
||||
[[ "$(run ipc call health-test repair integration.calendar)" == "false" ]] \
|
||||
|| fail 'non-repairable check started a repair'
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.repairingId == "" and .generation == ($before + 3)' --argjson before "$before_generation" \
|
||||
jq -e '.repairingId == "" and .generation == ($before + 1)' --argjson before "$mismatch_generation" \
|
||||
>/dev/null <<<"$state" || fail "rejected repair altered process state: $state"
|
||||
|
||||
python3 - "$service" <<'PY' || fail 'external repair failure notification is not bounded'
|
||||
import sys
|
||||
|
||||
source = open(sys.argv[1], encoding="utf-8").read()
|
||||
assert 'if (failed && external && !failureNotification.running)' in source
|
||||
assert '"notify-send", "-a", "Panama", "-i", "dialog-error-symbolic"' in source
|
||||
assert '"Panama action failed", "The requested health repair could not be completed."' in source
|
||||
PY
|
||||
|
||||
trap - EXIT
|
||||
cleanup
|
||||
printf 'health service contract: PASS\n'
|
||||
|
||||
Reference in New Issue
Block a user