test: add msglib mcp enrichment smoke

This commit is contained in:
zhaoyilun
2026-07-10 03:13:57 +08:00
parent 1277316663
commit 10e7a616c6
5 changed files with 243 additions and 14 deletions

View File

@@ -0,0 +1,173 @@
param(
[string]$SidecarExe = "runs/msglib-sidecar/MsgLibReadSidecar.exe",
[string]$SQLiteDllPath = $env:ISPHERE_MSGLIB_SQLITE_DLL,
[string]$DbPath = $env:ISPHERE_MSGLIB_DB,
[switch]$SkipBuild
)
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
$sidecarPath = Join-Path $repo $SidecarExe
$harnessDir = Join-Path $repo ("runs\msglib-mcp-enrichment-harness-" + [guid]::NewGuid().ToString("N"))
$harnessMain = Join-Path $harnessDir "main.go"
function Assert-True([bool]$Condition, [string]$Message) {
if (-not $Condition) { throw $Message }
}
if (-not $SQLiteDllPath -or -not (Test-Path -LiteralPath $SQLiteDllPath)) {
throw "SQLite DLL not found; set ISPHERE_MSGLIB_SQLITE_DLL or pass -SQLiteDllPath"
}
if (-not $DbPath -or -not (Test-Path -LiteralPath $DbPath)) {
throw "MsgLib DB not found; set ISPHERE_MSGLIB_DB or pass -DbPath"
}
try {
Push-Location $repo
try {
if (-not $SkipBuild) {
& powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $repo "scripts\build-msglib-sidecar.ps1") | Out-Host
if ($LASTEXITCODE -ne 0) { throw "build-msglib-sidecar.ps1 failed with exit code $LASTEXITCODE" }
}
Assert-True (Test-Path -LiteralPath $sidecarPath) "sidecar not found: $sidecarPath"
New-Item -ItemType Directory -Force -Path $harnessDir | Out-Null
@'
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"sort"
"time"
"github.com/modelcontextprotocol/go-sdk/mcp"
"isphere-ai-bridge/internal/mcpserver"
)
type summary struct {
Count int `json:"count"`
Sources []string `json:"sources"`
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
serverTransport, clientTransport := mcp.NewInMemoryTransports()
server, err := mcpserver.NewServerFromEnv()
if err != nil { fail("server_config", err) }
serverErr := make(chan error, 1)
go func() { serverErr <- server.Run(ctx, serverTransport) }()
client := mcp.NewClient(&mcp.Implementation{Name: "verify-msglib-mcp-enrichment", Version: "0.1.0"}, nil)
session, err := client.Connect(ctx, clientTransport, nil)
if err != nil { fail("connect", err) }
defer func() {
_ = session.Close()
cancel()
select {
case <-serverErr:
case <-time.After(2*time.Second):
fail("server_shutdown", fmt.Errorf("server did not stop"))
}
}()
contacts := callSearch(ctx, session, "isphere_search_contacts", "contacts")
groups := callSearch(ctx, session, "isphere_search_groups", "groups")
if contacts.Count == 0 { fail("contacts", fmt.Errorf("no msglib_readonly contacts returned")) }
if groups.Count == 0 { fail("groups", fmt.Errorf("no msglib_readonly groups returned")) }
out := map[string]any{
"ok": true,
"verification": "msglib_mcp_enrichment",
"contact_count": contacts.Count,
"contact_sources": contacts.Sources,
"group_count": groups.Count,
"group_sources": groups.Sources,
"printed_entity_values": false,
"message_bodies_returned": false,
"raw_rows_returned": false,
}
encoded, _ := json.Marshal(out)
fmt.Println(string(encoded))
}
func callSearch(ctx context.Context, session *mcp.ClientSession, tool string, field string) summary {
result, err := session.CallTool(ctx, &mcp.CallToolParams{Name: tool, Arguments: map[string]any{
"query": "",
"source_preference": "auto",
"cursor": "",
"limit": 5,
}})
if err != nil { fail(tool, err) }
if result.IsError { fail(tool, fmt.Errorf("tool returned isError=true")) }
payload, _ := json.Marshal(result.StructuredContent)
var decoded map[string]any
if err := json.Unmarshal(payload, &decoded); err != nil { fail(tool+"_decode", err) }
values, ok := decoded[field].([]any)
if !ok { fail(tool+"_shape", fmt.Errorf("%s missing or not array", field)) }
sourceSet := map[string]bool{}
count := 0
for _, value := range values {
item, ok := value.(map[string]any)
if !ok { continue }
source, _ := item["source"].(string)
if source != "msglib_readonly" { continue }
rawRef, _ := item["raw_ref"].(string)
if rawRef != "" { sourceSet[rawRef] = true }
count++
}
sources := make([]string, 0, len(sourceSet))
for source := range sourceSet { sources = append(sources, source) }
sort.Strings(sources)
return summary{Count: count, Sources: sources}
}
func fail(step string, err error) {
encoded, _ := json.Marshal(map[string]any{"ok": false, "step": step, "error": err.Error()})
fmt.Fprintln(os.Stderr, string(encoded))
os.Exit(1)
}
'@ | Set-Content -LiteralPath $harnessMain -Encoding UTF8
$oldSidecar = $env:ISPHERE_MSGLIB_SIDECAR_EXE
$oldDll = $env:ISPHERE_MSGLIB_SQLITE_DLL
$oldDb = $env:ISPHERE_MSGLIB_DB
$env:ISPHERE_MSGLIB_SIDECAR_EXE = (Resolve-Path -LiteralPath $sidecarPath).Path
$env:ISPHERE_MSGLIB_SQLITE_DLL = (Resolve-Path -LiteralPath $SQLiteDllPath).Path
$env:ISPHERE_MSGLIB_DB = (Resolve-Path -LiteralPath $DbPath).Path
try {
Push-Location $harnessDir
try {
$output = & go run .
if ($LASTEXITCODE -ne 0) { throw "go run MCP enrichment harness failed with exit code $LASTEXITCODE" }
$output | ForEach-Object { Write-Host $_ }
$lastLine = @($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | Select-Object -Last 1
$json = $lastLine | ConvertFrom-Json
}
finally { Pop-Location }
}
finally {
$env:ISPHERE_MSGLIB_SIDECAR_EXE = $oldSidecar
$env:ISPHERE_MSGLIB_SQLITE_DLL = $oldDll
$env:ISPHERE_MSGLIB_DB = $oldDb
}
Assert-True ($json.ok -eq $true) "harness did not return ok=true"
Assert-True ($json.printed_entity_values -eq $false) "harness must not print entity values"
Assert-True ($json.contact_count -gt 0) "contact_count should be > 0"
Assert-True ($json.group_count -gt 0) "group_count should be > 0"
}
finally { Pop-Location }
}
finally {
if (Test-Path -LiteralPath $harnessDir) {
Remove-Item -LiteralPath $harnessDir -Recurse -Force
}
}