Skip to content

Matrix QA 测试套件在 Docker 中启动临时的 Tuwunel 家庭服务器,对 OpenClaw Matrix 插件进行端到端的实时传输覆盖。适合开发者在本地源码检出后运行 pnpm openclaw qa matrix 来验证发送、接收、媒体、E2EE 等场景。默认运行全部场景(约30分钟),可用 --profile fast --fail-fast 作为发布门禁;若清理卡住可执行提示的 docker compose ... down --remove-orphans 命令。环境变量 OPENCLAW_QA_MATRIX_TIMEOUT_MS 控制总超时,OPENCLAW_QA_MATRIX_CAPTURE_CONTENT 可保留消息体用于调试。

OpenClaw Matrix QA 测试:运行配置与排错指南

Matrix QA 测试套件针对 @openclaw/matrix 插件,在 Docker 中启动一个临时的 Tuwunel 家庭服务器,并创建 driver、sut、observer 三个临时账号及预置房间,对 Matrix 的实时传输行为进行端到端覆盖。

注意:此套件仅面向维护者。发布的 OpenClaw 不包含 qa-lab,因此 openclaw qa 命令仅在源码检出目录下可用。源码检出后加载内置的运行器,无需额外安装插件。

更广泛的 QA 框架说明参见 QA 概览

快速开始

bash
pnpm openclaw qa matrix --profile fast --fail-fast

单独执行 pnpm openclaw qa matrix 默认使用 --profile all 且不会在第一个失败时停止。作为发布门禁,建议使用 --profile fast --fail-fast;并行运行完整场景集时可按模块拆分,例如 --profile transport|media|e2ee-smoke|e2ee-deep|e2ee-cli

测试流程说明

  1. 在 Docker 中创建临时 Tuwunel 家庭服务器(默认镜像 ghcr.io/matrix-construct/tuwunel:v1.5.1,服务器名 matrix-qa.test,端口 28008)。
  2. 注册三个临时用户:driver(发送入站流量)、sut(受测的 OpenClaw Matrix 账号)、observer(第三方流量捕获)。
  3. 根据所选测试场景创建所需房间(主房间、线程、媒体、重启、辅助、白名单、E2EE、验证 DM 等)。
  4. 启动一个子 OpenClaw 网关,使用真实的 Matrix 插件并限定为 SUT 账号;qa-channel 不在子网关中加载。
  5. 按顺序运行测试场景,通过 driver/observer 的 Matrix 客户端观察事件。
  6. 拆除家庭服务器,写入报告和摘要文件后退出。

CLI 命令

text
pnpm openclaw qa matrix [options]

常用参数

参数默认值说明
--profile <profile>all测试模块。参见下方 测试模块(Profile)
--fail-fast关闭在第一个检查或场景失败后立即停止。
--scenario <id>-只运行指定场景 ID。可重复使用。参见 测试场景(Scenario)
--output-dir &lt;path&gt;&lt;repo&gt;/.artifacts/qa-e2e/matrix-<时间戳>报告、摘要、观察事件和输出日志的写入路径。相对路径相对于 --repo-root
--repo-root &lt;path&gt;process.cwd()从非仓库根目录的当前工作目录运行时设定仓库根路径。
--sut-account &lt;id&gt;sutQA 网关配置中使用的 Matrix 账号 ID。

Provider 参数

测试使用真实的 Matrix 传输,但模型 provider 可配置:

参数默认值说明
--provider-mode &lt;mode&gt;live-frontiermock-openai 使用确定性 mock 分发,live-frontier 使用真实的前沿 provider。遗留别名 live-openai 仍可用。
--model &lt;ref&gt;provider 默认值provider/model 引用。
--alt-model &lt;ref&gt;provider 默认值场景中途切换的备用 provider/model 引用。
--fast关闭在 provider 支持时启用快速模式。

Matrix QA 不支持 --credential-source--credential-role 参数,因为测试在本地创建临时用户,不需要共享凭证池。

测试模块(Profile)

选中的模块决定运行哪些场景。

模块用途
all(默认)全部场景。慢但全面。
fast发布门禁子集:包括 canary、提及门控、白名单拦截、回复形状、重启恢复、线程跟进、线程隔离、反应观察、执行审批元数据投递。
transport传输层测试:线程、DM、房间、自动加入、提及/白名单、审批、反应场景。
media媒体附件测试:图片、音频、视频、PDF、EPUB。
e2ee-smoke最小 E2EE 覆盖:基本加密回复、线程跟进、bootstrap 成功。
e2ee-deep穷举 E2EE 测试:状态丢失、备份、密钥、恢复场景。
e2ee-cli通过测试工具驱动 openclaw matrix encryption setupverify * CLI 场景。

精确的场景映射见 extensions/qa-matrix/src/runners/contract/scenario-catalog.ts

测试场景(Scenario)

完整场景 ID 列表对应 extensions/qa-matrix/src/runners/contract/scenario-catalog.ts:15 中的 MatrixQaScenarioId 联合类型。类别包括:

  • 线程:matrix-thread-*matrix-subagent-thread-spawn
  • 顶层 / DM / 房间:matrix-top-level-reply-shapematrix-room-*matrix-dm-*
  • 流式与工具进度:matrix-room-partial-streaming-previewmatrix-room-quiet-streaming-previewmatrix-room-tool-progress-*matrix-room-block-streaming
  • 媒体:matrix-media-type-coveragematrix-room-image-understanding-attachmentmatrix-attachment-only-ignoredmatrix-unsupported-media-safe
  • 路由:matrix-room-autojoin-invitematrix-secondary-room-*
  • 反应:matrix-reaction-*
  • 审批:matrix-approval-*(exec/plugin 元数据、分块回退、拒绝反应、线程、target: "both" 路由)
  • 重启与重放:matrix-restart-*matrix-stale-sync-replay-dedupematrix-room-membership-lossmatrix-homeserver-restart-resumematrix-initial-catchup-then-incremental
  • 提及门控、Bot 到 Bot、白名单:matrix-mention-*matrix-allowbots-*matrix-allowlist-*matrix-multi-actor-orderingmatrix-inbound-edit-*matrix-mxid-prefixed-command-blockmatrix-observer-allowlist-override
  • E2EE:matrix-e2ee-*(基本回复、线程跟进、bootstrap、恢复密钥生命周期、状态丢失变体、服务器备份行为、设备卫生、SAS/QR/DM 验证、重启、工件编辑)
  • E2EE CLI:matrix-e2ee-cli-*(加密设置、幂等设置、bootstrap 失败、恢复密钥生命周期、多账号、网关回复往返、自我验证)

使用 --scenario &lt;id&gt;(可重复)可以运行指定的场景集合;结合 --profile all 可忽略模块门控。

环境变量

变量默认值效果
OPENCLAW_QA_MATRIX_TIMEOUT_MS1800000(30 分钟)整个运行的最大时限。
OPENCLAW_QA_MATRIX_CANARY_TIMEOUT_MS45000初始 canary 回复时限。发布 CI 中会加大,避免慢速 runner 上的第一次网关启动失败。
OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS8000无回复断言的静默窗口。被钳制为不超过运行超时。
OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS90000Docker 拆除时限。失败时会显示恢复命令 docker compose ... down --remove-orphans
OPENCLAW_QA_MATRIX_TUWUNEL_IMAGEghcr.io/matrix-construct/tuwunel:v1.5.1覆盖家庭服务器镜像版本,用于测试不同版本的 Tuwunel。
OPENCLAW_QA_MATRIX_PROGRESSon设为 0 静默 stderr 上的 [matrix-qa] ... 进度行;设为 1 强制启用。
OPENCLAW_QA_MATRIX_CAPTURE_CONTENTredacted(编辑)设为 1 时在 matrix-qa-observed-events.json 中保留消息 body 和 formatted_body。默认编辑以保护 CI 工件安全。
OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIToff设为 1 跳过工件写入后的强制 process.exit。默认强制退出是因为 matrix-js-sdk 的原生加密句柄可能在工件写入后仍保持事件循环活跃。
OPENCLAW_RUN_NODE_OUTPUT_LOG未设置当外部启动器设置了此变量(如 scripts/run-node.mjs 中),Matrix QA 复用该日志路径,不再创建自己的 tee。

输出工件

写入 --output-dir 目录:

  • matrix-qa-report.md — Markdown 协议报告(记录通过、失败、跳过及原因)。
  • matrix-qa-summary.json — 结构化摘要,适合 CI 解析和仪表盘。
  • matrix-qa-observed-events.json — 从 driver 和 observer 客户端观察到的 Matrix 事件。除非设置 OPENCLAW_QA_MATRIX_CAPTURE_CONTENT=1,否则消息体被编辑;审批元数据被概括,包含选定的安全字段和截断的命令预览。
  • matrix-qa-output.log — 运行的 stdout/stderr 合并日志。如果设置了 OPENCLAW_RUN_NODE_OUTPUT_LOG,则复用外部启动器的日志。

默认输出目录为 &lt;repo&gt;/.artifacts/qa-e2e/matrix-<时间戳>,因此多次运行不会相互覆盖。

问题排查建议

  • 运行接近结尾卡住matrix-js-sdk 的原生加密句柄可能比测试工具存活得更久。默认情况下会在工件写入后执行 process.exit;如果你手动取消了 OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT=1,则进程可能会继续挂起。
  • 清理错误:查看终端输出的恢复命令(通常是 docker compose ... down --remove-orphans),手动执行以释放家庭服务器端口。
  • CI 中断言窗口不稳定:CI 较慢时可增大 OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS(默认 8 秒);CI 较快时可适当减小。
  • 需要消息体用于 Bug 报告:重新运行并设置 OPENCLAW_QA_MATRIX_CAPTURE_CONTENT=1,然后提供 matrix-qa-observed-events.json。注意该工件包含敏感数据。
  • 测试不同 Tuwunel 版本:设置 OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE 为待测版本。套件只检查固定的默认镜像。

实时传输契约

Matrix 是三个实时传输测试套件之一(Matrix、Telegram、Discord),共享同一份契约检查清单,定义在 QA 概览 → 实时传输覆盖 中。qa-channel 保持为广泛的合成套件,有意不参与该契约矩阵。

相关文档

常见问题

Matrix QA 运行超时怎么办?

检查总超时设置 OPENCLAW_QA_MATRIX_TIMEOUT_MS(默认 30 分钟)。如果 CI 环境较慢,可以增大此值。也可以使用 --profile fast 只运行关键场景,缩短运行时间。若清理阶段超时,终端会输出 docker compose 拆除命令,手动运行即可。

如何只运行快速测试(发布门禁)?

使用 pnpm openclaw qa matrix --profile fast --fail-fastfast 模块包含 canary、提及门控、白名单、回复形状、重启恢复、线程、反应和审批元数据等核心场景。--fail-fast 让测试在第一个失败时立即停止。

清理失败、端口被占用怎么办?

查看命令行输出的恢复指令,通常是 docker compose ... down --remove-orphans。手动执行该命令后重启测试。如果端口 28008 仍然被占用,可以用 docker ps 找到残留容器并强制删除。