Skip to content

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):

godevccu -mode openccu -xml-rpc-port 2001 -json-rpc-port 8080 -defaults

Point a central of the default ccu system type at it (host, port: 2001, json_rpc_port: 8080).

A simulated openccu-lite box:

godevccu -mode lite -lite-listen 127.0.0.1:2121

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 .md files must resolve to a real file on disk; TestPublishedDocsLinksStayInsideDocsDir additionally rejects a page under docs/ that links out of docs/ with a relative path.
  • Wiring — the composition-root guards (TestEveryWiringSetterHasAProductionCaller, TestEveryRegistryWalkerHasAnAdoptSeam, TestEveryEventTypeHasASubscriber, …), described in Composition root and wiring.
  • Generated reference — TestGeneratedReferenceIsFresh regenerates the pages under docs/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.json or assets/openapi.yaml, run make docs-reference and 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:

make snapshot

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:

make matter-smoke

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 lint clean (golangci-lint, including gosec).
  • make vet clean (go vet).
  • make test and make contract green.
  • make race green.
  • make integration and make e2e green.
  • make bench shows no regression > 20 %.
  • make snapshot exits 0 (cross-stack parity).
  • make chiptool-test / make matter-smoke green when the change touches the Matter bridge (CI-only, needs-chiptool label).
  • cd assets/ui && npm run typecheck clean (not covered by make test).
  • cd assets/ui && npm run test (vitest) green.
  • cd assets/ui && npm run e2e (Playwright visual regression) green.
  • make licenses clean — no GPL / LGPL / MPL / AGPL dependencies.
  • make vuln and make secrets clean.
  • No CGo introduced (CGO_ENABLED=0 default build).
  • OpenAPI validates (make openapi-lint, advisory) and the spec matches the handlers.
  • make release (goreleaser snapshot) and make docker build cleanly for all target architectures.

See the Security guide for the wider security review expectations that accompany a release.

Not part of the published site nav, but worth reading in the checkout: