test(prune): red-prove $OWN_DIR protection under genuine disk pressure
Scenario 9 asserted only that target-$OWN existed, checked right after a no-pressure run (3b) where nothing was ever a candidate for eviction, and prune-cache.sh's self-clear step unconditionally recreates an empty $OWN_DIR whenever the run ends under the percentage floor regardless of what pass 2 did to it. Either way the existence check passed whether or not the pass-2 guard (protected_reason, prune-cache.sh:221) actually protected the directory. Moving that guard's $OWN_DIR check into the pass-1-only predicate — the exact mutation gitdan-actions#26 describes — left all 64 assertions green, confirmed here before the fix. Rewritten to run under a real, shrinking `df` (the scenario-17 pattern: a fake df that re-measures the fixture with `du` on every call, so eviction genuinely lowers the reported pressure), with MIN_FREE_PCT=0 and a clone-headroom floor sized so self-clear's percentage check can never fire — only pass 2's guard decides the outcome. The fixture gives $OWN_DIR real content and an older timestamp than a sibling target dir, sized so the requirement is met by evicting exactly one of them. With the guard removed, $OWN_DIR is the one evicted (LRU-oldest, and self-clear is structurally disabled by MIN_FREE_PCT=0 so there is nothing left to recreate it) — the scenario now fails loudly on the same mutation that left it green before. Restored and reverified green (67 assertions, up from 64) with the guard intact. bash scripts/selftest.sh: all 6 suites green. shellcheck -x --source-path=scripts scripts/*.sh: clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkSjXXtU6JYcN2vPntWhfb
This commit is contained in:
@@ -33,7 +33,16 @@
|
||||
# so evicting it frees almost nothing while costing every future PR its
|
||||
# warm start.
|
||||
# 8. SELF-CLEAR REPORTS LOUDLY to the job summary, not just a log warning.
|
||||
# 9. OWN CACHE NEVER EVICTED by a sibling pass.
|
||||
# 9. OWN CACHE NEVER EVICTED by a sibling pass, genuinely under pressure —
|
||||
# against a real, shrinking `df` (gitdan-actions#26): the static
|
||||
# CACHE_DF_OVERRIDE every other scenario uses never reflects an
|
||||
# eviction, so pass 3's self-clear (`rm -rf "$OWN_DIR"; mkdir -p
|
||||
# "$OWN_DIR"`) fires regardless and recreates an empty OWN_DIR whether
|
||||
# pass 2 touched it or not — existence survives either way, which is
|
||||
# why an existence-only assertion here passed even with the pass-2
|
||||
# guard removed. This one checks CONTENTS, and sizes the requirement
|
||||
# so it is satisfiable without self-clear at all: only pass 2's guard
|
||||
# decides the outcome.
|
||||
# 10. SCOPED TO THE CACHE ROOT — a decoy outside it (standing in for another
|
||||
# project's volume) is never touched.
|
||||
# 11. A LIVE READER MARKER PROTECTS A CACHE the same way a lock file does — a
|
||||
@@ -174,8 +183,54 @@ fi
|
||||
ok "no protected ref's own target dir reaches the merged-branch check"
|
||||
|
||||
echo
|
||||
echo "=== 9: own cache never evicted by a sibling pass ==="
|
||||
assert_kept "$root/target-$OWN" "this run's own cache survives"
|
||||
echo "=== 9: own cache survives a sibling pass genuinely under pressure ==="
|
||||
# A real, shrinking `df` (the scenario-17 pattern), not CACHE_DF_OVERRIDE:
|
||||
# eviction has to actually free space for "pressure eases once enough is
|
||||
# freed" to mean anything. MIN_FREE_PCT=0 and a clone-headroom floor (not
|
||||
# the percentage floor) drive the requirement, so the requirement is an
|
||||
# exact, chosen KB rather than a percentage of a volume size this fixture
|
||||
# would otherwise have to reverse-engineer.
|
||||
rm -rf "$root"; mkdir -p "$root"
|
||||
blob_kb=4096
|
||||
mkdir -p "$root/target-$OWN"
|
||||
head -c $((blob_kb * 1024)) /dev/zero > "$root/target-$OWN/blob"
|
||||
touch -d '2020-01-01' "$root/target-$OWN/.cache-last-used"
|
||||
mkdir -p "$root/target-$LIVE"
|
||||
head -c $((blob_kb * 1024)) /dev/zero > "$root/target-$LIVE/blob"
|
||||
touch -d '2021-01-01' "$root/target-$LIVE/.cache-last-used"
|
||||
# The clone-headroom lookup's base-snapshot candidate — never read for its
|
||||
# content (CACHE_CLONE_HEADROOM_PERCENT=0 below), only for existing so the
|
||||
# floor alone becomes the requirement.
|
||||
mkdir -p "$root/snapshot-$DEV"
|
||||
|
||||
real_du=$(command -v du)
|
||||
used9=$($real_du -sk "$root" | awk '{print $1}')
|
||||
cap9=$(( used9 + 2048 )) # 2 MB to spare: under the requirement, over nothing else
|
||||
mkdir -p "$scratch/bin9"
|
||||
cat > "$scratch/bin9/df" <<DFEOF
|
||||
#!/usr/bin/env bash
|
||||
used=\$($real_du -sk "$root" | awk '{print \$1}')
|
||||
echo "Filesystem 1024-blocks Used Available Capacity Mounted-on"
|
||||
echo "fake $cap9 \$used \$(( $cap9 - used )) 50% $root"
|
||||
DFEOF
|
||||
chmod +x "$scratch/bin9/df"
|
||||
|
||||
# Floor sits strictly between "0 evicted" (2048 KB free) and "1 evicted"
|
||||
# (2048 + blob_kb free) — satisfiable by evicting exactly one candidate.
|
||||
PATH="$scratch/bin9:$outer_path" \
|
||||
CACHE_CLONE_HEADROOM_PERCENT=0 CACHE_CLONE_HEADROOM_FLOOR_KB=$(( 2048 + blob_kb / 2 )) \
|
||||
GITHUB_STEP_SUMMARY="$scratch/summary" \
|
||||
bash "$prune" "$root" "$root/target-$OWN" "dev main" 0 \
|
||||
"$(cache_key unused-clone-probe)" "$DEV" "" \
|
||||
> "$scratch/log" 2>&1 \
|
||||
|| { cat "$scratch/log"; fail "prune-cache.sh exited non-zero"; }
|
||||
assert_kept "$root/target-$OWN" "this run's own cache directory survives a genuinely pressured sibling pass"
|
||||
assert_kept "$root/target-$OWN/blob" "and its contents survive — not a recreated empty directory"
|
||||
assert_gone "$root/target-$LIVE" "the sibling is evicted instead, to make the same room"
|
||||
if grep -q 'self-clear' "$scratch/log"; then
|
||||
fail "own cache was cleared by pass 3, not genuinely spared by pass 2 — this scenario proves nothing"
|
||||
fi
|
||||
ok "the requirement was met by pass 2 alone; pass 3 never ran"
|
||||
|
||||
echo
|
||||
echo "=== 7: target dirs evicted before snapshots ==="
|
||||
|
||||
Reference in New Issue
Block a user