test(acl): ACL integration test against real OpenZaak (closes #46) #54
@@ -63,24 +63,11 @@ jobs:
|
|||||||
path: services/acl/StrykerOutput/**/reports/mutation-report.html
|
path: services/acl/StrykerOutput/**/reports/mutation-report.html
|
||||||
if-no-files-found: warn
|
if-no-files-found: warn
|
||||||
|
|
||||||
integration:
|
# NOTE: there is deliberately no `integration` job here yet. `make integration`
|
||||||
runs-on: ubuntu-latest
|
# runs the ACL ↔ real-OpenZaak test locally / on a host-executing runner, but on
|
||||||
steps:
|
# the hosted runner a process on the runner cannot reach the stack's published
|
||||||
- uses: https://github.com/actions/checkout@v4
|
# ports (sibling containers — see gitea-actions-gotchas.md §5). Running it inside
|
||||||
- uses: https://github.com/actions/setup-dotnet@v4
|
# the compose network is tracked in #55.
|
||||||
with:
|
|
||||||
dotnet-version: '10.0.x'
|
|
||||||
# `make integration` brings the OpenZaak stack up, seeds a PUBLISHED BIG
|
|
||||||
# zaaktype (OZ_PUBLISH=1) and runs the Integration-category tests, then tears
|
|
||||||
# down. Needs Docker + python3 (both on ubuntu-latest) and outbound access to
|
|
||||||
# selectielijst.openzaak.nl from the OpenZaak container (see ADR-0006).
|
|
||||||
- run: make integration
|
|
||||||
- name: dump OpenZaak logs on failure
|
|
||||||
if: failure()
|
|
||||||
run: docker compose -f infra/openzaak/docker-compose.yml logs --no-color --tail=80 oz-init openzaak 2>&1 || true
|
|
||||||
- name: tear down on failure
|
|
||||||
if: failure()
|
|
||||||
run: docker compose -f infra/openzaak/docker-compose.yml down --volumes 2>&1 || true
|
|
||||||
|
|
||||||
compose-smoke:
|
compose-smoke:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ itself. No new test dependency is added.**
|
|||||||
- **The lane is kept out of the fast checks.** `make unit` runs with
|
- **The lane is kept out of the fast checks.** `make unit` runs with
|
||||||
`--filter "Category!=Integration"`; Stryker is pinned to `Acl.Tests` (`test-projects`), so
|
`--filter "Category!=Integration"`; Stryker is pinned to `Acl.Tests` (`test-projects`), so
|
||||||
neither the unit nor the mutation lane needs a live stack. A new `make integration` target
|
neither the unit nor the mutation lane needs a live stack. A new `make integration` target
|
||||||
brings the stack up, seeds, runs the lane, and always tears down — mirrored by a Gitea
|
brings the stack up, seeds, runs the lane, and always tears down. This matches `make` being
|
||||||
Actions `integration` job. This matches `make` being the single source of truth (ADR-0005).
|
the single source of truth (ADR-0005).
|
||||||
- **Publishing is opt-in in the seed.** `infra/openzaak/seed_catalogus.py` gains an
|
- **Publishing is opt-in in the seed.** `infra/openzaak/seed_catalogus.py` gains an
|
||||||
`OZ_PUBLISH=1` path that adds the relations OpenZaak's publish requires — two statustypen
|
`OZ_PUBLISH=1` path that adds the relations OpenZaak's publish requires — two statustypen
|
||||||
(begin/eind), a roltype, and a resultaattype whose Selectielijst procestype is matched onto
|
(begin/eind), a roltype, and a resultaattype whose Selectielijst procestype is matched onto
|
||||||
@@ -69,8 +69,13 @@ itself. No new test dependency is added.**
|
|||||||
`selectielijst.openzaak.nl`. It is a stable public reference API (the same one OpenZaak uses
|
`selectielijst.openzaak.nl`. It is a stable public reference API (the same one OpenZaak uses
|
||||||
in production) but it is a network touchpoint, and a CI environment without egress would need
|
in production) but it is a network touchpoint, and a CI environment without egress would need
|
||||||
a local Selectielijst service or a recorded fixture. `OZ_SELECTIELIJST` overrides the base URL.
|
a local Selectielijst service or a recorded fixture. `OZ_SELECTIELIJST` overrides the base URL.
|
||||||
- **Cost:** the lane needs the stack up first; CI runs it as a dedicated job (Docker + dotnet +
|
- **Cost:** the lane needs the stack up first, so it is separate from the fast lanes.
|
||||||
python3), separate from the fast lanes.
|
- **Not yet a hosted-runner job.** `make integration` passes locally and on a host-executing
|
||||||
|
runner, but on Gitea's hosted runner a process *on the runner* cannot reach the stack's
|
||||||
|
published ports — Compose starts sibling containers via the host daemon, so the ports bind to
|
||||||
|
the host, not the runner (gitea-actions-gotchas.md §5, the same split as §1). Running the test
|
||||||
|
and seed *inside* the compose network (via a built image, not bind mounts) to gate it in CI is
|
||||||
|
tracked in **#55**. Until then the lane runs locally and is not a merge gate.
|
||||||
|
|
||||||
## Alternatives considered
|
## Alternatives considered
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,14 @@ and CI cannot drift:
|
|||||||
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
| `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK |
|
||||||
| `unit` | `make unit` → `dotnet test … -c Release --filter "Category!=Integration"` | .NET 10 SDK |
|
| `unit` | `make unit` → `dotnet test … -c Release --filter "Category!=Integration"` | .NET 10 SDK |
|
||||||
| `mutation` | `make mutation` → `dotnet tool restore` → `dotnet stryker` (ACL); uploads the HTML report as an artifact | .NET 10 SDK |
|
| `mutation` | `make mutation` → `dotnet tool restore` → `dotnet stryker` (ACL); uploads the HTML report as an artifact | .NET 10 SDK |
|
||||||
| `integration` | `make integration` → `openzaak-up` → seed a **published** BIG zaaktype (`OZ_PUBLISH=1`) → `dotnet test … --filter "Category=Integration"` → tear down | .NET 10 SDK + container engine + python3 + egress to `selectielijst.openzaak.nl` |
|
|
||||||
| `compose-smoke` | `make smoke` → seed config volumes → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 |
|
| `compose-smoke` | `make smoke` → seed config volumes → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 |
|
||||||
|
|
||||||
|
> **`make integration` is not a hosted-runner job yet.** The ACL ↔ real-OpenZaak
|
||||||
|
> test (`make integration`, ADR-0006) passes locally and on a host-executing runner,
|
||||||
|
> but a process on the hosted runner can't reach the stack's published ports
|
||||||
|
> (sibling containers — see [gitea-actions-gotchas.md §5](gitea-actions-gotchas.md)).
|
||||||
|
> Run it inside the compose network to gate it in CI — tracked in **#55**.
|
||||||
|
|
||||||
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`,
|
||||||
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
`https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea
|
||||||
Actions resolves them from GitHub.
|
Actions resolves them from GitHub.
|
||||||
|
|||||||
@@ -124,3 +124,34 @@ needed). v3 uses the older artifact protocol that Gitea implements, and has no G
|
|||||||
guard. Inputs are the same (`name`, `path`, `if-no-files-found`), so it is a drop-in
|
guard. Inputs are the same (`name`, `path`, `if-no-files-found`), so it is a drop-in
|
||||||
swap. Do **not** bump to `@v4` until act_runner advertises github.com-compatible
|
swap. Do **not** bump to `@v4` until act_runner advertises github.com-compatible
|
||||||
artifact support.
|
artifact support.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. A runner process can't reach a service container's published port
|
||||||
|
|
||||||
|
**Symptom** — green locally, but a CI step that runs *on the runner* and talks to a
|
||||||
|
compose service over `localhost` fails. The ACL integration test's seed died with:
|
||||||
|
|
||||||
|
```
|
||||||
|
OpenZaak ready (000)
|
||||||
|
urllib.error.URLError: <urlopen error [Errno 111] Connection refused>
|
||||||
|
make: *** [Makefile:114: integration] Error 1
|
||||||
|
```
|
||||||
|
|
||||||
|
OpenZaak was demonstrably up — uwsgi had been serving for ~2 minutes — yet
|
||||||
|
`curl`/`urllib` to `localhost:8000` from the runner were refused the whole time.
|
||||||
|
|
||||||
|
**Why** — the same sibling-container split as §1. Compose starts the stack via the
|
||||||
|
host daemon, so `ports: ["8000:8000"]` publishes to the *daemon host*, not to the job
|
||||||
|
container. From the runner, `localhost:8000` has nothing listening. (`make smoke`
|
||||||
|
sidesteps this by polling readiness via `docker inspect` (§2), never a service port.)
|
||||||
|
|
||||||
|
**Fix** — don't talk to service ports from the runner. Either check state via `docker
|
||||||
|
inspect` (health), or run the client **inside the compose network** so it reaches the
|
||||||
|
service by name (`http://openzaak:8000`). For a test/seed that needs the repo's own
|
||||||
|
code, deliver it via a **built image** (not a bind mount — §1), then
|
||||||
|
`docker run --network <stack>_cg …`.
|
||||||
|
|
||||||
|
**Status** — `make integration` (the ACL ↔ real-OpenZaak test, ADR-0006) therefore
|
||||||
|
runs locally / on a host-executing runner only. Gating it on the hosted runner via
|
||||||
|
the compose network is tracked in **#55**.
|
||||||
|
|||||||
Reference in New Issue
Block a user