<# S1:IG 用户发一条文本 → iXserver → 第三方 chatbot(echo 自动回复)→ iXserver → IG 用户收到 echo。 前提:.\loop.ps1 up 各角色都健康,chatbot 以 --auto-reply echo 运行(config\loop.psd1 的 ChatbotAutoReply)。 通过退出 0,失败退出 1 并打印两侧的记录;两种情况都在 run\reports\ 生成场景报告(观察台在跑时)。 用法:.\scenarios\s1-ig-text-echo.ps1 [-TimeoutSec 60] [-NoReport] #> param([int]$TimeoutSec = 60, [switch]$NoReport) $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' $LoopNoReport = [bool]$NoReport . (Join-Path $PSScriptRoot '_lib.ps1') $Cfg = $LoopCfg $ig = "http://127.0.0.1:$($Cfg.Ports.IgMock)" $cb = "http://127.0.0.1:$($Cfg.Ports.Chatbot)" function Fail([string]$why) { Write-Host "S1 失败:$why" -ForegroundColor Red Write-Host '--- IG 模拟记录' (Invoke-RestMethod "$ig/_api/state").events | ForEach-Object { $_ | ConvertTo-Json -Depth 8 -Compress } | Out-Host Write-Host '--- chatbot 记录(最近 6 条)' # 记录是新的在前 (Invoke-RestMethod "$cb/_api/state").events | Select-Object -First 6 | ForEach-Object { $_ | ConvertTo-Json -Depth 8 -Compress } | Out-Host Add-LoopStep $why $false Save-LoopReport -Passed $false -Reason $why exit 1 } Start-LoopRun 'S1' 'IG 文本 → 第三方 echo → IG' Invoke-RestMethod "$ig/_api/clear" -Method Post | Out-Null $text = 'loop-s1 ' + [guid]::NewGuid().ToString('N').Substring(0, 8) $sent = Invoke-RestMethod "$ig/_api/send" -Method Post -ContentType 'application/json; charset=utf-8' -Body (@{ kind = 'text'; text = $text } | ConvertTo-Json) if ($sent.event.response.status -ne 200) { Fail "iXserver 收 webhook 返回 $($sent.event.response.status)" } Add-LoopStep 'iXserver 收下 webhook' $true "「$text」HTTP 200" # 出站是异步的:轮询 IG 模拟的 outbound,带上限 $expected = "echo: $text" $deadline = (Get-Date).AddSeconds($TimeoutSec) $hit = $null while (-not $hit -and (Get-Date) -lt $deadline) { $hit = @((Invoke-RestMethod "$ig/_api/state").events | Where-Object { $_.kind -eq 'outbound' -and $_.summary -eq $expected }) | Select-Object -First 1 if (-not $hit) { Start-Sleep -Milliseconds 500 } } if (-not $hit) { Fail "$TimeoutSec 秒内 iXserver 没有向 IG 用户发出「$expected」" } Add-LoopStep 'iXserver 向 IG 用户发出 echo' $true $expected if (@($hit.issues).Count) { Fail "出站请求有问题:$($hit.issues -join ';')" } if (-not $hit.tokenPresent) { Fail '出站请求没带 access_token' } Add-LoopStep '出站请求带 token、报文无问题' $true if ($hit.response.status -ne 200) { Fail "Graph 应答 $($hit.response.status)(IG 模拟档位 $($hit.response.mode)),用户实际没收到" } Add-LoopStep 'Graph 应答 200,用户收到' $true $hit.response.messageId # 也要等:iXserver 在 send-txt 应答之前就把消息发到 IG 了,客户端拿到应答才记 reply,会晚上百毫秒 $reply = $null while (-not $reply -and (Get-Date) -lt $deadline.AddSeconds(5)) { $reply = @((Invoke-RestMethod "$cb/_api/state").events | Where-Object { $_.kind -eq 'reply' -and $_.message -eq $expected }) | Select-Object -First 1 if (-not $reply) { Start-Sleep -Milliseconds 200 } } if (-not $reply) { Fail 'chatbot 侧没有对应的回复记录' } Set-LoopTicket $reply.ticketId if ($reply.response.status -ne 201) { Fail "send-txt 返回 $($reply.response.status)" } Add-LoopStep '第三方 send-txt 201' $true "ticket $($reply.ticketId)" Write-Host "S1 通过:「$text」→ ticket $($reply.ticketId) → IG 收到「$expected」" -ForegroundColor Green Save-LoopReport -Passed $true exit 0