diff --git a/scripts/redeploy-fleetd.sh b/scripts/redeploy-fleetd.sh index 1cb18d5..e3b0fb6 100755 --- a/scripts/redeploy-fleetd.sh +++ b/scripts/redeploy-fleetd.sh @@ -178,22 +178,44 @@ swap_staged_jar() { may recover this once you find out why the move failed." } -# fleetd #521: extracted so the suite can call this decision directly, the same way #510 extracted -# wait_for_daemon_exit (so its ordering became checkable) and #517 extracted drain_gate_refusal (so -# its abort branch became checkable) — see the comments above each. Before this, the only test of -# the swap step was test_swap_ordered_after_wait_and_before_start, a SOURCE-POSITION test: it checks -# where swap_staged_jar's call site sits relative to wait_for_daemon_exit and the start step, by -# reading this script's own text. Mutating the swap step's guard (`if [ "$DO_BUILD" = 1 ]` -> `if -# false`) leaves every one of those line positions unchanged, so that test stayed green while the -# swap never ran — a live redeploy would then start (or try to start) with no jar at the live path, -# since stage_built_jar already moved it out during the build step above, regardless of this guard. -# Pure: decides only whether a swap should happen, no side effects, so a test can call it directly -# with both values of do_build instead of driving the real build/stop/start flow. +# fleetd #521 — the swap decision, and the step that acts on it. +# +# The defect: the swap step used to be guarded inline by `if [ "$DO_BUILD" = 1 ]` in the main flow. +# Changing that to `if false` left the suite green and the swap never ran, so a redeploy reported +# every step succeeding while the daemon started on no jar at all (stage_built_jar has already moved +# the freshly built one to $JAR_STAGED by then) or on a stale one. +# test_swap_ordered_after_wait_and_before_start could not catch it: it reads this script's own text +# and compares line positions, and a same-line edit moves no line. +# +# Why these are TWO functions, and why the second one exists at all. Extracting only the predicate +# — `should_swap`, which is what #521 asked for — is not enough, and this was measured, not guessed: +# with the main flow calling `if should_swap "$DO_BUILD"; then`, changing THAT to `if false; then` +# still left the whole suite at exit 0 with no failures. Tests that call a predicate directly prove +# the predicate is right; nothing makes the code that does the work consult it. Extraction had moved +# the untested decision one level up rather than removing it. +# +# So the decision and the action live together in swap_if_built, and the main flow has no guard of +# its own to get wrong — it calls one function unconditionally. A test then calls swap_if_built with +# both values of do_build and checks whether the swap actually happened, which fails if the guard is +# removed, inverted, or stops being consulted. should_swap stays a separate predicate because it is +# the decision itself and is worth naming and testing on its own. +# +# What this still does not pin: deleting the swap_if_built call from the main flow altogether. That +# is the ordering test's job — its needle is that call site — and no test in this file can do better, +# because sourcing stops before the main flow ever runs (see the SOURCED guard below). should_swap() { local do_build="$1" [ "$do_build" = 1 ] } +swap_if_built() { + local do_build="$1" + should_swap "$do_build" || return 0 + say "swap" + swap_staged_jar "$JAR_STAGED" "$JAR" + ok "jar in place: $(jar_id)" +} + # `launchctl list