Public Access
Make the end-to-end suite self-contained with Testcontainers
It needed a hand-started stack and an opt-in flag, so it ran on one machine and never in CI. It now brings up PostgreSQL, Keycloak and an OpenSSH server itself, applies the committed migrations and starts the API as a child process, which makes it part of the ordinary test run at ~25s. The API runs as a process rather than through WebApplicationFactory. The client builds its own HttpClient for a URL the user typed, so there is no seam to hand a test handler through without inventing one that exists only for tests — and a test host would replace the entry point, Kestrel and the content root, so it would never prove that Program.cs composes or that the committed appsettings is found and layered in the documented order. Running out of the API's own output directory is what makes its configuration real. The suite still consumes what ships: the realm file from deploy/keycloak, the EF migrations, the API's own appsettings. Only Oidc:Authority is overridden, because the container's port is assigned at start. Falsified by reintroducing the wildcard-port redirect URI the realm once had — Keycloak rejects the authorization request and the suite fails at sign-in, which is what proves the committed file is the one imported. Skipping the migration step likewise fails, and the failure names the pending migration. A fresh Keycloak per run also sidesteps the --import-realm trap: editing the realm file and rerunning now always tests the edit. DodoDbContextFactory gains a Create(connectionString) so the fixture and dotnet ef place the migrations history table in exactly one place. If they disagreed the API would report every migration pending, which is how the readiness gate catches it.
This commit is contained in:
@@ -137,6 +137,10 @@ database inside the container, so the realm has to be recreated along with it:
|
||||
`docker compose rm -sf keycloak && docker compose up -d keycloak`. Cost an otherwise inexplicable
|
||||
debugging detour.
|
||||
|
||||
`DodoSSH.SystemTests` is immune to this by construction — its Keycloak is created and destroyed per run —
|
||||
which is a second reason the end-to-end suite starts its own containers rather than reusing the developer's
|
||||
stack. Editing the realm file and rerunning the suite always tests the edit.
|
||||
|
||||
## Local cache
|
||||
|
||||
**The cache location is per-OS and must stay non-roaming.** `ClientPaths` chooses it:
|
||||
@@ -189,6 +193,18 @@ macOS runners have no Docker daemon, and the Windows CI job is deliberately buil
|
||||
anything proved by an integration test is proved on Linux only — which is the right place for
|
||||
server code, and no coverage at all for client platform behaviour.
|
||||
|
||||
**The end-to-end suite launches the API's own launcher executable**, falling back to `dotnet exec` on the
|
||||
assembly. The fallback exists for one reason: a checkout or artefact copy that lost the execute bit
|
||||
produces a `Win32Exception` on Linux and nothing whatsoever on Windows. *Verified on Windows only* — the
|
||||
launcher path is what runs here, so the fallback itself is reasoned rather than exercised. If the suite
|
||||
fails in CI with a permission error before any container work, that is the path to look at.
|
||||
|
||||
**It also depends on `Server:PublicBaseUrl` being knowable before startup.** The port is chosen by binding
|
||||
a loopback socket and releasing it, because the API reads that URL at startup and advertises it to clients,
|
||||
so it cannot be discovered from Kestrel afterwards. The window for another process to take the port is a
|
||||
few milliseconds; if the suite ever fails with an address-in-use, this is why, and a retry is the fix
|
||||
rather than a redesign.
|
||||
|
||||
**`[CallerFilePath]` is rewritten to `/_/...` under `ContinuousIntegrationBuild`.** Any test that
|
||||
locates a fixture by source path passes locally and fails in CI. Copy fixtures to the output
|
||||
directory and read them via `AppContext.BaseDirectory` instead; `GoldenVectorTests` shows the
|
||||
|
||||
Reference in New Issue
Block a user