Tenant Service — Testing Strategy
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: TESTING_STANDARDS · DEFINITION_OF_DONE
1. Coverage targets
| Tier | Target | Enforced by |
|---|---|---|
| Unit | ≥ 80% statements + lines | Vitest --coverage in CI |
| Integration | Mandatory scenarios below | CI gate |
| Contract (Pact) | All published + consumed events | Pact broker |
| E2E | Critical tenant flows | Playwright staging |
2. Mandatory integration tests
2.1 Tenant isolation (test/integration/tenant-isolation.spec.ts)
| Scenario | Assertion |
|---|---|
| Tenant A admin cannot read Tenant B hierarchy nodes | 403 / RLS blocks |
| Tenant A user cannot hold membership in Tenant B nodes | RLS enforced |
Cross-tenant evaluate() call rejected | 403 TENANT_CROSS_TENANT |
2.2 Outbox (test/integration/outbox.spec.ts)
| Scenario | Assertion |
|---|---|
ActivateTenant writes tenant row and outbox row atomically | DB transaction |
Outbox relay publishes tenant.tenant.activated.v1 to NATS | Event received |
| Partial saga failure leaves tenant in PENDING; outbox not published | Compensated state |
2.3 Inbox (test/integration/inbox.spec.ts)
| Scenario | Assertion |
|---|---|
identity.user.registered.v1 consumed once (NATS redelivery) | No duplicate profiles |
identity.user.deactivated.v1 anonymizes profile idempotently | Idempotent apply |
2.4 Activation saga
| Scenario | Assertion |
|---|---|
| All downstream steps succeed → tenant becomes ACTIVE | Status confirmed |
| Hierarchy call fails → retried 3 times → PENDING with alert | Bounded backoff |
| Idempotency token prevents duplicate activation | Same token returns original result |
2.5 RBAC/ABAC evaluate
| Scenario | Assertion |
|---|---|
CLINICIAN allowed patient_chart:read at member node | decision: allow |
CLINICIAN denied patient_chart:write at non-member node | decision: deny |
| Built-in role cannot be deleted | 422 returned |
3. Contract tests (Pact)
| Subject | File |
|---|---|
tenant.tenant.activated.v1 | test/contract/tenant.activated.schema.spec.ts |
tenant.tenant.suspended.v1 | test/contract/tenant.suspended.schema.spec.ts |
tenant.role_assignment.created.v1 | test/contract/tenant.role.schema.spec.ts |
| identity-service consumer | test/contract/identity-service.pact.spec.ts |
4. E2E tests (staging)
| Scenario | File |
|---|---|
| Full onboarding: create → activate → create node → invite user → assign role | tenant-onboarding.e2e.spec.ts |
| Suspend tenant → confirm identity session invalidation within TTL | tenant-suspension.e2e.spec.ts |
| ABAC evaluate for clinical user at node | abac-evaluate.e2e.spec.ts |
5. Test data strategy
| Concern | Approach |
|---|---|
| Tenant isolation | Each suite creates isolated tenant via tenant_rls_bypass role |
| Downstream stubs | Wiremock stubs for identity-service and facility-service in integration |
| Idempotency tests | Use fixed idempotency key per test; teardown between tests |
| Subscription expiry | Inject clock via ClockPort; freeze time to trigger expiry cron |