测试分层总览
除e2e/perf 外,所有层都被 go test ./... 覆盖;需要 Python executor 的层在 venv 缺失时会 t.Skip 而不是失败(internal/testutil/python.go 的 RequirePythonModules)。
几点补充:
make test给所有包加了-short,但除 perf 外没有一层因此被跳过,所以make test就是全量 E2E。cmd/syncinvoker被Makefile从FAST_TEST_PACKAGES中剔除后逐文件跑:每个测试都起独立进程 + Python executor,perf 用例又不受-short保护,整包一起跑会超出预算;逐文件跑让SYNCINVOKER_TEST_TIMEOUT成为每个文件的预算,并分别产出覆盖率再合并。- 单个模块的
-run过滤示例:go test ./internal/worker/core/ -run TestWorkerCore_RequestTaskSlot。 - Python 单个模块:
PYTHONPATH=python uv run --project python python -m unittest python.tests.test_executor_protocol_contract。
- 日常迭代
- 提交前
- 只跑某一层 E2E
测试组织约定
三份文件定义了怎么放、怎么命名:- blockx 仓库
docs/specs/worker-test-organization.md:适用于internal/worker/**与cmd/worker/、cmd/bundle_worker/。三个层级:core unit(只测 Sans-IO 核心,禁止引入 HTTP、进程或 Python)、adapter integration(handler / subscriber / orchestrator / executor pool,允许 fake 与 stub)、process e2e(真实cmd/worker进程,只放在cmd/<entrypoint>/)。文件名表达实现边界:worker_test.go、dispatcher_retry_test.go、handler_protocol_test.go、worker_process_<slice>_test.go;禁止misc_test.go、e2e_test.go这类弱语义名。顶层函数Test<Boundary>_<Theme>,t.Run名必须写”场景 + 预期结果”。拆分阈值:一个文件超过 3 个逻辑块、一个顶层测试超过 8 个t.Run、一个 process E2E 文件超过 6 个独立 contract。 - blockx 仓库
docs/specs/python-test-organization.md:python/tests/一个文件一个实现边界,test_<boundary>.py;TestCase名<Boundary><Theme>Test;方法名”场景 + 预期结果”,例如test_deadline_after_resume_prevents_followup_waiting。 - blockx 仓库
docs/specs/system-e2e-testing.md:contract 文件叫contract_<behavior>_test.go、函数TestContractE2E_<Boundary>_<Behavior>;system 文件叫system_<behavior>_test.go、函数TestSystemE2E_<Behavior>;一个 system 文件只放一个场景族。拿不准放哪层时默认放 contract 层。
AGENTS.md 的测试指南补充四条:Go 测试与实现放同目录的 *_test.go;状态机、协议映射、core/adapter 边界优先用表驱动;新行为要同时覆盖 happy path 与 spec 里的失败 / 超时路径;改了协议或生命周期语义就在同一个变更里更新对应 spec。
不同层断言不同真相:core 单测断状态迁移、幂等、命令输出、TTL 与结果收敛;adapter 测试断协议映射与错误翻译;process E2E 只断外部可观察行为(gRPC 返回、终态、日志字段)。不要在 E2E 里穷举
DispatcherCore 的 retry 矩阵,也不要用进程测试替代 handler 的错误映射断言。测试工具与替身
testutil 没有 fake clock。core 的方法显式接收
now(例如 WorkerCore.HandleRequestTaskSlot(taskID string, ttlMs int64, now int64)),core 单测直接传时间值即可。
CI
.github/workflows/test.yml 在 PR 到 dev、push 到 dev 与手动触发时运行;除 Deploy Script Tests 外的 job 都通过 GitHub App token 配置 github.com/Chaintable/* 私有模块访问:
.github/workflows/build.yml 只在推 tag 时构建并推送镜像,不跑测试。
性能测试
e2e/perf 每个用例自起 etcd + coordinator + worker,用 PERF_* 环境变量控制规模,checkSLO 用 PERF_SLO_MULTIPLIER 放大后的阈值断言时延,阈值来源见 docs/specs/perf-methodology.md。
整包由 e2e/perf/short_test.go 的 TestMain 门控:BLOCKX_RUN_PERF 不为 1 时直接返回,一个用例都不跑。
- 主要变量:
PERF_N(每场景 task 数,默认 20)、PERF_C(并发,默认 4)、PERF_EXECUTOR_COUNT(默认 4)、PERF_IO_READS(默认 5)、PERF_SLO_MULTIPLIER(默认 1.0,CI 用 5)。test.sh自身读PERF_CPU、PERF_MEM、PERF_TIMEOUT,并透传WORKER_CPU_PROFILE、WORKER_TRACE、COORDINATOR_CPU_PROFILE、COORDINATOR_TRACE。 - 文件按
docs/specs/perf-methodology.md§3 的 Stage 命名:s0_framework_*、s1_builder_*、s2_call_count_*、s3_cpu_*、s4_io_*、s5_plugin_*;phase_*、m3_stream_build_test.go、calibration_test.go是规范之前的遗留文件。helpers_test.go放runScenario/startPerfInfra*/checkSLO等脚手架。 - 产物落
e2e/perf/_artifacts/(已 gitignore):<TestName>_<subtest>/spans.jsonl(with_trace子测试的 OTel span,开关BLOCKX_OTEL_SPAN_FILE+BLOCKX_OTEL_UDS_EVENTS=1)、<TestName>/*.pb.gz(pprof)、pyspy/。 - 离线分析 span:
python3 analyze_spans.py e2e/perf/_artifacts/<TestName>_with_trace/spans.jsonl。脚本在仓库根,只接受一个位置参数,默认/tmp/blockx_spans.jsonl。 - 报告:
docs/specs/perf-test-report.md(v1 主报告)、perf-test-report-appendix.md(v1 附录)、perf-test-report-v2.md(当前唯一基线,cgroup 12 vCPU / 32G)、perf-capability-backend-report.md(能力后端框架税)。复现步骤在docs/specs/perf-test-how-to-v2.md,方法论在docs/specs/perf-methodology.md。 cmd/perf是打已部署环境的负载 CLI(-coordinator、-n、-c、-mode),不属于go test。cmd/bundle-loadgen是 bundle 集群的负载生成器,自带纯单测。
相关文档
- 本地开发环境:venv、CGO、最小 worker 启动。
- 贡献流程:PR 里要写验证命令。
- Worker、Coordinator、Sync Invoker、Bundle 集群:各组件页的”测试”小节指向对应文件。
- blockx 仓库
docs/specs/worker-test-organization.md、docs/specs/python-test-organization.md、docs/specs/system-e2e-testing.md:组织规范。 - blockx 仓库
docs/specs/perf-methodology.md、docs/specs/perf-test-how-to-v2.md、e2e/perf/README.md:性能测试方法、复现与用例索引。 - blockx 仓库
AGENTS.md:命令与测试指南的权威来源。