diff --git a/scripts/prune-cache-selftest.sh b/scripts/prune-cache-selftest.sh index ab0aa17..dc640d0 100755 --- a/scripts/prune-cache-selftest.sh +++ b/scripts/prune-cache-selftest.sh @@ -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" < "$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 ==="