Test layers at a glance
Except fore2e/perf, every layer is covered by go test ./...; layers that need the Python executor call t.Skip instead of failing when the venv is missing (RequirePythonModules in internal/testutil/python.go).
A few additional notes:
make testadds-shortto every package, but no layer other than perf is skipped because of it, somake testis the full E2E run.cmd/syncinvokeris removed fromFAST_TEST_PACKAGESby theMakefileand run file by file: every test starts its own process + Python executor, and the perf cases aren’t guarded by-short, so running the whole package at once would exceed the budget; running per file makesSYNCINVOKER_TEST_TIMEOUTthe budget for each file and produces coverage per file that is merged afterwards.- Example of
-runfiltering for a single module:go test ./internal/worker/core/ -run TestWorkerCore_RequestTaskSlot. - A single Python module:
PYTHONPATH=python uv run --project python python -m unittest python.tests.test_executor_protocol_contract.
- Day-to-day iteration
- Before committing
- Run only one E2E layer
Test organization conventions
Three files define where tests go and how they’re named:docs/specs/worker-test-organization.mdin the blockx repository: applies tointernal/worker/**,cmd/worker/, andcmd/bundle_worker/. Three tiers:core unit(tests only the Sans-IO core; HTTP, processes, and Python are forbidden),adapter integration(handler / subscriber / orchestrator / executor pool; fakes and stubs allowed), andprocess e2e(a realcmd/workerprocess, only undercmd/<entrypoint>/). File names express the implementation boundary:worker_test.go,dispatcher_retry_test.go,handler_protocol_test.go,worker_process_<slice>_test.go; weakly named files likemisc_test.goande2e_test.goare forbidden. Top-level functions areTest<Boundary>_<Theme>, andt.Runnames must state “scenario + expected outcome”. Split thresholds: a file with more than 3 logical blocks, a top-level test with more than 8t.Runs, or a process E2E file with more than 6 independent contracts.docs/specs/python-test-organization.mdin the blockx repository: one implementation boundary per file inpython/tests/, namedtest_<boundary>.py;TestCasenames are<Boundary><Theme>Test; method names are “scenario + expected outcome”, for exampletest_deadline_after_resume_prevents_followup_waiting.docs/specs/system-e2e-testing.mdin the blockx repository: contract files are namedcontract_<behavior>_test.gowith functionsTestContractE2E_<Boundary>_<Behavior>; system files are namedsystem_<behavior>_test.gowith functionsTestSystemE2E_<Behavior>; a system file holds only one scenario family. When unsure which layer a test belongs in, default to the contract layer.
AGENTS.md add four rules: Go tests live in *_test.go in the same directory as the implementation; prefer table-driven tests for state machines, protocol mapping, and core/adapter boundaries; new behavior must cover both the happy path and the failure / timeout paths from the spec; and when you change protocol or lifecycle semantics, update the corresponding spec in the same change.
Different layers assert different truths: core unit tests assert state transitions, idempotency, command output, TTLs, and result convergence; adapter tests assert protocol mapping and error translation; process E2E tests assert only externally observable behavior (gRPC responses, terminal states, log fields). Don’t enumerate the
DispatcherCore retry matrix in E2E tests, and don’t use process tests as a substitute for handler error-mapping assertions.Test utilities and doubles
testutil has no fake clock. Core methods take
now explicitly (for example WorkerCore.HandleRequestTaskSlot(taskID string, ttlMs int64, now int64)), so core unit tests simply pass a time value.
CI
.github/workflows/test.yml runs on PRs to dev, pushes to dev, and manual triggers; every job except Deploy Script Tests configures access to the private github.com/Chaintable/* modules through a GitHub App token:
.github/workflows/build.yml only builds and pushes the image when a tag is pushed; it doesn’t run tests.
Performance testing
Eache2e/perf case starts its own etcd + coordinator + worker and uses PERF_* environment variables to control scale; checkSLO asserts latency against thresholds scaled up by PERF_SLO_MULTIPLIER, and the thresholds come from docs/specs/perf-methodology.md.
The whole package is gated by TestMain in e2e/perf/short_test.go: when BLOCKX_RUN_PERF is not 1, it returns immediately and runs no cases at all.
- Main variables:
PERF_N(tasks per scenario, default 20),PERF_C(concurrency, default 4),PERF_EXECUTOR_COUNT(default 4),PERF_IO_READS(default 5),PERF_SLO_MULTIPLIER(default 1.0, CI uses 5).test.shitself readsPERF_CPU,PERF_MEM, andPERF_TIMEOUT, and passes throughWORKER_CPU_PROFILE,WORKER_TRACE,COORDINATOR_CPU_PROFILE, andCOORDINATOR_TRACE. - Files are named after the Stages in
docs/specs/perf-methodology.md§3:s0_framework_*,s1_builder_*,s2_call_count_*,s3_cpu_*,s4_io_*,s5_plugin_*;phase_*,m3_stream_build_test.go, andcalibration_test.goare legacy files that predate the spec.helpers_test.goholds scaffolding such asrunScenario/startPerfInfra*/checkSLO. - Artifacts land in
e2e/perf/_artifacts/(gitignored):<TestName>_<subtest>/spans.jsonl(OTel spans from thewith_tracesubtests, enabled byBLOCKX_OTEL_SPAN_FILE+BLOCKX_OTEL_UDS_EVENTS=1),<TestName>/*.pb.gz(pprof),pyspy/. - Offline span analysis:
python3 analyze_spans.py e2e/perf/_artifacts/<TestName>_with_trace/spans.jsonl. The script lives at the repository root, accepts a single positional argument, and defaults to/tmp/blockx_spans.jsonl. - Reports:
docs/specs/perf-test-report.md(v1 main report),perf-test-report-appendix.md(v1 appendix),perf-test-report-v2.md(the only current baseline, cgroup 12 vCPU / 32G),perf-capability-backend-report.md(capability backend framework overhead). Reproduction steps are indocs/specs/perf-test-how-to-v2.mdand the methodology indocs/specs/perf-methodology.md. cmd/perfis a load CLI that targets a deployed environment (-coordinator,-n,-c,-mode) and isn’t part ofgo test.cmd/bundle-loadgenis the load generator for Bundle clusters and comes with its own pure unit tests.
Related docs
- Local development environment: venv, CGO, minimal worker startup.
- Contributing: PRs must include the verification commands.
- Worker, Coordinator, Sync Invoker, Bundle clusters: the “Testing” section on each component page points to the corresponding files.
docs/specs/worker-test-organization.md,docs/specs/python-test-organization.md,docs/specs/system-e2e-testing.mdin the blockx repository: organization conventions.docs/specs/perf-methodology.md,docs/specs/perf-test-how-to-v2.md,e2e/perf/README.mdin the blockx repository: performance testing methodology, reproduction, and case index.AGENTS.mdin the blockx repository: the authoritative source for commands and testing guidelines.