Skip to content

Commit b519a75

Browse files
mikolalysenkoclaude
andcommitted
test(setup-matrix): verify patches by RUNNING the code, not grepping the file
The matrix decided "applied" by scanning the patched file for the marker string. Now it actually EXECUTES the patched module with the ecosystem's standard runner and checks for the marker in the runtime output: npm/yarn/pnpm -> node <file> bun -> bun <file> deno -> deno run pip -> ./venv/bin/python <file> uv -> uv run python poetry/pdm/hatch -> *run python To make the patched code observable at runtime, the committed blob is now runnable: `console.log("MARKER")` for JS, `print("MARKER")` for Python. Compiled/loaded ecosystems we can't execute (cargo/go/maven/nuget/gem/ composer) keep an inert comment and fall back to reading the file (`cat`), preserving today's behavior for those gaps. verify_applied() runs every resolved copy of the file (covers hoisting, the pnpm store, and workspace/monorepo member dirs) and ORs the results. Also fixes a parallel-test race: the blob was written to a fixed /tmp/sm_blob, so concurrent package-manager test fns clobbered each other's fixture (afterHash mismatch -> apply no-op). Each case now uses its own mktemp file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 29d6523 commit b519a75

1 file changed

Lines changed: 62 additions & 12 deletions

File tree

tests/setup_matrix/run-case.sh

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,20 @@ SHIM
136136
}
137137

138138
# --- committed patch fixture ------------------------------------------
139+
# The patched blob is RUNNABLE code that emits the marker on stdout when the
140+
# file is executed, so verification can RUN the patched module with the
141+
# ecosystem's standard runner (node/bun/python) and observe the marker at
142+
# runtime — not merely scan the file for the string. Compiled/loaded
143+
# ecosystems we can't execute keep an inert comment (verified by reading the
144+
# file; see `run_file`).
145+
marker_blob() { # $1 = marker -> runnable payload on stdout
146+
case "$SM_ECOSYSTEM" in
147+
npm|deno|monorepo) printf 'console.log("%s");\n' "$1" ;;
148+
pypi) printf 'print("%s")\n' "$1" ;;
149+
*) printf '/* %s */\n' "$1" ;;
150+
esac
151+
}
152+
139153
write_manifest() { # $1=purl $2=key $3=afterHash
140154
cat > .socket/manifest.json <<EOF
141155
{
@@ -164,25 +178,31 @@ build_fixture() {
164178
return
165179
fi
166180
mkdir -p .socket/blobs
181+
# Per-case scratch file for the blob. MUST NOT be a fixed path like
182+
# /tmp/sm_blob: the Rust matrix wrappers run the package-manager test fns in
183+
# parallel, so a shared path races (one case hashes a blob another just
184+
# overwrote → afterHash mismatch → apply no-ops).
185+
local blob_tmp; blob_tmp="$(mktemp)"
167186
case "$SM_PATCHSET" in
168187
empty)
169188
printf '{"patches":{}}\n' > .socket/manifest.json
170189
note "empty manifest" ;;
171190
wrong)
172191
# A patch for a package that is NOT installed: nothing should match.
173-
local body="/* $SM_MARKER */"; printf '%s\n' "$body" > /tmp/sm_blob
174-
local h; h="$(git_sha256 /tmp/sm_blob)"; cp /tmp/sm_blob ".socket/blobs/$h"
192+
marker_blob "$SM_MARKER" > "$blob_tmp"
193+
local h; h="$(git_sha256 "$blob_tmp")"; cp "$blob_tmp" ".socket/blobs/$h"
175194
write_manifest "$WRONG_PURL" "$SM_MANIFEST_KEY" "$h"
176195
note "manifest targets absent purl $WRONG_PURL" ;;
177196
alt)
178-
local body="/* $SM_ALT_MARKER */"; printf '%s\n' "$body" > /tmp/sm_blob
179-
local h; h="$(git_sha256 /tmp/sm_blob)"; cp /tmp/sm_blob ".socket/blobs/$h"
197+
marker_blob "$SM_ALT_MARKER" > "$blob_tmp"
198+
local h; h="$(git_sha256 "$blob_tmp")"; cp "$blob_tmp" ".socket/blobs/$h"
180199
write_manifest "$SM_PURL" "$SM_MANIFEST_KEY" "$h" ;;
181200
*) # primary
182-
local body="/* $SM_MARKER */"; printf '%s\n' "$body" > /tmp/sm_blob
183-
local h; h="$(git_sha256 /tmp/sm_blob)"; cp /tmp/sm_blob ".socket/blobs/$h"
201+
marker_blob "$SM_MARKER" > "$blob_tmp"
202+
local h; h="$(git_sha256 "$blob_tmp")"; cp "$blob_tmp" ".socket/blobs/$h"
184203
write_manifest "$SM_PURL" "$SM_MANIFEST_KEY" "$h" ;;
185204
esac
205+
rm -f "$blob_tmp"
186206
}
187207

188208
# --- per-PM project scaffold (must exist before setup runs) -----------
@@ -467,24 +487,54 @@ reset_modules() {
467487
rm -rf node_modules packages/*/node_modules 2>/dev/null || true
468488
}
469489

470-
# Resolve every on-disk copy of the patched file and decide whether the patch
471-
# was applied (marker present). Sets APPLIED / PRIMARY_PRESENT / TARGET.
490+
# Execute a single patched file with the ecosystem's STANDARD runner so the
491+
# patched code actually runs; its stdout/stderr (where the marker would be
492+
# printed) is emitted for the caller to inspect. npm→node, bun→bun, deno→deno,
493+
# pip→the venv's python3, uv→uv run, poetry/pdm/hatch→their `run`. For
494+
# compiled/loaded ecosystems we cannot execute (cargo/go/maven/nuget/gem/
495+
# composer) we `cat` the file so its inert marker comment is still observed —
496+
# matching the previous file-based behavior for those gaps.
497+
run_file() { # $1 = absolute path to the resolved package file
498+
case "$SM_ECOSYSTEM" in
499+
npm|monorepo)
500+
case "$SM_PM" in
501+
bun) bun "$1" ;;
502+
*) node "$1" ;;
503+
esac ;;
504+
deno) deno run -A "$1" ;;
505+
pypi)
506+
case "$SM_PM" in
507+
uv) uv run python "$1" ;;
508+
poetry) poetry run python "$1" ;;
509+
pdm) pdm run python "$1" ;;
510+
hatch) hatch run python "$1" ;;
511+
pip) ./venv/bin/python "$1" ;;
512+
*) python3 "$1" ;;
513+
esac ;;
514+
*) cat "$1" ;;
515+
esac
516+
}
517+
518+
# Decide whether the patch was applied by RUNNING every on-disk copy of the
519+
# patched file and checking whether the marker appears in its runtime output.
520+
# Sets APPLIED / PRIMARY_PRESENT / TARGET.
472521
verify_applied() {
473522
local check_marker="$SM_MARKER"
474523
[ "$SM_PATCHSET" = alt ] && check_marker="$SM_ALT_MARKER"
475524
APPLIED=false
476525
PRIMARY_PRESENT=null
477526
TARGET=""
478-
local n_found=0 cand
527+
local n_found=0 cand out
479528
while IFS= read -r cand; do
480529
[ -n "$cand" ] && [ -f "$cand" ] || continue
481530
n_found=$((n_found + 1))
482531
[ -z "$TARGET" ] && TARGET="$cand"
483-
if grep -q "$check_marker" "$cand" 2>/dev/null; then APPLIED=true; TARGET="$cand"; fi
484-
if grep -q "$SM_MARKER" "$cand" 2>/dev/null; then PRIMARY_PRESENT=true; fi
532+
out="$(run_file "$cand" 2>&1)"
533+
if printf '%s' "$out" | grep -q "$check_marker"; then APPLIED=true; TARGET="$cand"; fi
534+
if printf '%s' "$out" | grep -q "$SM_MARKER"; then PRIMARY_PRESENT=true; fi
485535
done < <(resolve_targets)
486536
[ "$PRIMARY_PRESENT" = null ] && [ "$n_found" -gt 0 ] && PRIMARY_PRESENT=false
487-
log "verify: marker '$check_marker' present=$APPLIED (candidates=$n_found, target=${TARGET:-<none>})"
537+
log "verify(run): marker '$check_marker' in runtime output=$APPLIED (candidates=$n_found, target=${TARGET:-<none>})"
488538
}
489539

490540
# npm-family is the surface `setup` actually configures today — the only place

0 commit comments

Comments
 (0)