Skip to main content

Config Service — Testing Strategy

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


1. Coverage Targets

Test typeCoverage targetTool
Unit tests≥ 80 % statement + branchVitest
Integration testsAll use cases coveredVitest + Testcontainers (PostgreSQL + Redis)
Contract tests (consumer)All internal API endpointsPact
Contract tests (event schema)All 13 produced event typesJSON Schema
E2E testsCritical resolution pathsPlaywright / SuperTest against running service

2. Mandatory Test Scenarios

2.1 Tenant Isolation (test/integration/tenant-isolation.spec.ts)

ScenarioExpected
Resolve for user in Tenant A returns Tenant A config✓ allow, Tenant A data
Resolve for user in Tenant A with Tenant B nodeId{ effect: "deny", reason: "CROSS_TENANT" }
GET /internal/config/tokens with nodeId belonging to Tenant B403 CROSS_TENANT
TENANT_ADMIN from Tenant A cannot create role in Tenant B403 Forbidden
RLS policy prevents SELECT of Tenant B config_nodes when app.current_tenant_id = Tenant A0 rows returned

2.2 Outbox (test/integration/outbox.spec.ts)

ScenarioExpected
Feature definition created → event in outbox before tx commitEvent present in outbox table
Outbox relay publishes to NATS → marks delivered_atdelivered_at not null
Crash between tx commit and NATS publish → relay replaysEvent delivered exactly once (dedup by event ID)

2.3 Inbox (test/integration/inbox.spec.ts)

ScenarioExpected
Same event delivered twice (NATS redelivery)Second delivery acknowledged, not processed
inbox table prevents duplicate cache evictionCache evicted exactly once

3. Unit Test Scenarios

ModuleKey scenarios
ResolveConfigUseCaseStep-by-step: module deny, feature deny, FORBIDDEN, ABAC deny, ExplicitAllow, ExplicitDeny
RoleBFSExpanderBFS stops at depth 10; cycles skipped; empty role set
DesignTokenMergerLWW priority: User > Module > OrgNode > Tenant > Global; locale override
UIVisibilityResolverRole rule applied; user rule overrides role rule; ExplicitAllow cascades to bound elements
UserNodeOverrideCheckerExpired override silently ignored; active override wins; conflict detection
ConfigNodeCycleDetectorDetects cycle in parent chain; depth-limited traversal
CacheKeyBuilderKey format correctness per namespace convention

4. Contract Tests

Pact Consumer Contracts

ProviderContractKey interactions
facility-serviceGET /internal/hierarchy/nodes/{id}/ancestorsReturns ancestor chain for valid nodeId; 403 for cross-tenant
platform-admin-serviceGET /internal/licenses/checkReturns { active: true/false }
platform-admin-serviceGET /internal/platform/features/{key}Returns { enabled: true/false }
access-policyPOST /internal/access/evaluateReturns { effect: "allow|deny", reason, policyId }

Event Schema Tests

All 13 event subjects validated against registered JSON schema on publish.


5. Performance Tests

ScenarioTarget
Resolution with cold cache (no Redis hit)p95 < 300 ms
Resolution with warm cachep95 < 20 ms
Concurrent resolutions: 100 rpsNo degradation, p99 < 500 ms
BFS expansion with 8-level role tree< 10 ms

6. Security Tests

TestExpected
Resolution request with Tenant B nodeIdCROSS_TENANT deny
POST override with missing justification422 Unprocessable Entity
POST role with isSystem=true by TENANT_ADMIN403 Forbidden
BFS with cycle (cycle injected in test DB)Cycle skipped; terminates cleanly
RLS bypass attempt via SQL injection in featureKeyParameterized query; no bypass