mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
The suite drove a containerized freight API, so every code change needed an image rebuild before a test could see it, and there was no way to attach a debugger. Files also ran strictly in sequence against one shared database, which is the root of the warm-stack gotchas the README documents: stowaway paid bookings climbing back aboard, a short consist on the fifth file. The freight app now boots inside each vitest worker from dist/, and each worker owns a whole shard of the topology - its own database, payment API, gateway mock and broker vhost - so nothing mutable is shared and files run in parallel. Full suite drops from roughly 20 minutes to 196s at 4 shards. - main.ts exports createFreightApp() so the harness applies the same prefix, pipes, filters and interceptors as production instead of replaying them by hand; self-start is guarded by require.main so the Dockerfile CMD still boots - booking-window tick cadence is env-driven (BOOKING_WINDOW_TICK_CRON), */1 in the suite, */10 unchanged in production - prepare-shards.mjs seeds a template database (boot seeders, then the SQL fixtures that depend on them) and clones it per shard; it.mjs re-clones on every run, so each run is hermetic - gateway mock and payment API are generated per shard: the mock keeps modes and orders process-global and 20 of 25 specs reset it in beforeAll, and the inbound CBE bill query has to reach one specific shard's app - poll() samples every 250ms instead of 2000ms, keeping the caller's deadline - authz.it.ts seeds its own invoice; it previously read another spec's leftover and returned early, which silently passed on a pristine database Known: an unlocked MAX(sequence_no)+1 in train-scheduling.service.ts races under concurrent allocation and leaves a short consist, so 1-3 specs fail intermittently. Pre-existing and reproduces at the production tick cadence.
61 lines
2.9 KiB
YAML
61 lines
2.9 KiB
YAML
# EDR Freight — API integration stack (headless, sharded).
|
|
#
|
|
# Overlay on docker-compose.e2e.yaml, plus a GENERATED third file holding the
|
|
# per-shard services (integration/.it-shards.yaml, written by gen-shards.mjs).
|
|
#
|
|
# The freight API is NOT a container here — it boots inside each vitest worker,
|
|
# on the host, so a code change needs no image rebuild and a breakpoint works.
|
|
# Each worker is a full shard of the topology; nothing mutable is shared:
|
|
#
|
|
# shard i:
|
|
# freight app (in vitest worker, host :3111+i)
|
|
# │ ▲
|
|
# │ └──── HTTP ─── payment-api-it-{i} :3131+i (inbound CBE bill query,
|
|
# │ │ via host.docker.internal)
|
|
# └── HTTP ──────────────► │ ──HTTP──> gateway-mock-it-{i} :4600+i
|
|
# ▲ │
|
|
# └──── RabbitMQ vhost payment_s{i} ──┘ (outbox → payment.events → consumer)
|
|
#
|
|
# Shared by every shard: postgres (one container, one database per shard cloned
|
|
# from a seeded template), rabbitmq (one container, one vhost per shard), minio,
|
|
# and the one-shot migration.
|
|
#
|
|
# Its own compose project (`name:` below overrides the base) and its own host
|
|
# ports, so it can run side by side with the Cypress e2e stack.
|
|
#
|
|
# node integration/scripts/it.mjs up|test|down|logs
|
|
#
|
|
# Never start it with plain `docker compose -f docker-compose.it.yaml` — it is
|
|
# an OVERLAY and needs the base file first:
|
|
# docker compose -f docker-compose.e2e.yaml -f docker-compose.it.yaml \
|
|
# -f integration/.it-shards.yaml ...
|
|
name: edr-freight-it
|
|
|
|
services:
|
|
# Outbox transport. The payment API publishes payment.succeeded/failed here
|
|
# and freight consumes it — the production path. Copied from the passenger
|
|
# harness (e2e/docker-compose.yml). One broker, one vhost per shard
|
|
# (payment_s0, payment_s1, …) created by it.mjs — a shared vhost would let one
|
|
# shard's freight consumer eat another shard's settlement event.
|
|
rabbitmq-it:
|
|
image: rabbitmq:3-management
|
|
environment:
|
|
RABBITMQ_DEFAULT_USER: edr
|
|
RABBITMQ_DEFAULT_PASS: edr_secret
|
|
RABBITMQ_DEFAULT_VHOST: payment
|
|
ports:
|
|
- "${IT_RABBIT_PORT:-5772}:5672"
|
|
- "${IT_RABBIT_UI_PORT:-15772}:15672"
|
|
healthcheck:
|
|
# check_running, NOT ping: ping only proves the Erlang node answers, and
|
|
# it.mjs runs `rabbitmqctl add_vhost` the moment this goes healthy — which
|
|
# on a cold boot failed with "this command requires the 'rabbit' app to be
|
|
# running on the target node". check_running waits for the application.
|
|
test: ["CMD", "rabbitmq-diagnostics", "-q", "check_running"]
|
|
interval: 5s
|
|
timeout: 10s
|
|
retries: 20
|
|
# The per-shard `gateway-mock-it-{i}` and `payment-api-it-{i}` services live in
|
|
# integration/.it-shards.yaml. The base file's `freight-api-e2e` is never
|
|
# started — the app runs in-process (integration/src/app.ts).
|