feat(zgw): docker OpenZaak integration-test harness (WP-54)

Opt-in docker-compose (postgres+redis+OpenZaak, no celery/nginx) +
bootstrap-catalogus.sh seed a real OpenZaak instance; OpenZaakIntegrationTests
(Category=Integration, excluded from default dotnet test/CI) proves the ZGW
seam against it for the first time. That live run caught a real bug:
ZgwHttpClient never sent Content-Crs/Accept-Crs headers, so every write would
412 against a spec-compliant OpenZaak — fixed alongside the harness.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-30 09:08:35 +02:00
co-authored by Claude Sonnet 5
parent 73172510ea
commit 5cb3e1a9f0
12 changed files with 471 additions and 15 deletions
+74
View File
@@ -0,0 +1,74 @@
# OpenZaak integration harness (WP-54)
A real OpenZaak, for developing/testing the ZGW seam (`backend/src/BigRegister.Api/Zgw/`)
against something that isn't a fixture or a stub `HttpMessageHandler`. Deliberately **not**
part of the root `docker-compose.yml` and **not** wired into `npm run ci` / CI — see
[docs/reference/openzaak-integration.md](../../docs/reference/openzaak-integration.md) for the
full picture; this is just "how to run it".
## Bring it up
```bash
cd backend/openzaak
docker compose -f docker-compose.openzaak.yml up -d # postgres, redis, migrate+configure, OpenZaak
./bootstrap-catalogus.sh # seeds a catalogus/zaaktype/zaak to read back
```
`bootstrap-catalogus.sh` waits for OpenZaak to answer, then over plain REST + a hand-rolled
HS256 JWT (same shape as `ZgwTokenProvider.cs`, matching the `bigregister-test` client
`setup_configuration/data.yaml` creates): a catalogus, a published zaaktype ("Herregistratie
arts", with the statustypen/resultaattype/roltype OpenZaak requires before a zaaktype can be
published), and one zaak (`BIG-2026-000123`) with an initiator rol for the seeded BSN
(`111222333` — the same fixture BSN `OpenZaakZaakSourceTests.cs` uses). It writes what it
seeded to `seeded.env` (gitignored) and prints a summary.
**Not idempotent** — re-running against the same (already-seeded) instance fails on OpenZaak's
`domein`+`rsin` uniqueness constraint for the catalogus. Reset with:
```bash
docker compose -f docker-compose.openzaak.yml down -v && docker compose -f docker-compose.openzaak.yml up -d
```
## Run the integration test against it
```bash
cd backend
dotnet test --filter Category=Integration
```
`OpenZaakIntegrationTests.cs` points a `WebApplicationFactory<Program>` at
`Zgw:Enabled=true` + `http://localhost:8000` with the harness's credentials, hits
`GET /api/v1/admin/cases`, and asserts the seeded zaak comes back — through the real HTTP +
JWT + Catalogi-label-resolution path, not a mock. This test is tagged `Category=Integration`
and is **excluded** from the default `dotnet test` run and from CI (`ci.yml`,
`scripts/ci-local.sh` both filter `Category!=Integration`) — it only passes with this harness
up, so it never runs where the harness doesn't exist.
## Tear down
```bash
docker compose -f docker-compose.openzaak.yml down -v
```
## What's in here / what isn't
- `docker-compose.openzaak.yml` — postgres (postgis), redis, a one-shot `web-init` (runs
Django migrations then `setup_configuration` against `setup_configuration/data.yaml`), and
`web` (the OpenZaak API on `:8000`). Pinned to `openzaak/open-zaak:1.29.1`. No
celery/celery-beat/celery-flower/nginx — trimmed for a lean, fast-booting harness; add them
back only if a later WP needs a real async notification delivery round-trip here (WP-52's
webhook is already covered by fixture tests against no live instance).
`NOTIFICATIONS_DISABLED=true` is required, not optional: without it, OpenZaak 500s (and
**rolls back the whole create**) on any notified resource — see the compose file's comment.
- `setup_configuration/data.yaml` — the declarative, scripted alternative to clicking through
the Django admin (upstream's own documented `setup_configuration` CLI mechanism): creates the
one `bigregister-test` client (`heeft_alle_autorisaties: true` — this instance never exists
for anything but this harness, so there's no least-privilege boundary worth modeling).
- `bootstrap-catalogus.sh` — the business content (catalogus/zaaktype/zaak/…) `setup_configuration`
has no YAML for; every field value here was checked against OpenZaak's own OpenAPI spec and a
live run of this exact script, not guessed (two OpenZaak quirks it works around: a zaaktype
needs ≥1 resultaattype and 2 statustypen before it can be published, and its
`selectielijstklasse` and the zaaktype's `selectielijstProcestype` must reference the same
`procesType` on the public VNG selectielijst API).
- **Not here**: Documenten (DRC) / Notificaties (NRC) content — add if a later WP needs to prove
those round-trips against a live instance too (WP-51/52 are fixture-tested today).