Skip to main content

Audit Service — Testing Strategy

Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · TESTING_STANDARDS

1. Coverage targets

LayerTargetTool
Domain (AuditEntry, AuditExport, ChainService)≥ 90 %Vitest
Application (use cases, ingestion)≥ 85 %Vitest
Infrastructure (adapters, NATS consumer)≥ 70 %Vitest + TestContainers
Integration≥ 70 %Vitest + TestContainers
Contract100 % of consumed event schemasSchema registry conformance

2. Test types and mandatory tests

2.1 Unit tests (test/unit/)

ModuleScenarios
ChainServiceCorrect SHA-256 computation; chain links prev_id correctly; deterministic output
AuditEntry (domain)Immutability: no methods mutate state; all fields set at creation only
IngestionServiceEvent normalisation for each AuditEventType; malformed event → DLQ path
DedupServiceDuplicate source_event_id returns true; new ID returns false
AuditExport (domain)State machine: queued → processing → completed / failed; fileUrl required before completed
AuditQueryFiltersValue object: immutable; range > 90 days rejected

2.2 Integration tests (test/integration/) — MANDATORY

Test fileWhat it verifiesBlock on failure
tenant-isolation.spec.tsTenant Admin sees only own tenant's audit_entries; cross-tenant query returns 403Hard block
outbox.spec.tsN/A — audit service has no outbox. audit.export.completed.v1 published directly by export worker; verify NATS message emitted.CI
inbox.spec.tsN/A — audit service does not consume commands. Wildcard NATS consumer verified by ingestion.spec.tsCI
ingestion.spec.tsFull path: NATS message received → dedup check → normalise → chain-hash compute → INSERT → ACKHard block
dedup.spec.tsDuplicate source_event_id → silently skipped; ACK returned; row count unchangedHard block
chain-integrity.spec.tsChain-hash computed correctly; tampered chain_hash detected by verification jobHard block
db-role-permissions.spec.tsaudit_app role: INSERT succeeds; UPDATE fails with permission error; DELETE failsHard block
query-api.spec.tsFilter combinations; date range > 90 days → 400; pagination correct
export.spec.tsExport job: queued → processing → completed; file written to object storage; signed URL returned
disclosure.spec.tsGET /api/v1/audit/disclosures returns only entries for the specified patient

2.3 Contract / schema conformance tests (test/contract/)

The audit service consumes events from all platform services. For each event type, a schema conformance test verifies the ingested payload conforms to the registered schema version.

EventConformance test
identity.user.suspended.v1user-suspended.schema.spec.ts
tenant.tenant.activated.v1tenant-activated.schema.spec.ts
patient_chart.note.signed.v1note-signed.schema.spec.ts
patient_chart.breakglass.invoked.v1breakglass-invoked.schema.spec.ts
ai_gateway.decision.accepted.v1ai-decision-accepted.schema.spec.ts
… (all registered event types)*.schema.spec.ts

Malformed events (not conforming to schema) must route to DLQ.

2.4 E2E tests (test/e2e/)

FlowTest
Event emitted → ingested → queryableingestion-to-query.e2e.spec.ts
Export requested → file available → signed URL downloadableexport-flow.e2e.spec.ts
Cross-tenant isolation under real JWTtenant-isolation.e2e.spec.ts
Meta-audit: export request creates AuditEntrymeta-audit.e2e.spec.ts

3. Test data strategy

  • All test data uses synthetic events with stable source_event_id values.
  • TestContainers provides an isolated Postgres 16 instance per integration test run.
  • NATS: TestContainers NATS image for integration tests; mock for unit tests.
  • Object storage: MinIO TestContainers for export tests.

4. CI pipeline

┌─────────────────────────────────────────────────────┐
│ 1. lint + typecheck │
│ 2. unit tests (vitest) │
│ 3. integration tests (TestContainers) │
│ ├── tenant-isolation.spec.ts (MANDATORY) │
│ ├── ingestion.spec.ts (MANDATORY) │
│ ├── dedup.spec.ts (MANDATORY) │
│ ├── chain-integrity.spec.ts (MANDATORY) │
│ └── db-role-permissions.spec.ts (MANDATORY) │
│ 4. schema conformance tests (schema registry) │
│ 5. coverage gate (≥ 80 % overall) │
│ 6. e2e tests (staging deploy) │
└─────────────────────────────────────────────────────┘

5. Quality gates

GateThresholdEnforced by
Overall coverage≥ 80 %Vitest coverage in CI
Domain coverage≥ 90 %Path-filtered coverage
tenant-isolationMust passCI hard block
chain-integrityMust passCI hard block
db-role-permissionsMust passCI hard block
Schema conformanceMust passSchema registry CI step

6. Security-specific tests

TestDescription
audit_entries UPDATE via audit_app roleExpect permission denied error from Postgres
audit_entries DELETE via audit_app roleExpect permission denied error from Postgres
Chain-hash recompute after field mutationExpect verification job to report mismatch
Query with foreign tenant JWTExpect empty result (RLS filters to zero rows)