# iXserverLoopEnv:模拟闭环测试环境 在 FG-W11-ICON-DEV 一台机器上把五个角色跑起来,让一条 IG 消息从入站到第三方回复、再回到 IG 全程走真 HTTP。 方案与取舍见 iXserver 仓库的 `docs/构建模拟闭环测试环境.html`。 | 角色 | 端口 | 来源 | | --- | --- | --- | | ABP(授权 + 消息模板) | https 44332 | `C:\Projects\HKTBAbp` 发布到 `run\abp` | | iXserver API(IIS Express) | 8081,WebSocket 33346 | `C:\Projects\iXserver` 整解决方案编译后拷到 `run\ixserver` | | 第三方 chatbot 客户端 | 5056 | `iXserver\Tools\ThirdPartyChatbotTestClient` | | IG 后端模拟 | 5070 | `iXserver\Tools\IgMockServer` | | SCRM 客服系统模拟 | 5080 | `iXserver\Tools\ScrmMockServer` | | 闭环观察台(只读,泳道时序图) | 5090 | `iXserver\Tools\LoopConsole` | 所有端口只绑本机。iXserver 的旧接口和 WebSocket **没有鉴权**,绝不能对外开放 8081 / 33346。 ## 这个仓库装什么 只装「环境」:`loop.ps1`、`config\`、`db\`、`tools\`、`scenarios\`、`deployed.json`。 程序本身不在这里——两个模拟服务的代码在 iXserver 的 `Tools\`(它们模拟的是 iXserver 自己的协议, 要和协议改动同一个提交);编译产物、日志、上传文件在被忽略的 `run\`。 **以 Mac 上的 `~/projects/iXserverLoopEnv` 为准**,用 remote-dev-box 的 `sync.sh` 推到 winbox 的 `C:\Projects\iXserverLoopEnv`。提交在 Mac 上做,winbox 上只跑。 ## 第一次 ```powershell .\loop.ps1 reset-abp -Init # iCONAbpFX 拷完后:换 setsail secret 与 admin 密码,留底 .\loop.ps1 deploy # 编译 iXserver 整解决方案 + 发布 ABP(慢) .\loop.ps1 reset # 建 iXserverLoop:EDMX 建表 → FeatureTest 种子 → loop_patch,留底 .\loop.ps1 up ``` 之后日常: ```powershell .\loop.ps1 status .\loop.ps1 deploy -Only ixserver # 改了 iXserver 代码 .\loop.ps1 deploy -Only ixserver -ConfigOnly # 只改了 config\ixserver\overrides.psd1 .\loop.ps1 reset -FromBackup # 库回到干净状态(秒级) .\loop.ps1 logs -Only ixserver -Tail 100 .\loop.ps1 down ``` ## 场景 `scenarios\` 下每个脚本独立可跑,通过退出 0、失败退出 1 并打印两侧记录。前提是 `up` 后各角色都健康。 观察台在跑时,每次跑完(通过或失败)都会生成一份**场景报告**:这次的时序图、iXserver 内部步骤、逐步断言、部署版本, 存成 `run\reports\<开始时间>-<场景>-.html`(单文件,离线可开,不进 git)。 `.\loop.ps1 reports` 列出最近的,观察台 里也能点开。加 `-NoReport` 只断言不出报告(省几秒)。 新写场景照 S1 / S8 点源 `scenarios\_lib.ps1`:`Start-LoopRun` → 每个断言 `Add-LoopStep` → `Save-LoopReport`。 ```powershell .\scenarios\s1-ig-text-echo.ps1 # IG 文本 → iXserver → 第三方 chatbot echo → IG 收到 .\scenarios\s2-auth-ip-whitelist.ps1 # IP 白名单:token 端点 + send-txt 经真 IIS 放行 / 拒绝、可信代理的 XFF 规则;临时改 oauth_client 与 Web.config,结束还原,约 2~3 分钟 .\scenarios\s5-ig-handoff.ps1 # 机器人工单 → SCRM 开工 + 客服上线 → 下一条:echo 在前、问句在后 → 点 Yes → 新人工工单 → 客服回复 → 旧单迟到回复 409 → 下班 .\scenarios\s8-human-chain.ps1 # SCRM 开工 → 新 IG 用户 → 人工工单推送 → 指派 / 回复 → IG 收到 → 结束 → 下班 ``` S5 依赖 `epro_ig_demo` 的 `DisconnectChatbotFlowSetting` 已打开(`db\ixserver\loop_patch.sql` 第 3 节;没 reset 过的库要单独执行那一段), 问句按钮标题跟 ABP 模板走,模板改过时用 `-YesTitle` 指定。 跑的时候开着观察台 ,每一跳和状态变化会实时画成泳道时序图;`?ticket=<工单号>` 只看一张。 `epro_ig_demo` 常开条款同意(`db\ixserver\loop_patch.sql` 第 3 节的 `T_and_C_Setting`): 新 IG 用户的第一句话会被条款拦下,三个场景都先调 `_lib.ps1` 的 `Complete-LoopTnC` 走完「条款 → 同意 → 选语言 → 问候」。 staging 的 IG 条款组**缺 Agree 按钮**(漏了 Line 问候里的「Agreement Button (Line IG)」);闭环 ABP 在 `db\abp\loop_patch.sql` 第 3 节补上了,这一处与 staging 不同。改过这个补丁要 `.\loop.ps1 reset-abp -Init` 重新打并留底。 S5 / S8 结束时(失败也一样)会把服务号切回机器人、在线人数归零,所以几个场景先后跑互不影响;要停在人工状态看页面加 `-KeepShift`。 从 Mac 看几个页面用 SSH 本地端口转发: ```bash ssh -N -L 5056:127.0.0.1:5056 -L 5070:127.0.0.1:5070 -L 5080:127.0.0.1:5080 -L 5090:127.0.0.1:5090 FG-W11-ICON-DEV ``` ## 几个容易踩的点 - **库是 iXserverLoop,不是 iXsererTest。** FeatureTest 每个方法都 drop 重建 iXsererTest, 反过来闭环 API 的连接池连着它会让 FeatureTest 无限卡在删库上。 - **API 从 `run\ixserver` 跑,不从 `API\` 源码目录跑。** 编译 FeatureTest 会刷新 `API\bin` 里的模块 dll, 正在跑的站点会被回收、甚至换成依赖不全的版本。 - **`reset` 把建库与 `loop_patch.sql` 绑在一起。** 种子里有真格式的 FB token 与 api.commas.hk 等真实 webhook, 补丁把它们全换成假值 / 黑洞,并在末尾自检;不提供「只建不补」。 - **`OAuth_Authority` 必须逐字等于本地 ABP 签出 token 的 `iss`。** IdentityServer4 没设 IssuerUri, iss 取请求的 Host,所以全链路统一用 `https://localhost:44332`,换成 127.0.0.1 就全部 401。 - **签名密钥不在库里**,在 ABP 进程工作目录的 `tempkey.jwk`。deploy 删掉仓库里那把开发密钥, 首次 `up` 时 ABP 自己生成一把,留存到 `run\abp-key\`,之后重新部署沿用同一把。 - **备份在 SQL 实例的默认备份目录**(`*.loop.bak`),不在 `run\backup\`:SQL 服务账号对 `C:\Projects` 不一定有写权限。 - **进程用 WMI(Win32_Process.Create)起**,不用 Start-Process:经 SSH 起的进程会随会话一起被杀。 pid 记在 `run\pids\`,`down` 按进程树杀。 - **VS Code 的自动端口转发会抢闭环端口。** 在 winbox 上用 VS Code Remote-SSH 连 Mac 时,它从终端输出里认 `localhost:端口`,然后在 winbox 本机占住同一个端口转发回 Mac,闭环角色就报「端口被 Code 占着」。 Mac 的 `~/.vscode-server/data/Machine/settings.json` 已设 `remote.autoForwardPorts=false`、 `remote.restoreForwardedPorts=false`;已经转发出去的要在 VS Code「端口」面板里停掉。 - **WMI 起的进程只有系统环境变量。** `TEMP` 是 `C:\Windows\TEMP`,ASP.NET 编译临时目录也会退回系统目录, 没写权限,首个请求就 500。`loop.ps1` 给每个角色设了 `TEMP`/`TMP` 指到 `run\data\temp`, 并在 Web.config 的 `` 上写 `tempDirectory`。 - **ABP 的 HTTPS 证书用的是 IIS Express 自带的 localhost 证书**(LocalMachine\My,到 2030 年,已在当前用户受信任根里)。 winbox 的 ASP.NET dev 证书 2026-05 已过期;用 IIS Express 这张,iXserver(.NET Framework)连 ABP 不用另外信任、也不弹框。 - **ABP 的各个 DbContext 按名字找连接串,找不到退回 `Default`**,而仓库 `appsettings.json` 的 `Default` 指向公司内网的库。 `appsettings.Loop.json` 把所有连接串都盖成本机 iCONAbpFX。 - PowerShell 5.1 的两个坑已经在 `loop.ps1` 里绕开:原生命令往 stderr 写一行就抛异常(统一走 `Invoke-Native`); `Get-Content` 默认按 GBK 读无 BOM 的 UTF-8(拷配置用 `Copy-Item`,脚本文件一律带 BOM)。 - **iXserver 的主日志在 `run\ixserver\Log\{Debug,Information,Warning,Error}\<日期>\`**(注入的 ILogger,内部步骤很全,观察台就读它)。 `run\data\API_Log` 是静态 `Logger` 写的另一份,几乎是空的,别看它下结论。排查先看 `Log\Error`。 `deploy` 的 robocopy 排除了 `Log` / `Logs`,重新部署不会清掉日志。 - `deployed.json` 记录每次部署时两个源码仓库的 commit 与未提交文件。闭环结果离开「当时部署的是哪个版本」没法解读, 跑场景的记录里引用它。注意 winbox 上 iXserver 仓库的 HEAD 不随 `sync.sh` 前进(只推文件), `commit` 字段可能停在很久以前,以 `uncommitted` 清单和 Mac 上的提交为准。 ## 闭环专用凭据(假值,可公开) 见 `config\loop.psd1` 的 `Secrets`:setsail 与 FX_App 的 client secret、ABP admin 密码、所有渠道 token 的替身。 staging 的 secret 明文不出现在这个仓库里。