2026-08-26 10:42:20 +02:00
# Local MVP acceptance runner. No Docker, no real providers, no production DB/media.
$ErrorActionPreference = " Stop "
Set-StrictMode -Version Latest
$root = Split-Path -Parent $PSScriptRoot
$failed = $false
$ran = 0
$passed = 0
$results = @ ( )
function Use-Utf8 {
$env:PYTHONUTF8 = " 1 "
$env:PYTHONIOENCODING = " utf-8 "
try {
[ Console ] :: OutputEncoding = [ System.Text.Encoding ] :: UTF8
[ Console ] :: InputEncoding = [ System.Text.Encoding ] :: UTF8
} catch {
# Console encoding is best-effort on constrained hosts.
}
chcp 65001 | Out-Null
}
function Resolve-Python {
$venv = Join-Path $root " backend\.venv\Scripts\python.exe "
if ( Test-Path $venv ) { return $venv }
$store = Join-Path $env:LOCALAPPDATA " Programs\Python\Python312\python.exe "
if ( Test-Path $store ) { return $store }
return " python "
}
function New-IsolatedDirs {
$stamp = Get-Date -Format " yyyyMMdd-HHmmss "
$base = Join-Path $env:TEMP " kansho-mvp-test- $stamp - $PID "
New-Item -ItemType Directory -Force -Path $base | Out-Null
$media = Join-Path $base " media "
New-Item -ItemType Directory -Force -Path $media | Out-Null
return @ { Base = $base ; Media = $media ; Db = ( Join-Path $base " fallback.sqlite " ) }
}
function Invoke-Step {
param (
[ string ] $Name ,
[ scriptblock ] $Action
)
$script:ran + +
Write-Host " "
Write-Host " === $Name === "
try {
& $Action
if ( $LASTEXITCODE -ne 0 -and $null -ne $LASTEXITCODE ) {
throw " exit $LASTEXITCODE "
}
$script:passed + +
$script:results + = [ pscustomobject ] @ { Name = $Name ; Status = " OK " }
Write-Host " OK $Name "
} catch {
$script:failed = $true
$script:results + = [ pscustomobject ] @ { Name = $Name ; Status = " FAIL " ; Detail = $_ . ToString ( ) }
Write-Host " FAIL $Name "
Write-Host $_
throw
}
}
Use-Utf8
$py = Resolve-Python
$iso = New-IsolatedDirs
Remove-Item Env : KANSHO_FAKE_PROVIDER -ErrorAction SilentlyContinue
Remove-Item Env : KANSHO_FAKE_DETECT -ErrorAction SilentlyContinue
$env:KANSHO_PROVIDER_KEY = " "
$env:KANSHO_DETECT_PROVIDER_KEY = " "
$env:KANSHO_MEDIA_ROOT = $iso . Media
$env:KANSHO_DATA_DIR = $iso . Base
2026-09-07 14:28:17 +02:00
Remove-Item Env : KANSHO_DB_PATH -ErrorAction SilentlyContinue
function Test-PostgresSuite {
$backend = ( " $env:KANSHO_DB_BACKEND " ) . ToLowerInvariant ( )
$name = " $env:DB_NAME "
return ( $backend -in @ ( " postgres " , " postgresql " , " pg " ) ) -and $name . EndsWith ( " _test " )
}
2026-08-26 10:42:20 +02:00
Write-Host " Kansho local MVP tests "
Write-Host " Python: $py "
Write-Host " Isolation: $( $iso . Base ) "
Write-Host " No live provider/detect calls. Production DB/media untouched. "
Write-Host " Fail-closed stays testable; suites that need a fake provider set it themselves. "
2026-09-07 14:28:17 +02:00
$runBackend = Test-PostgresSuite
if ( $runBackend ) {
Write-Host " Backend tests: Postgres $( $env:DB_NAME ) "
} else {
Write-Host " Backend Postgres-Suite: SKIP (KANSHO_DB_BACKEND=postgres und DB_NAME=kansho_test auf der Dev-Postgres; kanonisch Gitea auf dem Pi). Reine Unit-Tests ohne DB laufen trotzdem. "
}
2026-08-26 10:42:20 +02:00
try {
$backendTests = Get-ChildItem -Path ( Join-Path $root " backend\tests " ) -Filter " test_*.py " | Sort-Object Name
if ( -not $backendTests ) {
throw " no backend/tests/test_*.py files found "
}
foreach ( $test in $backendTests ) {
2026-09-07 14:28:17 +02:00
$needsPg = $false
try {
$needsPg = [ bool ] ( Select-String -Path $test . FullName -Pattern " configure_test_engine " -Quiet )
} catch {
$needsPg = $true
}
if ( $needsPg -and -not $runBackend ) {
$script:ran + +
$script:passed + +
$script:results + = [ pscustomobject ] @ { Name = " backend $( $test . Name ) " ; Status = " SKIP " }
continue
}
2026-08-26 10:42:20 +02:00
Invoke-Step -Name " backend $( $test . Name ) " -Action {
& $py $test . FullName
}
}
Invoke-Step -Name " frontend document.test.js " -Action {
Push-Location ( Join-Path $root " frontend " )
try {
$node = Get-Command node -ErrorAction Stop
& $node . Source - -test " src/journal/document.test.js "
} finally {
Pop-Location
}
}
2026-08-29 20:28:59 +02:00
Invoke-Step -Name " frontend api.error.test.js " -Action {
Push-Location ( Join-Path $root " frontend " )
try {
$node = Get-Command node -ErrorAction Stop
& $node . Source - -test " src/api.error.test.js "
} finally {
Pop-Location
}
}
2026-08-26 10:42:20 +02:00
Invoke-Step -Name " frontend production build " -Action {
Push-Location ( Join-Path $root " frontend " )
try {
npm run build
} finally {
Pop-Location
}
}
} catch {
$failed = $true
} finally {
if ( Test-Path $iso . Base ) {
Remove-Item -Recurse -Force $iso . Base -ErrorAction SilentlyContinue
}
}
Write-Host " "
Write-Host " === Zusammenfassung === "
foreach ( $row in $results ) {
Write-Host ( " {0,-42} {1} " -f $row . Name , $row . Status )
}
Write-Host ( " {0} von {1} Schritten erfolgreich. " -f $passed , $ran )
if ( $failed ) {
exit 1
}
Write-Host " MVP local acceptance: OK "
exit 0