diff --git a/scripts/setup-loopback.sh b/scripts/setup-loopback.sh index 7870e89..60fdd80 100755 --- a/scripts/setup-loopback.sh +++ b/scripts/setup-loopback.sh @@ -41,6 +41,9 @@ if [ "$COUNT" -lt 1 ] || [ "$COUNT" -gt "$MAX" ]; then fi END=$((START + COUNT - 1)) +# Announce the range up front — also a tell when two checkouts run different +# package versions with different pool conventions (0.3.x started at 127.0.0.1). +echo "Configuring loopback addresses 127.0.0.$START-127.0.0.$END on lo0..." for i in $(seq $START $END); do # Use a host (/32) netmask, not the implicit class-A /8. Without an explicit netmask, # macOS gives each 127.0.0.x alias a 255.0.0.0 mask, so every alias claims to own the @@ -58,4 +61,23 @@ for i in $(seq $START $END); do $SUDO ifconfig lo0 alias 127.0.0.$i netmask 255.255.255.255 up done -echo "✓ Configured $COUNT loopback addresses (127.0.0.$START-127.0.0.$END)" \ No newline at end of file +# Verify every alias actually landed before claiming success. A partial run +# (expired sudo credential mid-loop, interruption) previously still printed ✓, +# leaving the test runner failing later on the missing addresses. +MISSING=() +LO0_STATE=$(ifconfig lo0) +for i in $(seq $START $END); do + if ! echo "$LO0_STATE" | grep -q "inet 127\.0\.0\.$i "; then + MISSING+=("127.0.0.$i") + fi +done + +if [ ${#MISSING[@]} -gt 0 ]; then + echo "✗ ${#MISSING[@]} loopback address(es) failed to configure. Fix with:" + for addr in "${MISSING[@]}"; do + echo " sudo ifconfig lo0 alias $addr netmask 255.255.255.255 up" + done + exit 1 +fi + +echo "✓ Configured and verified $COUNT loopback addresses (127.0.0.$START-127.0.0.$END)" \ No newline at end of file diff --git a/src/harperLifecycle.ts b/src/harperLifecycle.ts index 0fe4ed2..026ee03 100644 --- a/src/harperLifecycle.ts +++ b/src/harperLifecycle.ts @@ -222,7 +222,7 @@ function getHarperScript(harperBinPath?: string): string { // 1. Explicit option if (harperBinPath) { ok(existsSync(harperBinPath), `Harper script not found at provided harperBinPath: ${harperBinPath}`); - return harperBinPath; + return logResolvedHarperScript(harperBinPath, 'harperBinPath option'); } // 2. Environment variable @@ -232,7 +232,7 @@ function getHarperScript(harperBinPath?: string): string { existsSync(envPath), `Harper script not found at HARPER_INTEGRATION_TEST_INSTALL_SCRIPT path: ${envPath}` ); - return envPath; + return logResolvedHarperScript(envPath, 'HARPER_INTEGRATION_TEST_INSTALL_SCRIPT'); } // 3. Auto-resolve from node_modules @@ -240,7 +240,7 @@ function getHarperScript(harperBinPath?: string): string { const require = createRequire(import.meta.url); const resolved = require.resolve('harper/dist/bin/harper.js'); if (existsSync(resolved)) { - return resolved; + return logResolvedHarperScript(resolved, 'node_modules'); } } catch { // harper package not found in node_modules @@ -251,7 +251,7 @@ function getHarperScript(harperBinPath?: string): string { while (true) { const potentialPath = join(currentDir, 'dist/bin/harper.js'); if (existsSync(potentialPath)) { - return potentialPath; + return logResolvedHarperScript(potentialPath, 'ancestor dist'); } const parentDir = dirname(currentDir); if (parentDir === currentDir) { @@ -269,6 +269,42 @@ function getHarperScript(harperBinPath?: string): string { ); } +const loggedHarperScripts = new Set(); + +/** + * Logs which Harper binary was resolved and how, once per distinct path. + * + * Which binary runs is the single most consequential (and previously invisible) + * decision the harness makes: resolving a stale `harper` package from + * node_modules while the caller expected their local build produces confusing + * wholesale test failures with no hint of the cause. When the `node_modules` + * path wins while `./dist/bin/harper.js` also exists, warn with the override. + */ +function logResolvedHarperScript(scriptPath: string, source: string): string { + if (loggedHarperScripts.has(scriptPath)) return scriptPath; + loggedHarperScripts.add(scriptPath); + console.log(`[integration-testing] Using Harper at ${scriptPath} (via ${source})`); + if (source === 'node_modules') { + // Mirror resolution step 4's ancestor walk so the warning fires even when + // tests run from a subdirectory of the repo that holds the local build. + let currentDir = process.cwd(); + while (true) { + const localDist = join(currentDir, 'dist/bin/harper.js'); + if (existsSync(localDist) && localDist !== scriptPath) { + console.warn( + `[integration-testing] Warning: resolved the 'harper' package from node_modules, but ${localDist} also exists. ` + + `If you meant to test the local build, set HARPER_INTEGRATION_TEST_INSTALL_SCRIPT=${localDist}.` + ); + break; + } + const parentDir = dirname(currentDir); + if (parentDir === currentDir) break; + currentDir = parentDir; + } + } + return scriptPath; +} + /** * Strips ANSI escape sequences (colors, bold, underline, cursor movement, etc.) from a string. */