136 lines
5.3 KiB
PowerShell
136 lines
5.3 KiB
PowerShell
# End-to-end smoke test:
|
|
# start proxy -> run chat cases -> wait batch flush -> verify ClickHouse -> stop proxy.
|
|
param(
|
|
[string]$Model = "gpt-5.4-mini",
|
|
[string]$ApiKey = $env:NEWAPI_KEY,
|
|
[string]$ProxyBase = "http://127.0.0.1:8080"
|
|
)
|
|
|
|
if (-not $ApiKey) { throw "NEWAPI_KEY not set" }
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Section($name) {
|
|
Write-Host ""
|
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
|
Write-Host $name -ForegroundColor Cyan
|
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
|
}
|
|
|
|
Section "Start proxy"
|
|
if (Test-Path proxy.log) { Remove-Item proxy.log -Force }
|
|
if (Test-Path proxy.err.log) { Remove-Item proxy.err.log -Force }
|
|
$proxy = Start-Process -FilePath .\TokenThief.exe -PassThru -RedirectStandardOutput proxy.log -RedirectStandardError proxy.err.log -WindowStyle Hidden
|
|
Write-Host "proxy pid=$($proxy.Id)"
|
|
Start-Sleep -Seconds 2
|
|
$health = & curl.exe -s -o NUL -w "%{http_code}" "$ProxyBase/healthz"
|
|
Write-Host "healthz: $health"
|
|
if ($health -ne "200") {
|
|
Get-Content proxy.log -Tail 30 | Write-Host
|
|
Get-Content proxy.err.log -Tail 30 | Write-Host
|
|
throw "proxy did not start"
|
|
}
|
|
|
|
$results = @{}
|
|
|
|
function CallChat {
|
|
param([string]$Url, [string]$JsonBody)
|
|
|
|
$bodyTmp = New-TemporaryFile
|
|
$headTmp = New-TemporaryFile
|
|
$outTmp = New-TemporaryFile
|
|
# PowerShell 5.1 Set-Content -Encoding UTF8 writes a BOM; newapi rejects BOM-prefixed JSON.
|
|
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
|
[System.IO.File]::WriteAllText($bodyTmp.FullName, $JsonBody, $utf8NoBom)
|
|
|
|
$code = & curl.exe -s -X POST $Url `
|
|
-H "Content-Type: application/json" `
|
|
-H "Authorization: Bearer $ApiKey" `
|
|
-D $headTmp.FullName `
|
|
-o $outTmp.FullName `
|
|
--data-binary "@$($bodyTmp.FullName)" `
|
|
-w "%{http_code}"
|
|
|
|
$rid = ""
|
|
foreach ($line in Get-Content $headTmp.FullName) {
|
|
if ($line -match '^X-Request-Id:\s*(.+)$') {
|
|
$rid = $matches[1].Trim()
|
|
break
|
|
}
|
|
}
|
|
$body = Get-Content $outTmp.FullName -Raw -ErrorAction SilentlyContinue
|
|
if (-not $body) { $body = "" }
|
|
|
|
Remove-Item $bodyTmp.FullName, $headTmp.FullName, $outTmp.FullName -Force -ErrorAction SilentlyContinue
|
|
|
|
return @{ StatusCode = $code; RequestID = $rid; Body = $body }
|
|
}
|
|
|
|
try {
|
|
Section "T1: non-stream chat completions"
|
|
$t1Body = '{"model":"' + $Model + '","messages":[{"role":"user","content":"Say hello in one short sentence."}],"stream":false}'
|
|
$r = CallChat "$ProxyBase/v1/chat/completions" $t1Body
|
|
Write-Host " status=$($r.StatusCode) rid=$($r.RequestID)"
|
|
$preview = if ($r.Body.Length -gt 200) { $r.Body.Substring(0, 200) } else { $r.Body }
|
|
Write-Host " body(first 200): $preview"
|
|
$results.T1 = $r
|
|
|
|
Section "T2: stream chat completions"
|
|
$t2Body = '{"model":"' + $Model + '","messages":[{"role":"user","content":"Say exactly: one two three four five"}],"stream":true}'
|
|
$r = CallChat "$ProxyBase/v1/chat/completions" $t2Body
|
|
Write-Host " status=$($r.StatusCode) rid=$($r.RequestID)"
|
|
$chunkCount = ([regex]::Matches($r.Body, "^data:", "Multiline")).Count
|
|
$hasDone = $r.Body.Contains("[DONE]")
|
|
Write-Host " SSE chunk lines=$chunkCount contains [DONE]=$hasDone body_len=$($r.Body.Length)"
|
|
$results.T2 = $r
|
|
|
|
Section "T3: large body (request_truncated should be true)"
|
|
$bigContent = "x" * (12 * 1024 * 1024)
|
|
$t3Body = '{"model":"' + $Model + '","messages":[{"role":"user","content":"' + $bigContent + '"}],"stream":false,"max_tokens":5}'
|
|
Write-Host " request body size: $($t3Body.Length) bytes"
|
|
$r = CallChat "$ProxyBase/v1/chat/completions" $t3Body
|
|
Write-Host " status=$($r.StatusCode) rid=$($r.RequestID)"
|
|
$preview = if ($r.Body.Length -gt 200) { $r.Body.Substring(0, 200) } else { $r.Body }
|
|
Write-Host " body(first 200): $preview"
|
|
$results.T3 = $r
|
|
|
|
Section "T4: nonexistent model (upstream error response should be logged)"
|
|
$t4Body = '{"model":"definitely-not-a-real-model-xyz","messages":[{"role":"user","content":"hi"}]}'
|
|
$r = CallChat "$ProxyBase/v1/chat/completions" $t4Body
|
|
Write-Host " status=$($r.StatusCode) rid=$($r.RequestID)"
|
|
$preview = if ($r.Body.Length -gt 200) { $r.Body.Substring(0, 200) } else { $r.Body }
|
|
Write-Host " body(first 200): $preview"
|
|
$results.T4 = $r
|
|
|
|
Section "T5: healthz (should not be logged)"
|
|
$code = & curl.exe -s -o NUL -w "%{http_code}" "$ProxyBase/healthz"
|
|
Write-Host " /healthz status=$code"
|
|
|
|
Section "Wait batch flush (4s)"
|
|
Start-Sleep -Seconds 4
|
|
|
|
Section "T6: ClickHouse verification"
|
|
$rids = @()
|
|
foreach ($k in @("T1","T2","T3","T4")) {
|
|
if ($results[$k].RequestID) { $rids += $results[$k].RequestID }
|
|
}
|
|
Write-Host " request_ids: $($rids -join ', ')"
|
|
$env:CHECK_RIDS = ($rids | ConvertTo-Json -Compress)
|
|
if ($rids.Count -eq 1) { $env:CHECK_RIDS = "[`"$($rids[0])`"]" }
|
|
& go run .\tests\scripts\dbcheck\main.go
|
|
Remove-Item Env:CHECK_RIDS -ErrorAction SilentlyContinue
|
|
|
|
} finally {
|
|
Section "Stop proxy"
|
|
Stop-Process -Id $proxy.Id -Force
|
|
Write-Host "tail proxy.log:"
|
|
Get-Content proxy.log -Tail 30 | Write-Host
|
|
if (Test-Path proxy.err.log) {
|
|
$err = Get-Content proxy.err.log -ErrorAction SilentlyContinue
|
|
if ($err) {
|
|
Write-Host "proxy.err.log:"
|
|
$err | Write-Host
|
|
}
|
|
}
|
|
}
|