Batch 4 of test implementation cycle 1 (existing-code Step 6, final batch).
- AZ-585 SteadyStateLoadTests + ColdStartRssTests: NFT-RES-LIM-01..04.
SteadyStateLoadFixture runs one 5-min sustained-load window and samples
RSS (docker stats), Npgsql conns (pg_stat_activity), and FDs
(/proc/1/fd) every 5s; three test methods assert independently. All
SkippableFact-gated on docker primitives.
- AZ-586 PerformanceTests: NFT-PERF-01..04. Sequential single-client,
5 warm-ups + N measured calls, P50+P95 via LatencyPercentiles, recorded
to PERF_RESULTS_FILE. Tagged Category=Perf so default gate excludes them.
Infrastructure:
- entrypoint.sh now applies --filter "${TEST_FILTER:-Category!=Perf}"
per AZ-586 (default CI gate excludes performance).
- MetricCsvRecorder: idempotent CSV appender keyed on env var, used by
both Perf and ResLim categories.
Step 6 (Implement Tests) is complete. Final report at
_docs/03_implementation/implementation_report_tests.md handoffs the
full-suite gate to test-run/SKILL.md (Step 7).
Co-authored-by: Cursor <cursoragent@cursor.com>
10 KiB
Test Implementation Final Report
Run: existing-code Step 6 (Implement Tests)
Date: 2026-05-15
Cycle: 1
Verdict: HANDOFF — full-suite gate owned by .cursor/skills/test-run/SKILL.md (Step 7)
Scope
11 test tasks decomposed by /decompose-tests and tracked under epic AZ-575:
| Task | Description | SP | Batch |
|---|---|---|---|
| AZ-576 | Test infrastructure (compose, csproj, mocks, helpers) | 5 | 1 |
| AZ-577 | Vehicles positive (FT-P-01..06) | 5 | 2 |
| AZ-578 | Missions positive (FT-P-07..12) | 5 | 2 |
| AZ-579 | Waypoints + health positive (FT-P-13..18) | 5 | 2 |
| AZ-580 | Validation + authz negative (FT-N-01..08) | 3 | 2 |
| AZ-581 | Security auth/claims (NFT-SEC-01..06+04b) | 5 | 3 |
| AZ-582 | Security alg/rotation/CORS (NFT-SEC-07..13) | 5 | 3 |
| AZ-583 | Resilience cascade + migrator (NFT-RES-01..04) | 3 | 3 |
| AZ-584 | Resilience config/DB/rotation/race (NFT-RES-05..08) | 5 | 3 |
| AZ-585 | Resource limits (NFT-RES-LIM-01..04) | 3 | 4 |
| AZ-586 | Performance (NFT-PERF-01..04) | 3 | 4 |
| Total | 47 |
Results
| Batch | Tasks | SP | Verdict | Carry-forwards |
|---|---|---|---|---|
| 1 | AZ-576 | 5 | PASS_WITH_WARNINGS | 0 |
| 2 | AZ-577..AZ-580 | 18 | PASS_WITH_WARNINGS | 3 |
| 3 | AZ-581..AZ-584 | 18 | PASS_WITH_WARNINGS | 3 |
| 4 | AZ-585, AZ-586 | 6 | PASS_WITH_WARNINGS | 0 |
Cumulative reviews: 1 (cumulative_review_batches_01-03_cycle1_report.md, PASS_WITH_WARNINGS, 4 Low findings).
AC Test Coverage
| Source | ACs | Tests | Coverage |
|---|---|---|---|
| FT-P (functional positive) | 18 | 18 | 18/18 |
| FT-N (negative) | 8 | 8 | 8/8 |
| NFT-SEC (security) | 14 | 22 | 14/14 (some scenarios → multiple Theory rows) |
| NFT-RES (resilience) | 8 | 12 | 8/8 |
| NFT-RES-LIM (resource lim) | 4 | 4 | 4/4 |
| NFT-PERF (performance) | 4 | 4 | 4/4 |
| Total | 56 | 68 | 56/56 |
Every AC has at least one trace via [Trait("Traces", "AC-X.Y")]; structural carry-forwards (6 total) are pinned with [Trait("carry_forward", "...")] so dotnet test --filter "carry_forward~..." surfaces them as a set when the underlying spec/code reconciliation lands.
Spec-vs-Code Carry-forwards (6 total)
| Site | Spec says | Code says | Carry-forward tag |
|---|---|---|---|
FT-P-03 Vehicles/PositiveTests.cs |
POST /vehicles/{id}/setDefault → 200 + body |
[HttpPatch("{id:guid}/default")] → 204 NoContent |
AC-1.4/route-shape |
FT-P-14/15 Waypoints/PositiveTests.cs |
Nested GeoPoint:{Lat,Lon,Mgrs} |
LinqToDB entity flat Lat/Lon/Mgrs |
flat-waypoint-shape |
FT-N-07 Waypoints/NegativeTests.cs |
Missing parent → 404 + problem envelope | GetWaypoints returns [] |
AC-4.2/missing-parent-soft |
NFT-RES-01 Resilience/CascadeF3Tests.cs |
Mid-walk cascade is transactional | MissionService.DeleteMission is non-transactional |
ADR-006 |
NFT-RES-02 Resilience/CascadeF4Tests.cs |
Waypoint cascade leaves detection=0/waypoint=1 partial state | WaypointService.DeleteWaypoint queries media BEFORE any deletion — aborts at step 1 with nothing deleted |
AC-4.6/walk-order |
NFT-RES-08 Resilience/DefaultVehicleRaceTests.cs |
TOCTOU race observable | ux_vehicles_one_default partial unique index closes the race |
AC-1.4/index-closes-race |
These carry-forwards flip the moment the spec or the code is reconciled; the tests fail loudly at that point — intentional.
Code Review Summary
- 0 Critical / 0 High / 0 Medium across all four batches.
- 4 Low findings captured in cumulative review (3 follow-up + 1 baseline-carried) — see
_docs/03_implementation/cumulative_review_batches_01-03_cycle1_report.md. - Auto-fix rounds across the cycle: batch 2 (89× xUnit1030 warnings), batch 3 (3× missing-using errors), batch 4 (1× TokenMinter parameter-less ctor). All auto-fix-eligible per the Auto-Fix Gate matrix; no escalations.
Files Added (high level)
- Helpers (10):
ApiDtos,DbAssertions,DockerLogs,FixtureSql,ForeignKeypair,HttpAssertions,LatencyPercentiles,MetricCsvRecorder,MissionsContainerHelper— plus the existingTestEnvironment. - Fixtures (9):
CascadeF3Fixture,CascadeF4Fixture,ComposeRestartFixture,DbResetFixture,JwksMockReverseFixture(spec-only stub),JwksRotateFixture,PostgresStopStartFixture,Seeds,StubSchema,SteadyStateLoadFixture. - Test classes (24): grouped under
Tests/{Vehicles,Missions,Waypoints,Health,Errors,Security,Resilience,Performance,ResourceLimits,Reporting}/per the AZ-576 layout. - Infrastructure:
docker-compose.test.ymlextensions (fixtures volume),entrypoint.shCategory-filter,Reporting/TrxToCsvPostProcessor.cs(from batch 1). - JWKS mock: extended
SignBody(permissions_array) +TokenSigner(kid_override validation) — required by NFT-SEC-06 and NFT-SEC-11.
SkippableFact / SkippableTheory inventory
| Test | Skip predicate | Reason when skipped |
|---|---|---|
Tests/Health/HealthTests.NFT_P_17 (FT-P-17) |
COMPOSE_RESTART_ENABLED=1 |
postgres-test stop/start |
Tests/Errors/Error500Tests.NFT_N_08 |
COMPOSE_RESTART_ENABLED=1 |
drops vehicles table |
Tests/Security/ErrorRedactionTests.NFT_SEC_08 |
COMPOSE_RESTART_ENABLED=1 |
drops vehicles table |
Tests/Security/StartupConfigTests.NFT_SEC_12 (theory + HTTP-JWKS) |
MissionsContainerHelper.Enabled |
docker run primitives |
Tests/Security/CorsConfigTests.NFT_SEC_13 (4 scenarios) |
MissionsContainerHelper.Enabled |
docker run primitives |
Tests/Resilience/CascadeF3Tests.NFT_RES_01 |
COMPOSE_RESTART_ENABLED=1 |
drops media table |
Tests/Resilience/CascadeF4Tests.NFT_RES_02 |
COMPOSE_RESTART_ENABLED=1 |
drops media table |
Tests/Resilience/MigratorRestartTests.NFT_RES_03/04 |
ComposeRestartFixture.Enabled |
docker compose restart |
Tests/Resilience/ConfigDbStartupTests.* (8 methods) |
MissionsContainerHelper.Enabled |
docker run primitives |
Tests/Resilience/JwksRotationNoRestartTests.NFT_RES_07 |
MissionsContainerHelper.Enabled (for StartedAt read) |
docker inspect |
Tests/ResourceLimits/SteadyStateLoadTests.* (3 methods) |
SteadyStateLoadFixture.SkipReason (set on missing docker) |
docker stats / docker exec |
Tests/ResourceLimits/ColdStartRssTests.NFT_RES_LIM_04 |
COMPOSE_RESTART_ENABLED=1 + MissionsContainerHelper.Enabled |
docker compose stop/start |
Every Skippable test surfaces an explicit reason; none silent-pass.
Handoff to Step 7 (Run Tests)
This report is a HANDOFF — the full-suite gate is owned by .cursor/skills/test-run/SKILL.md. That skill is responsible for:
- Building the docker compose stack (
docker compose -f docker-compose.test.yml --profile test build). - Running the e2e-consumer (
docker compose ... up --abort-on-container-exit --exit-code-from e2e-consumer e2e-consumer postgres-test missions jwks-mock). - Inspecting
test-results/report.csv+ the Skippable test reasons. - Surfacing any blocking failure to the user via the test-run-skill's BLOCKING-gate protocol.
- Optionally enabling the Docker-CLI Skippable subset via a one-time consumer-image upgrade (
docker-cliinstall + socket bind) before the next cycle.
The performance suite is intentionally NOT part of the default gate — it runs via scripts/run-performance-tests.sh only.
Outstanding follow-ups (NOT blocking Step 7)
- Docker-CLI inside e2e-consumer image — needed to activate the 12 Skippable methods. Recommend a separate ticket sized 3 SP (Dockerfile add of
docker-clipackage +docker-compose.test.yml/var/run/docker.sockmount). Validates run-perf script's/app/→/src/path bug at the same time. - Test/source compilation separation —
Azaion.Missions.csprojSdk.Web globs pulltests/**/*.cs. Recommend<Compile Remove="tests/**" />or moving to a.sln. Pre-existing project layout drift. - AC-1.4 carry-forward decision — see NFT-RES-08 carry-forward. The product team should decide whether the partial unique index OR an application-level guard is the canonical solution; today the test pins the index behaviour.
- AC-4.6 walk-order decision — see NFT-RES-02 carry-forward. The waypoint cascade walks dependency tables in a different order than the spec implied; the team should reconcile spec and code.
Sign-off
Cycle 1 test implementation complete. 4 batches, 11 tasks, 47 SP. All ACs traced; no blocking findings; tracker tickets transitioned to In Testing. Autodev advances to Step 7 (Run Tests).