Files
codebase-memory-mcp/scripts/test-windows.ps1
T
FlipperandClaude Opus 4.8 0eb2c58913 test(windows): convert fixed reds to green guards, wire CI, rewrite drive test
Rebased onto current main and reworked in response to review. Three of the four
Windows reds were fixed upstream since the branch was cut at b075f05, so they are
now green regression guards; the fourth stays a genuine known-red.

- test_non_ascii_path.py (#636/#357): green guard - fixed by #700 (per-pass
  readers now route through cbm_fopen -> _wfopen). Re-verified green on main.
- test_hook_augment.py (#618): green guard - fixed by #619 (cbm_is_walkable_abs_path
  accepts drive-letter X:/ cwd). Re-verified green on main.
- test_ui_drive_listing.py (#548): rewritten. The fix exposes drives via a new
  roots[] field, not the dirs[] array the old test asserted (which would stay red
  against fixed code). Now asserts every fixed drive is in roots and browsable.
  Re-verified green on main (drives C:/D:/E:).
- test_cli_non_ascii_arg.py (#423/#20): unchanged - main() is still narrow-argv
  with no wide command line, so this remains genuinely red (the keeper).

- scripts/test-windows.ps1: split green guards (gate CI) from opt-in known-reds;
  add -GuardsOnly; run indexing in-process (CBM_INDEX_SUPERVISOR=0) so a guard
  reflects the path/hook/drive fix under test, not the index-worker spawn path.
- .github/workflows/_test.yml: new test-windows-guards job builds the product+UI
  binary (scripts/build.sh --with-ui) and runs the guards with -GuardsOnly so
  #700/#619/#548 stay enforced on Windows CI.
- RED_TEST_ANALYSIS.md: refreshed to record the landed fixes and current status.

Signed-off-by: Flipper <jacobphilipp@ymail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 13:22:41 +02:00

167 lines
6.8 KiB
PowerShell

<#
.SYNOPSIS
Run the native-Windows product-surface test suite for codebase-memory-mcp.
.DESCRIPTION
Builds the product binary (build/c/codebase-memory-mcp.exe) if it is not
already present, then runs the deterministic Windows integration tests under
tests/windows/ against a real codebase-memory-mcp.exe (real stdio / CLI /
HTTP UI, real SQLite DB).
Two categories of test:
GUARDS - regression guards for Windows bugs already fixed on main.
They must stay GREEN (exit 0); a RED (exit 1) means the fix
regressed and fails this runner.
* test_non_ascii_path.py guards #636/#357 (fixed by #700)
* test_hook_augment.py guards #618 (fixed by #619)
* test_ui_drive_listing.py guards #548 (roots field)
KNOWN REDS - genuine, still-open Windows bugs reproduced at the product
surface. They are EXPECTED to be RED (exit 1) and are opt-in
(never gate CI). If one turns GREEN the underlying bug was
fixed and it should be promoted to a guard.
* test_cli_non_ascii_arg.py reproduces #423/#20 (narrow
argv main() - no wide command line)
Determinism: indexing runs in-process (CBM_INDEX_SUPERVISOR=0). These tests
exercise path / hook / drive handling, not the index-supervisor subprocess
path; the pass-level readers (#700's cbm_fopen routing) run in-process either
way, so the guard coverage is identical while results stay independent of the
local toolchain's worker-spawn behavior.
On native Windows the MinGW/LLVM toolchain ships no libasan/libubsan, so the
build disables sanitizers (SANITIZE=). Where the toolchain provides
AddressSanitizer/UBSan (Linux containers, WSL), prefer scripts/test.sh.
.PARAMETER Binary
Path to an existing codebase-memory-mcp.exe. If omitted, the script builds it
(target selected by -Target) into build/c/.
.PARAMETER Target
Makefile.cbm target used when building: 'cbm-with-ui' (default; needed for the
drive-picker guard's embedded HTTP UI) or 'cbm' (no UI - the drive guard then
reports a precondition and is skipped).
.PARAMETER GuardsOnly
Run only the green guards (the CI gate). Skips the opt-in known-red repros.
.PARAMETER Make
Path to GNU make (default: 'make' on PATH; MSYS2 ships it at
C:\msys64\usr\bin\make.exe).
.EXAMPLE
pwsh -File scripts/test-windows.ps1
.EXAMPLE
pwsh -File scripts/test-windows.ps1 -GuardsOnly -Binary build\c\codebase-memory-mcp.exe
#>
[CmdletBinding()]
param(
[string]$Binary,
[ValidateSet("cbm-with-ui", "cbm")]
[string]$Target = "cbm-with-ui",
[switch]$GuardsOnly,
[string]$Make = "make"
)
$ErrorActionPreference = "Stop"
$repoRoot = Split-Path -Parent $PSScriptRoot
Set-Location $repoRoot
$python = (Get-Command python -ErrorAction SilentlyContinue)
if (-not $python) { $python = (Get-Command py -ErrorAction SilentlyContinue) }
if (-not $python) { throw "Python 3 is required to run the Windows tests." }
$py = $python.Source
# A writable Windows temp dir that GNU make forwards to the native gcc. MSYS2
# strips TMP/TEMP from the environment it hands native children, so pass them as
# make command-line variables (make exports those to recipe processes).
$tmp = $env:TEMP
if (-not $tmp) { $tmp = "$env:USERPROFILE\AppData\Local\Temp" }
function Resolve-Binary {
param([string]$Explicit)
if ($Explicit) { return (Resolve-Path $Explicit).Path }
$built = Join-Path $repoRoot "build\c\codebase-memory-mcp.exe"
if (Test-Path $built) { return $built }
Write-Host "Building $Target via Makefile.cbm ..." -ForegroundColor Cyan
& $Make "-j" "-f" "Makefile.cbm" $Target "SANITIZE=" "TMP=$tmp" "TEMP=$tmp" "TMPDIR=$tmp"
if ($LASTEXITCODE -ne 0) { throw "build failed (exit $LASTEXITCODE)" }
if (-not (Test-Path $built)) { throw "binary not produced at $built" }
return $built
}
$bin = Resolve-Binary -Explicit $Binary
Write-Host "Binary: $bin" -ForegroundColor Green
$env:PYTHONUTF8 = "1" # encode argv/stdio as UTF-8
$env:CBM_INDEX_SUPERVISOR = "0" # in-process indexing (see .DESCRIPTION)
# Green regression guards - must stay GREEN (exit 0). RED (exit 1) = the fix for
# the referenced issue regressed. The drive-picker guard needs the embedded HTTP
# UI (build target cbm-with-ui); against a non-UI binary it reports a precondition
# (exit 2) and is skipped rather than failed.
$guards = @(
"tests\windows\test_non_ascii_path.py",
"tests\windows\test_hook_augment.py",
"tests\windows\test_ui_drive_listing.py"
)
# Opt-in known-red repros - EXPECTED red (exit 1); never gate CI.
$knownReds = @(
"tests\windows\test_cli_non_ascii_arg.py"
)
$guardFailures = @()
$guardSkips = @()
$fixedKeepers = @()
Write-Host "`n--- Green guards ---" -ForegroundColor Cyan
foreach ($t in $guards) {
Write-Host "`n=== $t ===" -ForegroundColor Cyan
& $py $t $bin
$code = $LASTEXITCODE
if ($code -eq 0) {
Write-Host "GREEN ($t)" -ForegroundColor Green
} elseif ($code -eq 1) {
Write-Host "RED ($t) - REGRESSION: a fixed Windows bug is broken again" -ForegroundColor Red
$guardFailures += $t
} else {
Write-Host "PRECONDITION ($t) exit=$code - skipped (see message above)" -ForegroundColor Yellow
$guardSkips += $t
}
}
if (-not $GuardsOnly) {
Write-Host "`n--- Known reds (opt-in, expected red) ---" -ForegroundColor Cyan
foreach ($t in $knownReds) {
Write-Host "`n=== $t ===" -ForegroundColor Cyan
& $py $t $bin
$code = $LASTEXITCODE
if ($code -eq 1) {
Write-Host "RED ($t) - expected; the underlying Windows bug is still open" -ForegroundColor DarkYellow
} elseif ($code -eq 0) {
Write-Host "GREEN ($t) - the bug appears FIXED; promote this to a guard" -ForegroundColor Green
$fixedKeepers += $t
} else {
Write-Host "PRECONDITION ($t) exit=$code - skipped (see message above)" -ForegroundColor Yellow
}
}
}
Write-Host ""
if ($guardSkips.Count -gt 0) {
Write-Host ("Guards skipped (precondition): {0} - e.g. the drive-picker guard " -f $guardSkips.Count) -ForegroundColor Yellow
Write-Host "needs a UI build (-Target cbm-with-ui, the default)." -ForegroundColor Yellow
}
if ($fixedKeepers.Count -gt 0) {
Write-Host ("Known-red repros that are now GREEN (promote to guards): {0}" -f ($fixedKeepers -join ", ")) -ForegroundColor Green
}
if ($guardFailures.Count -gt 0) {
Write-Host ("REGRESSION: {0} green guard(s) went red: {1}" -f $guardFailures.Count, ($guardFailures -join ", ")) -ForegroundColor Red
Write-Host "A previously-fixed Windows bug is broken again. See tests/windows/RED_TEST_ANALYSIS.md." -ForegroundColor Red
exit 1
}
Write-Host "All Windows green guards passed." -ForegroundColor Green
exit 0