Testing¶
The test pillars OpenCCU-Loom is held to, the make target behind each, what the contract tests guard, the cross-stack snapshot pipeline, and the pre-release checklist.
Who this page is for
Contributors and developers writing or running tests. For the development setup itself, see Development environment.
Test pillars¶
| Pillar | Location | Run with | What it covers |
|---|---|---|---|
| Unit | per package | make test | Regular Go tests; target ≥ 80 % in core packages (client, central, model/custom, store). |
| Contract | tests/contract/ | make contract | Protocol / capability invariants — each test states a hard rule and fails if violated. |
| Wiring pins | tests/contract/wiring_pins/ | make contract | Pins for production wiring through the composition root — see Composition root and wiring. |
| Golden / replay | tests/golden/ | make test | Recorded CCU sessions replayed against the daemon; assertions compare emitted events / JSON to golden files. |
| Integration | tests/integration/ (//go:build integration) | make integration | Daemon run against the in-process godevccu simulator plus Mosquitto (Docker); end-to-end behavior. |
| End-to-end | tests/e2e/ (//go:build e2e) | make e2e | Full black-box end-to-end flows against the built binary (REST, WS, MQTT, SPA, Prometheus, CLI). |
| Matter scenarios | tests/scenario/ | make scenarios | Replays the Matter behaviour corpus under notes/parity/matter/scenarios/ against a live go-fabric bridge. It carries no build tag, so make test runs it too; make scenarios runs it alone and verbose. |
| Chip-tool commissioner | tests/chiptool/ (//go:build chiptool) | make chiptool-test, make matter-smoke | Real chip-tool commissioner runs against the Matter bridge — the only guard that exercises a real Matter controller, not just parity fixtures. CI-only; cannot run on macOS. |
| Load test | tests/loadtest/ | go test -tags=loadtest ./tests/loadtest/... | Production-shaped load harness (documented in notes/testplans/testplan.md). |
| Benchmarks | tests/bench/ | make bench | Performance; regressions > 20 % block release. |
| Fuzz | per package | make fuzz | XML-RPC / BIN-RPC / JSON-RPC parsers and paramset normalization. |
| SPA unit (vitest) | assets/ui/src/**/*.test.ts | cd assets/ui && npm run test | Component-level Svelte tests. Not covered by make test. |
| SPA browser-e2e | assets/ui/tests/e2e/ | cd assets/ui && npm run e2e | Playwright browser-e2e + light/dark visual-regression baselines, mocked API. Not covered by make test. |
| SPA typecheck | assets/ui/ | cd assets/ui && npm run typecheck | tsc type-checking; not covered by make test and must be green before a release merge. |
make test runs the unit and contract pillars (wiring pins and the scenario corpus included); make race adds -race. Integration, e2e, bench, fuzz, chip-tool, load-test, and the SPA suites sit behind build tags or their own toolchains and run on their own targets.
For the openccu-lite south path the counterpart to godevccu is litefake — godevccu's pkg/litefake, a fake of a whole box (token auth, the XML-RPC proxy with its init refusal and method tiers, the SSE event stream, metadata, system and pairing APIs) composed over per-interface simulator listeners. The occulited transport tests, the lite_* contract and wiring pins, and the lite e2e runs all boot it in-process; the wire contract it implements is kept verbatim in its CONTRACT.md, and tests/contract/occulited_wire_contract_test.go pins the production client against it, deviation runs included.
Running against a simulated system¶
Both south-bound system types can be simulated on the workstation — no hardware involved. That is useful far beyond the test suites: developing against a large device fleet, demonstrations, or pointing a daemon on another machine at a reproducible counterpart. Both recipes use the godevccu CLI; go install github.com/SukramJ/godevccu/cmd/godevccu@latest (or make build in its checkout) yields the one binary.
A simulated CCU (XML-RPC + JSON-RPC):
Point a central of the default ccu system type at it (host, port: 2001, json_rpc_port: 8080).
A simulated openccu-lite box:
serves occulited's HTTP API and, by default, loads every device type godevccu embeds — the startup log prints the per-interface device counts, the URL and the API token. -lite-devices restricts the fleet; -lite-tokens, -lite-interfaces and -lite-tls steer auth, topology and transport. Add a central pointed at it (a fresh data_dir — the YAML file is read into the config store only on first boot):
centrals:
- name: litebox
host: 127.0.0.1
system_type: openccu-lite
api_token: "olt_0123456789abcdef0123456789abcdef" # the CLI's built-in default token
json_rpc_port: 2121
interfaces:
- HmIP-RF
- BidCos-RF
- VirtualDevices
The rest of the config file is the ordinary daemon setup from the configuration reference. After bring-up the daemon carries the box's full fleet (GET /api/v1/devices), a value written over REST comes back as a device event on the stream, and a setValue sent to the box's proxy by a second client shows up in the daemon's model — the same push path a real box uses, exercised end to end.
Delegate test boilerplate
Production code (architecture, public API, wire decisions) belongs in the main work; the mechanical per-test work — fakes, table cases, assertions, race scaffolding — is well suited to a sub-agent. Name the file and surface, list the cases, and point at an existing test for style.
What contract tests guard¶
Contract tests in tests/contract/ lock invariants that must never silently drift. Representative examples:
- Protocol / capability invariants — that every MVP interface has ping/pong, that CUxD uses the BIN-RPC backend, that the device-profile registry stays in parity, and a cross-stack reliability-defaults drift detector.
- Documentation purity (
doc_purity_test.go) — code comments carry no audit / wave / drift tracking tags and no German function-words; markdown references in//comments must point at files that exist. - Markdown link integrity — every relative Markdown link across the repo's
.mdfiles must resolve to a real file on disk;TestPublishedDocsLinksStayInsideDocsDiradditionally rejects a page underdocs/that links out ofdocs/with a relative path. - Wiring — the composition-root guards (
TestEveryWiringSetterHasAProductionCaller,TestEveryRegistryWalkerHasAnAdoptSeam,TestEveryEventTypeHasASubscriber, …), described in Composition root and wiring. - Generated reference —
TestGeneratedReferenceIsFreshregenerates the pages underdocs/reference/(configuration, WebSocket, REST) and compares them byte for byte with the checked-in copies. When it fails after a change to the config schema,assets/wsapi.jsonorassets/openapi.yaml, runmake docs-referenceand commit the result.
Touching a boundary means touching a test
If you change a protocol, capability, or state-machine boundary, you must add or update a contract test in the same change.
Cross-stack snapshot pipeline¶
The release-gate parity check compares OpenCCU-Loom's domain model against aiohomematic's model when both load the same wire data. The whole pipeline runs from one target:
This dumps both stack snapshots against the same godevccu release and diffs them per field (make snapshot-go, make snapshot-py, make snapshot-diff). Exit 0 means full intersection parity. The snapshot JSON files are large and gitignored — produced on demand, kept locally. The common-schema definition lives in notes/parity/model_snapshot_schema.md.
When you change model code (data-point creation, visibility marks, custom-DP composition, channel methods), rerun the snapshot and verify the drift score has not regressed in your area.
Matter parity¶
The Matter wire stack lives in the go-fabric module, and its parity tests run there — the *_parity_matterjs_test.go files under cluster/, tlv/, im/, mdns/ and secure/. What this repository still holds is the host half: internal/north/matteradapter/parity_matterjs_test.go, the schema pin in tests/contract/matter_schema_sync_test.go, the cluster-conformance guards under tests/integration/, and the chip-tool smoke target:
The full set of standing Matter guards is catalogued in the Matter parity contract.
Pre-release checklist¶
Run before tagging a release. All of these must pass:
-
make lintclean (golangci-lint, includinggosec). -
make vetclean (go vet). -
make testandmake contractgreen. -
make racegreen. -
make integrationandmake e2egreen. -
make benchshows no regression > 20 %. -
make snapshotexits 0 (cross-stack parity). -
make chiptool-test/make matter-smokegreen when the change touches the Matter bridge (CI-only, needs-chiptool label). -
cd assets/ui && npm run typecheckclean (not covered bymake test). -
cd assets/ui && npm run test(vitest) green. -
cd assets/ui && npm run e2e(Playwright visual regression) green. -
make licensesclean — no GPL / LGPL / MPL / AGPL dependencies. -
make vulnandmake secretsclean. - No CGo introduced (
CGO_ENABLED=0default build). - OpenAPI validates (
make openapi-lint, advisory) and the spec matches the handlers. -
make release(goreleaser snapshot) andmake dockerbuild cleanly for all target architectures.
See the Security guide for the wider security review expectations that accompany a release.
Related, repo-only testing docs¶
Not part of the published site nav, but worth reading in the checkout:
notes/contributor/spa-e2e-against-godevccu.md— SPA end-to-end validation against the embeddedgodevccusimulator, without a physical CCU.notes/testplans/testplan.mdandnotes/testplans/e2e-testplan.md— the fuller test-debt dashboard and the E2E suite's design plan / as-built log.