fleetd #521: extract should_swap so the swap guard can't be silently disabled
CI / contract (pull_request) Successful in 1m29s
CI / build (pull_request) Successful in 1m29s

Mutating the swap step's guard (if [ "$DO_BUILD" = 1 ] -> if false) left the
whole test suite green: test_swap_ordered_after_wait_and_before_start only
checks source positions, which an in-place if-condition edit never moves.
Extracts the decision into should_swap(do_build), following the same shape as
#510's wait_for_daemon_exit and #517's drain_gate_refusal, with a direct test
for each value.
This commit is contained in:
Dai Ha
2026-09-12 11:42:46 +07:00
parent c71ac231e5
commit c89a375e5d
2 changed files with 34 additions and 1 deletions
+17 -1
View File
@@ -178,6 +178,22 @@ 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.
should_swap() {
local do_build="$1"
[ "$do_build" = 1 ]
}
# `launchctl list <label>` exits 0 iff the label is loaded (registered with launchd) — true whether
# or not it is currently running, which is exactly "supervision is active" for our purposes. Read-
# only: neither helper below changes anything, so both are also safe under --check.
@@ -720,7 +736,7 @@ fi
# NOW is it safe to put the freshly built jar at the path the NEXT `java -jar` (direct, or via
# launchd/systemd's ExecStart) will read from — this mv is the one and only write to $JAR anywhere
# in this script's mutating flow. If it fails, do not start: die() below exits before "start" runs.
if [ "$DO_BUILD" = 1 ]; then
if should_swap "$DO_BUILD"; then
say "swap"
swap_staged_jar "$JAR_STAGED" "$JAR"
ok "jar in place: $(jar_id)"
+17
View File
@@ -365,6 +365,21 @@ test_wait_for_daemon_exit_times_out_if_pid_never_clears() {
source "$ROOT/scripts/redeploy-fleetd.sh" # restore the real running_pid/sleep for later tests
}
# fleetd #521 — the swap step's own guard. Before this, `if [ "$DO_BUILD" = 1 ]` (the swap guard)
# could be mutated to `if false` and every test here still passed: nothing called the decision
# directly, and test_swap_ordered_after_wait_and_before_start below only checks source POSITIONS,
# which a same-line `if [...]` -> `if false` edit never moves. These two tests call should_swap()
# directly instead, so they fail if the swap guard becomes unreachable OR if its logic regresses.
test_should_swap_true_when_build_ran() {
should_swap 1 || fail "should_swap 1 (a build ran and staged a jar) must return true"
}
test_should_swap_false_when_build_skipped() {
if should_swap 0; then
fail "should_swap 0 (--no-build; nothing was staged this run) must return false"
fi
}
# fleetd #493 item 2: "put the swap after that wait, before the start." Sourcing stops before the
# main flow ever runs (see the SOURCED guard in redeploy-fleetd.sh), so the ordering guarantee
# itself — as opposed to the pure functions it's built from — can only be checked by reading the
@@ -670,6 +685,8 @@ test_stage_built_jar_dies_when_build_produced_nothing
test_swap_staged_jar_moves_staged_onto_live
test_swap_staged_jar_dies_without_staged_file
test_swap_staged_jar_dies_when_mv_fails
test_should_swap_true_when_build_ran
test_should_swap_false_when_build_skipped
test_require_no_build_jar_dies_when_absent
test_require_no_build_jar_accepts_present_jar
test_wait_for_daemon_exit_returns_true_once_pid_clears