Agent 默认
Agent 会话仅在本地针对受信任源码、且现有依赖安装已准备就绪时,运行一个/少量聚焦测试和廉价静态检查。切勿在本地执行不受信任的仓库工具。更大的测试套件、包含 typecheck/lint 分流的变更门禁、构建、Docker、包流水线、E2E、线上验证以及跨平台验证,均通过 Crabbox 远程运行。受信任维护者的重型验证默认使用 Blacksmith Testbox。已配置的 Testbox 工作流会填充凭据,因此不受信任的贡献者或 fork 代码必须使用无密钥的 fork CI,或经过净化的直接 AWS Crabbox。 不要为预期的工作预热。等第一个重型命令就绪时再惰性获取后端,在后续重型命令中复用返回的tbx_... id,每次运行都同步当前检出,并在交接前停止它。
第一次成功复用后,包装器会将该租约的 base、dependency 和 Testbox workflow fingerprint 记录到 .crabbox/testbox-leases/ 下。仅有源码修改时会继续复用已预热的 box。若 merge base、lockfile、package-manager 输入、wrapper 或 Testbox workflow 发生变化,则会失败并要求新的租约。每次运行仍会同步当前检出。OPENCLAW_TESTBOX_ALLOW_STALE=1 仅用于有意进行诊断,不用于发布验证。
下面的本地测试命令仅适用于人工工作流和受限的 agent 验证。若远程提供方不可用,必须上报;这不意味着可以在本地静默运行更宽泛的门禁。
对于不受信任的重型验证,使用 --provider aws 惰性预热。每次运行都必须设置 CRABBOX_ENV_ALLOW=CI,传入 --provider aws --no-hydrate,并在安装依赖或运行测试前使用一个新的临时远程 HOME。为该不受信任源码使用一个新预热的专用租约;绝不要复用受信任或已预填充的租约。先从一个干净、受信任的 main 检出中启动已安装的受信任 Crabbox 二进制,并且只用 --fresh-pr 获取远程 PR;绝不要在本地执行不受信任检出的 wrapper 或配置。取消设置 CRABBOX_AWS_INSTANCE_PROFILE,并在未解析到空的 aws.instanceProfile 时失败关闭。在任何安装/测试之前,使用受信任的绝对路径工具要求 IMDSv2 token,证明 IAM 凭据端点返回 404,并验证远程 git rev-parse HEAD 等于完整审阅过的 PR head SHA。将该租约绑定到该 SHA,并在 head 变更时停止/重新预热。与 --fresh-pr 一起上传来自干净 main 的受信任 scripts/crabbox-untrusted-bootstrap.sh;它会安装固定版本的 Node/pnpm,验证 SHA 和 package-manager pin,隔离 HOME,安装依赖,然后执行所请求的测试。如果 broker 不能证明不存在 role 或不存在远程 PR,则使用无密钥的 fork CI。不要使用 hydrate-github、--no-sync,或带凭据填充的 Testbox 工作流。
取消设置所有 CRABBOX_TAILSCALE* 覆盖项,强制使用 --network public --tailscale=false,清除 exit-node/LAN 标志,并要求 crabbox inspect 在上传任何脚本之前报告公共网络且没有 Tailscale 状态。
常规本地顺序
- 对于已变更范围的 Vitest 证明,使用
pnpm test:changed。 - 对于单个文件、目录或显式目标,使用
pnpm test <path-or-filter>。 - 仅当你有意需要完整的本地 Vitest 测试套件时,才使用
pnpm test。
-
有依赖已就绪时的有界聚焦证明:
node scripts/run-vitest.mjs <path-or-filter>。 -
先分类的变更检查:
node scripts/check-changed.mjs;仅文档、 无变更和小型元数据计划在依赖已就绪时保持本地执行,而重型或缺少依赖的计划则委派给 Testbox。 -
显式保留租约的广泛证明:
node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox ... -- env OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 corepack pnpm check:changed,这样 pnpm 会在 Testbox 内运行。 -
wrapper 最终的
exitCode和计时 JSON 就是命令结果。一次委派的 Blacksmith GitHub Actions 运行在 SSH 命令成功后可能显示cancelled,因为 Testbox 会从 keepalive action 外部被停止;在将其视为失败之前,请先检查 wrapper 摘要和命令输出。 -
OPENCLAW_HEAVY_CHECK_LOCK_SCOPE=worktree <local-heavy-check command>:将 heavy-check 的串行化保持在当前 worktree 内,而不是 Git common dir 中,适用于诸如pnpm check:changed和有针对性的pnpm test ...等命令。仅在高容量本地主机上、且你有意在链接的 worktree 之间运行独立检查时使用它。 -
针对一个很小文件、且明确由用户要求的本地回退:
node scripts/run-vitest.mjs <path-or-filter>。 -
变更门禁或广泛证明:
node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox ... -- env OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 corepack pnpm check:changed,这样 pnpm 会在 Testbox 内运行。 -
wrapper 最终的
exitCode和计时 JSON 就是命令结果。一次委派的 Blacksmith GitHub Actions 运行在 SSH 命令成功后可能显示cancelled,因为 Testbox 会从 keepalive action 外部被停止;在将其视为失败之前,请先检查 wrapper 摘要和命令输出。 -
OPENCLAW_HEAVY_CHECK_LOCK_SCOPE=worktree <local-heavy-check command>:将 heavy-check 的串行化保持在当前 worktree 内,而不是 Git common dir 中,适用于诸如pnpm check:changed和有针对性的pnpm test ...等命令。仅在高容量本地主机上、且你有意在链接的 worktree 之间运行独立检查时使用它。
核心命令
共享测试状态和进程辅助工具
src/test-utils/openclaw-test-state.ts:当测试需要隔离的HOME、OPENCLAW_STATE_DIR、OPENCLAW_CONFIG_PATH、配置 fixture、工作区、代理目录或身份验证配置文件存储时,可在 Vitest 中使用。pnpm test:env-mutations:report:用于生成非阻塞报告,列出直接修改HOME、OPENCLAW_STATE_DIR、OPENCLAW_CONFIG_PATH、OPENCLAW_WORKSPACE_DIR或相关环境变量的测试/测试框架。可使用它查找共享测试状态辅助工具的迁移候选项。test/helpers/openclaw-test-instance.ts:用于需要运行中的网关、CLI 环境、日志捕获以及统一清理的进程级 E2E 测试。- 使用
scripts/lib/docker-e2e-image.sh的 Docker/Bash E2E 流程可以将docker_e2e_test_state_shell_b64 <label> <scenario>传入容器,并使用scripts/lib/openclaw-e2e-instance.sh对其进行解码;多主目录脚本可以传入docker_e2e_test_state_function_b64,并在每个流程中调用openclaw_test_state_create <label> <scenario>。node --import tsx scripts/lib/openclaw-test-state.mts -- create --label <name> --scenario <name> --env-file <path> --json会写入一个可由宿主机加载的环境文件(create前的--可避免较新的 Node 运行时将--env-file误认为 Node 参数)。启动网关的流程可以加载scripts/lib/openclaw-e2e-instance.sh,以获取入口点解析、模拟 OpenAI 启动、前台/后台启动、就绪探测、状态环境变量导出、日志转储和进程清理功能。
控制 UI、TUI 和扩展通道
- Control UI mocked E2E:
pnpm test:ui:e2e运行 Vitest + Playwright 流程,该流程启动 Vite Control UI,并通过模拟的 Gateway WebSocket 驱动真实的 Chromium 页面。测试位于ui/src/**/*.e2e.test.ts;共享模拟和控制逻辑位于ui/src/test-helpers/control-ui-e2e.ts。pnpm test:e2e包含此流程。Agent 运行默认使用 Testbox/Crabbox,包括针对性验证;只有在明确需要本地回退时,才使用node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/e2e/chat-flow.messaging.e2e.test.ts。 - TUI PTY 测试:
node scripts/run-vitest.mjs run --config test/vitest/vitest.tui-pty.config.ts运行快速的假后端 PTY 流程。OPENCLAW_TUI_PTY_INCLUDE_LOCAL=1或pnpm tui:pty:test:watch --mode local运行较慢的tui --local冒烟测试,该测试仅模拟外部模型端点。CI 还会在构建dist/后设置OPENCLAW_TUI_PTY_USE_BUILT_CLI=1;只有在精确匹配当前 HEAD 的构建产物已经存在时才使用该标志。断言稳定的可见文本或固定装置调用,不要断言原始 ANSI 快照。 pnpm test:extensions和pnpm test extensions运行所有扩展/插件分片。重量级通道插件、浏览器插件和 OpenAI 作为专用分片运行;其他插件组保持批量运行。pnpm test extensions/<id>运行单个捆绑插件流程。- 带有同级测试的源文件会优先映射到该同级测试,然后才回退到更宽泛的目录 glob。
src/channels/plugins/contracts/test-helpers、src/plugin-sdk/test-helpers和src/plugins/contracts下的辅助文件编辑会使用本地导入图来运行导入它们的测试;当依赖路径明确时,不会对所有分片进行宽泛运行。 - 合约目录目标会分发到对应的合约流程:
pnpm test src/channels/plugins/contracts运行四个通道合约配置,pnpm test src/plugins/contracts运行插件合约配置,因为通用的channels/plugins项目会排除contracts/**。 auto-reply拆分为三个专用配置(core、top-level、reply),这样回复测试框架不会占用较轻量的顶层状态/令牌/辅助测试的大部分资源。- 选定的
plugin-sdk和commands测试文件会通过专用的轻量流程运行,该流程仅保留test/setup.ts;运行时开销较大的用例仍使用其现有流程。 - 基础 Vitest 配置默认使用
pool: "threads"和isolate: false,并在整个仓库的配置中启用共享的非隔离运行器。 pnpm test:channels运行vitest.channels.config.ts。
网关和 E2E
- 网关测试包含在未指定目标的
pnpm test完整测试套件中;使用pnpm test:gateway单独运行。 pnpm test:e2e:仓库 E2E 聚合测试 =pnpm test:e2e:gateway && pnpm test:ui:e2e。pnpm test:e2e:gateway:网关端到端冒烟测试(多实例 WS/HTTP/节点配对)。在vitest.e2e.config.ts中默认使用threads+isolate: false,并启用一个 worker;使用OPENCLAW_E2E_WORKERS=<n>可启用并行执行(上限为 16),使用OPENCLAW_E2E_VERBOSE=1可启用详细日志。pnpm test:live:提供商实时测试(Claude/Minimax/DeepSeek/z.ai 等,由*.live.test.ts控制)。需要 API 密钥,并设置LIVE=1(或OPENCLAW_LIVE_TEST=1)以取消跳过;使用OPENCLAW_LIVE_TEST_QUIET=0输出详细信息。
完整 Docker 套件(pnpm test:docker:all)
构建共享的 live 测试镜像,将 OpenClaw 一次性打包为 npm tarball,构建或复用一个精简的 Node/Git runner 镜像,以及一个将该 tarball 安装到 /app 的功能镜像,然后通过加权调度器运行 Docker 冒烟测试通道。scripts/package-openclaw-for-docker.mjs 是稳定的本地/CI 软件包打包入口点,并会在 Docker 使用 tarball 前验证该 tarball 以及 dist/postinstall-inventory.json。
- 精简镜像(
OPENCLAW_DOCKER_E2E_BARE_IMAGE):安装器/更新/插件依赖通道;挂载预构建的 tarball,而不是复制仓库源代码。 - 功能镜像(
OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE):普通的已构建应用功能通道。 - 通道定义:
scripts/lib/docker-e2e-scenarios.mts。规划器:scripts/lib/docker-e2e-plan.mts。执行器:scripts/test-docker-all.mjs。 node scripts/test-docker-all.mjs --plan-json会输出由调度器负责的 CI 计划(通道、镜像类型、软件包/live 镜像需求、状态场景、凭证检查),不会构建或运行 Docker。
资源上限的环境变量模式为
OPENCLAW_DOCKER_ALL_<RESOURCE>_LIMIT(资源名转为大写,非字母数字字符折叠为 _)。
其他行为:运行器默认会预检 Docker,清理过期的 OpenClaw E2E 容器,在兼容通道之间共享提供者 CLI 工具缓存,并且在首次失败后停止调度新的池化通道,除非设置了 OPENCLAW_DOCKER_ALL_FAIL_FAST=0。如果某个通道在低并行度主机上超过了有效的权重/资源上限,它仍然可以从空池启动,并单独运行直到释放容量。每个通道的日志、summary.json、failures.json 和阶段计时都会写入 .artifacts/docker-tests/<run-id>/;使用 pnpm test:docker:timings <summary.json> 查看慢通道,并使用 pnpm test:docker:rerun <run-id|summary.json|failures.json> 打印低成本的定向重跑命令。
值得注意的 Docker 通道
沙箱兼容性通道
本地 PR 门禁
对于本地 PR 合并/门禁检查,运行:pnpm check:changedpnpm checkpnpm check:test-typespnpm buildpnpm testpnpm check:docs
pnpm test 在负载很高的主机上偶发失败,在将其视为回归之前先重新运行一次,然后使用 pnpm test <path/to/test> 将其隔离。对于内存受限的主机:
OPENCLAW_VITEST_MAX_WORKERS=1 pnpm testOPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-cache pnpm test:changed
测试性能工具
pnpm test:perf:imports:启用 Vitest 的导入耗时 + 导入拆解报告,同时仍然对显式文件/目录目标使用分组通道路由。pnpm test:perf:imports:changed会将相同的性能分析范围限定到自origin/main以来发生变更的文件。pnpm test:perf:changed:bench -- --ref <git-ref>:将路由后的 changed 模式路径与同一已提交 git diff 的原生 root-project 运行进行基准测试;pnpm test:perf:changed:bench -- --worktree则在不先提交的情况下,对当前工作区变更集进行基准测试。pnpm test:perf:profile:main会为 Vitest 主线程写入 CPU 配置文件(.artifacts/vitest-main-profile);pnpm test:perf:profile:runner会为单元测试运行器写入 CPU + 堆配置文件(.artifacts/vitest-runner-profile)。pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json:串行运行每个 full-suite Vitest 叶子配置,并写入分组耗时数据以及每个配置的 JSON/日志工件。Full-suite 报告默认会隔离文件,因此来自更早文件的保留模块图和 GC 暂停不会计入后续断言;仅在有意分析共享 worker 累积时才传入-- --no-isolate。Test Performance Agent 会在尝试修复慢测试之前,将其作为基线。pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json用于比较一次以性能为重点的更改之后的分组报告。- Full、extension 和 include-pattern 分片运行会更新
.artifacts/vitest-shard-timings.json中的本地计时数据;后续的 whole-config 运行会使用这些计时数据来平衡慢分片和快分片。Include-pattern CI 分片会将分片名称附加到计时键中,这样在不替换 whole-config 计时数据的情况下,过滤后的分片计时仍然可见。将OPENCLAW_TEST_PROJECTS_TIMINGS=0设置为忽略本地计时工件。
基准测试
模型延迟(scripts/bench-model.ts)
模型延迟(scripts/bench-model.ts)
MINIMAX_API_KEY、MINIMAX_BASE_URL、MINIMAX_MODEL、ANTHROPIC_API_KEY。默认提示词:“仅回复一个词:ok。不加标点或额外文本。”CLI 启动(scripts/bench-cli-startup.ts)
CLI 启动(scripts/bench-cli-startup.ts)
startup:--version、--help、health、health --json、status --json、statusreal:health、status、status --json、sessions、sessions --json、tasks --json、tasks list --json、tasks audit --json、agents list --json、gateway status、gateway status --json、gateway health --json、config get gateway.portall:两个预设合并
sampleCount、avg、p50、p95、min/max、退出码/信号分布,以及每个命令的最大 RSS。--cpu-prof-dir / --heap-prof-dir 会为每次运行写入 V8 配置文件。保存的输出:pnpm test:startup:bench:smoke 会写入 .artifacts/cli-startup-bench-smoke.json;pnpm test:startup:bench:save 会写入 .artifacts/cli-startup-bench-all.json(runs=5 warmup=1)。纳入仓库的 fixture:test/fixtures/cli-startup-bench.json,可通过 pnpm test:startup:bench:update 刷新,并由 pnpm test:startup:bench:check 比较。网关启动(scripts/bench-gateway-startup.ts)
网关启动(scripts/bench-gateway-startup.ts)
默认使用构建后的 CLI 入口 案例 id:
dist/entry.js;请先运行 pnpm build。传入 --entry scripts/run-node.mjs 可改为测量源码运行器,并请将这些结果与构建后入口的基线分开保存。default、skipChannels(跳过通道启动)、oneInternalHook、allInternalHooks、fiftyPlugins(50 个 manifest 插件)、fiftyStartupLazyPlugins(50 个 startup-lazy manifest 插件)。输出包括首次进程输出、/healthz、/readyz、HTTP 监听日志时间、Gateway 就绪日志时间、CPU 时间、CPU 核心占比、最大 RSS、堆、启动跟踪指标、事件循环延迟,以及插件查找表细节指标。脚本会在子 Gateway 环境中设置 OPENCLAW_GATEWAY_STARTUP_TRACE=1。/healthz 表示存活状态(HTTP 服务器可以响应)。/readyz 表示可用就绪状态(启动插件 sidecar、通道,以及 ready-critical 的 post-attach 工作都已稳定)。启动钩子是异步分发的,不属于就绪性保证的一部分。就绪日志时间是 Gateway 的内部时间戳,适合做进程侧归因,但不能替代外部 /readyz 探测。在比较变更时请使用 JSON 输出或 --output。仅当跟踪输出表明存在导入、编译或 CPU 密集型工作,而仅靠阶段时间无法解释时,才使用 --cpu-prof-dir。网关重启(scripts/bench-gateway-restart.ts)
网关重启(scripts/bench-gateway-restart.ts)
仅限 macOS 和 Linux(使用 SIGUSR1 进行进程内重启;在 Windows 上会立即失败)。与上面的网关启动相同,默认使用构建后的入口,并可通过 案例 id:
--entry scripts/run-node.mjs 覆盖。skipChannels、skipChannelsAcpxProbe(开启 ACPX 启动探针)、skipChannelsNoAcpxProbe(关闭探针)、default、fiftyPlugins。输出包括下一次 /healthz、下一次 /readyz、停机时间、重启就绪时间、CPU、RSS、替换进程的启动跟踪指标,以及关于信号处理、活动工作项清理、关闭阶段、下一次启动、就绪时间和内存快照的重启跟踪指标。脚本会设置 OPENCLAW_GATEWAY_STARTUP_TRACE=1 和 OPENCLAW_GATEWAY_RESTART_TRACE=1。当变更涉及重启信号、关闭处理器、重启后的启动、sidecar 关闭、服务切换,或重启后的就绪性时,请使用此基准。先从 skipChannels 开始,以将 Gateway 机制与通道启动隔离开;只有在这个窄场景解释清楚重启路径之后,才使用 default 或插件密集型案例。跟踪指标只是归因线索,不是最终裁决——判断重启变更时,应综合多次样本、匹配的 owner span、/healthz//readyz 行为,以及用户可见的重启契约。入门 E2E(Docker)
可选;仅在容器化入门冒烟测试时需要。在干净的 Linux 容器中执行完整的冷启动流程:openclaw health。