@@ -125,56 +125,60 @@ After each image builds, [Trivy](https://trivy.dev/) scans it for known vulnerab
125125dependencies. The scan fails if it finds any critical or high severity issues with available fixes. Results upload to
126126GitHub Security for tracking. The backend scan respects ` .trivyignore ` for acknowledged vulnerabilities.
127127
128- ## Integration tests
128+ ## Backend tests
129129
130- The integration test workflow is the most complex. It spins up the entire stack on a GitHub Actions runner to verify
131- that services work together correctly.
130+ The backend CI workflow runs three test jobs: unit tests (no infrastructure needed), integration tests (requires
131+ infrastructure), and E2E tests (requires infrastructure and Kubernetes).
132+
133+ ### Integration tests
134+
135+ Integration tests verify that services work together correctly. Tests run inside Docker containers to ensure the same
136+ environment as production.
132137
133138``` mermaid
134139sequenceDiagram
135140 participant GHA as GitHub Actions
136- participant K3s as K3s Cluster
137141 participant Docker as Docker Compose
138- participant Tests as pytest
139-
140- GHA->>K3s: Install k3s
141- GHA->>Docker: Pre-pull base images
142- GHA->>Docker: Build services (bake)
143- GHA->>Docker: Start compose stack
144- Docker->>Docker: Wait for health checks
145- GHA->>Tests: Run pytest
146- Tests->>Docker: HTTP requests
147- Tests-->>GHA: Coverage report
142+ participant Tests as pytest (in container)
143+
144+ GHA->>Docker: Build base + backend images
145+ GHA->>Docker: Start infrastructure (infra --wait)
146+ GHA->>Docker: docker compose run backend pytest
147+ Tests->>Docker: Connect to kafka:29092, mongo:27017
148+ Tests-->>GHA: Coverage report (via volume mount)
148149 GHA->>GHA: Upload to Codecov
149150```
150151
151- The workflow starts by installing [ k3s] ( https://k3s.io/ ) , a lightweight Kubernetes distribution, so the backend can
152- interact with a real cluster during tests. It pre-pulls container images in parallel to avoid cold-start delays during
153- the build step.
152+ The workflow builds the base image with GHA layer caching using [ docker/build-push-action] ( https://github.com/docker/build-push-action ) ,
153+ then builds the backend image on top. Infrastructure services start via ` ./deploy.sh infra --wait ` .
154154
155- The CI workflow uses ` deploy.sh ` to start the infrastructure, ensuring consistency between local development and CI
156- environments. The ` deploy.sh dev --ci ` command starts the full stack without observability services (Jaeger, Grafana,
157- etc.) and waits for all services to be healthy before proceeding. For backend-only tests, ` deploy.sh infra --wait `
158- starts just the infrastructure services (MongoDB, Redis, Kafka, Zookeeper, Schema Registry).
155+ Tests run inside a container using ` docker compose run --rm -T backend ` , which:
159156
160- The [ docker/bake-action] ( https://github.com/docker/bake-action ) builds all services with GitHub Actions cache support.
161- It reads cache layers from previous runs and writes new layers back, so unchanged dependencies don't rebuild. The cache
162- scopes are branch-specific with a fallback to main, meaning feature branches benefit from the main branch cache even on
163- their first run.
157+ - Uses the same Docker network as infrastructure services
158+ - Connects to services using Docker hostnames (` kafka:29092 ` , ` mongo:27017 ` )
159+ - Writes coverage reports to the mounted volume for upload
164160
165- Once images are built, ` docker compose up -d ` starts the stack. The workflow then uses curl's built-in retry mechanism
166- to wait for the backend health endpoint:
161+ The ` .env.test ` file contains Docker-internal hostnames, ensuring tests use the same configuration locally and in CI.
162+
163+ ### E2E tests
164+
165+ E2E tests require Kubernetes for code execution. The workflow installs [ k3s] ( https://k3s.io/ ) on the runner and
166+ configures the kubeconfig to be accessible from inside Docker containers:
167167
168168``` bash
169- curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:443/api/v1/health/live
169+ # Update kubeconfig to use host IP instead of localhost
170+ HOST_IP=$( hostname -I | awk ' {print $1}' )
171+ sed -i " s/127.0.0.1/${HOST_IP} /g" /home/runner/.kube/config
170172```
171173
172- This approach is cleaner than shell loops and more reliable than Docker Compose's ` --wait ` flag (which has issues with
173- init containers that exit after completion). The backend's ` depends_on ` configuration ensures MongoDB, Redis, Kafka,
174- and Schema Registry are healthy before backend starts, so waiting for backend health implicitly waits for all
175- dependencies. Once the health check passes, the workflow runs pytest against the integration and unit test suites with
176- coverage reporting. Test isolation uses
177- per-worker database names and schema registry prefixes to avoid conflicts when pytest-xdist runs tests in parallel.
174+ Tests run inside Docker with the kubeconfig mounted:
175+
176+ ``` bash
177+ docker compose run --rm -T \
178+ -v /home/runner/.kube/config:/app/kubeconfig.yaml:ro \
179+ backend \
180+ uv run pytest tests/e2e -v
181+ ```
178182
179183Coverage reports go to [ Codecov] ( https://codecov.io/ ) for tracking over time. The workflow always collects container
180184logs and Kubernetes events as artifacts, which helps debug failures without reproducing them locally.
@@ -209,17 +213,28 @@ uv run mypy .
209213# Security scan
210214uv tool run bandit -r . -x tests/ -ll
211215
212- # Unit tests only (fast)
216+ # Unit tests only (fast, no infrastructure needed )
213217uv run pytest tests/unit -v
218+ ```
214219
215- # Full integration tests (requires docker compose up)
216- uv run pytest tests/integration tests/unit -v
220+ For integration and E2E tests, use Docker to match the CI environment:
221+
222+ ``` bash
223+ # Start infrastructure
224+ ./deploy.sh infra --wait
225+
226+ # Run integration tests inside Docker
227+ docker compose run --rm -T backend \
228+ uv run pytest tests/integration -v
229+
230+ # Run E2E tests (requires k8s configured)
231+ docker compose run --rm -T \
232+ -v ~ /.kube/config:/app/kubeconfig.yaml:ro \
233+ backend \
234+ uv run pytest tests/e2e -v
217235```
218236
219- For the full integration test experience, start the stack with ` docker compose up -d ` , wait for the backend to be
220- healthy, then run pytest. Alternatively, use ` ./deploy.sh test ` which handles startup, health checks, testing, and
221- cleanup automatically. The CI workflow's yq modifications aren't necessary locally since your environment
222- likely has the expected configuration already.
237+ Alternatively, use ` ./deploy.sh test ` which handles startup, health checks, testing, and cleanup automatically.
223238
224239## Build optimizations
225240
0 commit comments