Skip to content

Commit 8bd5380

Browse files
committed
test(e2e): make the locked-destination case unable to pass for the wrong reason
Two holes in 171 as first written: a PowerShell holder that failed to start left the build trivially succeeding (silent pass), and `chmod 444` is toothless under root — which the container e2e job runs as. The holder now signals readiness through a sentinel and the test fails if it never appears, and the load-bearing assertion is inode+mtime+size invariance of the destination: 'nothing was written', not 'the write happened to succeed'.
1 parent cd753e3 commit 8bd5380

1 file changed

Lines changed: 28 additions & 9 deletions

File tree

tests/e2e/171_bmi_staging_locked_dest.sh

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
#!/usr/bin/env bash
22
# requires:
33
# 171_bmi_staging_locked_dest.sh — mcpp#311: staging must survive a destination
4-
# that another process is holding, and must fail LOUDLY when it genuinely can't.
4+
# another process is holding, and must fail LOUDLY when it genuinely can't.
55
#
66
# The reported failure: mcpp writes the staged std BMI path into
77
# compile_commands.json so clangd can resolve `import std;`, clangd
88
# memory-maps that file, and the old `Copy-Item -Force` staging step then tried
99
# to overwrite it in place → Windows error 1224 (a file with a user-mapped
1010
# section open cannot be replaced) → the whole build reported "build failed".
1111
#
12-
# Windows: reproduce it exactly, WITHOUT needing clangd — a background
13-
# PowerShell holds a MemoryMappedFile on the staged BMI.
14-
# POSIX: the closest analogue an ordinary test can create is an unwritable
15-
# destination (chmod 444); the old `cp -f` silently unlinked and rewrote it,
16-
# the new path must not need to write at all.
12+
# Windows: reproduce that exactly and WITHOUT clangd — a background PowerShell
13+
# holds a MemoryMappedFile on the staged BMI. The holder signals readiness
14+
# through a sentinel file, so a PowerShell that never started fails the test
15+
# instead of letting it pass for the wrong reason.
16+
#
17+
# The load-bearing assertion is platform-neutral and root-proof: an equivalent
18+
# destination must not be written AT ALL (same inode, same mtime, same size).
19+
# Permissions alone would not do — root ignores them, and the container e2e job
20+
# runs as root.
1721
set -e
1822

1923
TMP=$(mktemp -d)
@@ -41,18 +45,27 @@ DST="$(dirname "$NINJA")/$(echo "$EDGE" | awk '{print $2}')"
4145
SRC=$(echo "$EDGE" | awk '{print $NF}')
4246
[[ -f "$DST" ]] || { echo "FAIL: staged BMI missing at $DST"; exit 1; }
4347

48+
identity() { stat -c '%i %Y %s' "$1"; }
49+
BEFORE=$(identity "$DST")
50+
4451
# Dirty the staging edge without touching the shared cache's CONTENT.
4552
touch "$SRC"
4653

4754
HOLDER=""
4855
case "$(uname -s)" in
4956
MINGW* | MSYS* | CYGWIN*)
5057
WINDST="$(cygpath -w "$DST")"
58+
READY="$TMP/mapped.flag"
59+
WINREADY="$(cygpath -w "$READY")"
5160
powershell -NoProfile -Command \
52-
"\$mm = [System.IO.MemoryMappedFiles.MemoryMappedFile]::CreateFromFile('$WINDST', [System.IO.FileMode]::Open); Start-Sleep -Seconds 90" &
61+
"\$mm = [System.IO.MemoryMappedFiles.MemoryMappedFile]::CreateFromFile('$WINDST', [System.IO.FileMode]::Open); \
62+
Set-Content -Path '$WINREADY' -Value 'mapped'; Start-Sleep -Seconds 120" &
5363
HOLDER=$!
54-
# Give the mapping time to exist before the build races it.
55-
sleep 3
64+
for _ in $(seq 1 40); do [[ -f "$READY" ]] && break; sleep 1; done
65+
[[ -f "$READY" ]] || {
66+
kill "$HOLDER" 2>/dev/null || true
67+
echo "FAIL: could not map the staged BMI — the test would not have proven anything"
68+
exit 1; }
5669
echo "holding a user-mapped section on $WINDST (pid $HOLDER)"
5770
;;
5871
*)
@@ -75,6 +88,12 @@ if [[ $rc -ne 0 ]]; then
7588
fi
7689
grep -q "stage --output" build2.log || {
7790
cat build2.log; echo "FAIL: the staging edge did not run"; exit 1; }
91+
92+
# The real assertion: nothing was written. Not "the write succeeded anyway".
93+
AFTER=$(identity "$DST")
94+
[[ "$BEFORE" == "$AFTER" ]] || {
95+
echo "FAIL: an equivalent destination was rewritten (was '$BEFORE', now '$AFTER')"
96+
exit 1; }
7897
cmp "$SRC" "$DST" || { echo "FAIL: held destination no longer matches the cache"; exit 1; }
7998

8099
cd "$TMP"

0 commit comments

Comments
 (0)