Skip to main content

cbc-bridge-service — Testing Strategy

Version: 1.0 Status: Draft Owner: Government / Emergency + QA Last Updated: 2026-04-21 References: SERVICE_OVERVIEW.md, SECURITY_MODEL.md, FAILURE_MODES.md, docs/standards/DEFINITION_OF_DONE.md

Testing strategy for cbc-bridge-service. Given this service is a civil-emergency tier with direct MNO RAN impact, the testing bar is elevated: zero tolerance for silent regressions in the PKI verification path, the CBS encoder, or the audit hash-chain.


1. Test Pyramid

┌─────────────────┐
│ Drill + GameDay │ ← real-MNO staging, quarterly
├─────────────────┤
│ E2E tests │ ← full flow through mock MNO CBE
├─────────────────┤
│ Contract tests │ ← with regulator-portal + gov-client clients
├─────────────────┤
│ Integration │ ← Postgres, NATS, HSM (softhsm2), CBE adapters
├─────────────────┤
│ Unit tests │ ← dominant — domain logic, no I/O
└─────────────────┘

Distribution: ~70% unit, ~20% integration, ~6% contract, ~3% E2E, ~1% drill/GameDay.


2. Unit Tests

Framework: Vitest. Must NOT import infrastructure (no NestJS, no @grpc, no Postgres, no NATS). Pure domain logic only.

2.1 CBS PDU encoder tests

  • Per severity (P0/P1/P2): Message Identifier mapping correct (4370/4371/4372).
  • Per language: DCS correct (GSM7 for en, UCS-2 for fa/ps/ar).
  • Per-language body exceeding 1 page: correct Page Parameter pagination.
  • Serial Number allocation monotonic.
  • ≥ 40 tests covering boundary conditions (exactly 82 GSM7 / 93 UCS-2 chars, single / multi-page, mixed-language body bundles).

2.2 UCS-2 / GSM7 conformance

Corpus test: 100 strings per language (en/fa/ps/ar), round-trip through encode → decode → byte-equal check. Includes ZWJ, ZWNJ, Tatweel, Arabic-Indic digits, mixed Latin+Arabic.

2.3 Domain-state-machine tests

Broadcast state transitions:

  • ACCEPTED → DISPATCHING: all happy path permutations.
  • ACCEPTED → CANCELLED: only within grace window + only with dual-control.
  • DISPATCHING → ACKED: all MNOs succeed.
  • DISPATCHING → PARTIAL: mixed MNO outcome.
  • DISPATCHING → FAILED: all MNOs failed.
  • Invalid transitions (e.g., ACKED → CANCELLED) rejected.

≥ 30 tests. Error cases must assert specific error codes.

2.4 Hash-chain tests

  • Chain-append correctness: record_hash = sha256(canonical(payload) || prev_hash).
  • Canonicalisation per RFC 8785 (JCS): deterministic across object-key orderings, number representations, whitespace.
  • Tamper detection: single-bit flip in a row must be detected by verifier.
  • Genesis row prev_hash = 32 zero bytes.
  • Concurrent-append safety: two workers appending simultaneously must not corrupt ordering.

2.5 Authorisation-gate tests

  • Caller cert-subject matching (cbc.authorised_callers lookup).
  • allowedSeverities enforcement: caller authorised for P1 cannot submit P0.
  • allowedRegions enforcement: caller authorised for Kabul cannot target Balkh without explicit grant.
  • Expiry enforcement: notBefore / notAfter on caller registry row.

2.6 Adapter selection tests

Per-MNO configured adapter chosen at dispatch; unknown MNO → ADAPTER_NOT_CONFIGURED; fallback preference logic; config-reload without restart.

2.7 Property-based tests

fast-check properties:

  • Hash chain appended N times remains monotonic and verifiable.
  • Any permutation of per-MNO dispatch order yields same final-status aggregate.
  • CBS PDU encode then decode == original (for all language × severity combinations).
  • Canonicalisation invariant under object-key reordering.

At least 10 properties, 500+ runs each.

Unit coverage targets: ≥ 90% line on domain layer; ≥ 80% branch.


3. Integration Tests

Framework: Vitest + Testcontainers + softhsm2. Real Postgres, real NATS, real Redis in containers; HSM via softhsm2.

3.1 End-to-end persistence

  • Accept broadcast → row in cbc.broadcasts, row in cbc.mno_dispatches per MNO, audit row appended.
  • Re-accept of same correlationId within dedup window returns original broadcastId (idempotency).
  • Hash-chain verifier over 10 000 inserted rows completes < 30 s.

3.2 PKI + HSM paths

Using softhsm2 pre-loaded with test caller certs:

  • Valid cert + valid signature → SUCCESS.
  • Cert revoked (CRL) → FAILURE CRL_REVOKED.
  • Cert revoked (OCSP-stapled) → FAILURE OCSP_REJECT.
  • Cert not in cbc.authorised_callers → FAILURE CALLER_NOT_REGISTERED.
  • Signature over tampered request body → FAILURE BAD_SIG.
  • Replay of earlier signature (nonce / timestamp window) → FAILURE REPLAY_NONCE.

3.3 MNO CBE adapter integration

Mock CBE endpoints (Standard3gpp, Ericsson, Huawei):

  • Happy dispatch path.
  • CBE timeout → FAILED for that MNO; others unaffected.
  • CBE reject (vendor-proprietary error) → adapter translates to canonical CBE_REJECT.
  • Mid-dispatch adapter circuit-break: after 3 failures, circuit opens.

3.4 Drill mode

  • Scheduled drill fires on time.
  • Drill uses CBS test-range Message Identifier (4370..4379 test slot).
  • Drill is_drill=true in audit.
  • Drill-result report written to S3 + email sent to NDMA + NOC.

3.5 NATS event emission

  • Produced events match JSON Schema.
  • cbc.audit.v1 carries chain recordHash.
  • Outbox pattern: NATS publish + DB write atomic (durable outbox table).

3.6 Cancellation dual-control

  • Single-approver cancel → rejected.
  • Two-approver cancel within window → CANCELLED for pending MNOs.
  • Already-ACKED MNOs retained; audit breakdown shows effective vs. ineffective.

4. Contract Tests

Pact (provider) + event-schema conformance.

4.1 Provider contract

cbc-bridge-service is provider for:

  • regulator-portal-service — gRPC BroadcastEmergency, GetBroadcastStatus, CancelBroadcast.
  • Civil Defence / NDMA client — same gRPC with different auth material.

4.2 Consumer contract

cbc-bridge-service is consumer of:

  • HSM PKCS#11 library (vendor-tested).
  • MNO CBE adapters (standard3gpp specified; proprietary adapters tested against vendor stubs).

4.3 Event schema conformance

JSON Schema for every produced NATS event; ajv-based contract test fails the build if a field is removed or renamed without a schema-version bump.


5. End-to-End Tests

Env: dedicated cbc-e2e Kubernetes namespace with real service + Postgres + Redis + NATS + HSM + 3 mock MNO CBE pods.

Scenarios:

5.1 Happy-path emergency broadcast

Government client submits signed P0 → accepted → dispatched to all 5 MNO mocks → all ACK → DELIVERED → audit chain intact → regulator-portal SIEM stream event received.

5.2 Partial success

One MNO mock configured to time out → final status PARTIAL → per-MNO breakdown correct → retry of failed MNO dispatches on human-triggered resubmit succeeds.

5.3 Authentication failure under storm

10 concurrent requests with revoked certs → all rejected → CbcPkiVerifyFailureSpike alert fires → legitimate request still succeeds.

5.4 Drill

Monthly drill fires → drill broadcast visible in NOC dashboard → after-action report generated → email to NDMA + NOC.

5.5 Cancellation

Government client submits → initiates cancel → second approver confirms within 60 s → CANCELLED for pending MNOs → audit shows both initiator + approver.

5.6 Audit verification

Insert 10 000 audit rows, daily verifier runs → OK. Manually corrupt one row → next run detects break at specific row.


6. Drill & GameDay

Quarterly GameDay against real MNO staging endpoints (per MoU with MNO partners).

6.1 GameDay scope

  • Submit authorised test broadcast from government-PKI client.
  • Verify CBS PDU arrives at MNO CBE correctly.
  • Verify subscriber handsets (test devices per MNO) receive + display correctly in all 4 languages.
  • Confirm ATRA observer acknowledges drill reception via regulator portal.

6.2 GameDay chaos injection

  • Kill primary HSM pod → verify HSM HA fail-over + broadcast completes.
  • Kill one MNO CBE adapter → verify PARTIAL status + NOC paging.
  • Network partition Kabul ↔ Mazar → verify region-local operation continues.

6.3 GameDay pass criteria

  • 100% test broadcasts delivered to ≥ 4 of 5 MNOs within 60 s.
  • Zero PKI verification false-failures.
  • Zero audit chain breaks.
  • All chaos injections recovered per runbook within declared RTO.

7. Load Tests

7.1 Normal load

Expected traffic is low: ≤ 10 broadcasts / month steady-state. Load testing focuses on concurrency + burst resilience.

7.2 Burst load

100 concurrent cancellation requests. Assert no state-machine race; all cancellations audit-logged correctly.

7.3 Fingerprint-storm load

500 bad-cert requests / second for 5 min → CbcPkiVerifyFailureSpike fires → legitimate requests still accepted < 500 ms P99.


8. Security Tests

8.1 PKI-bypass corpus

500+ crafted attack vectors:

  • Cert chain manipulation.
  • Signature malleability.
  • Replay attack (reused signature with stale timestamp).
  • Nonce window evasion.
  • Homoglyph attack on callerOrg.

All must produce specific FAILURE reason + audit row.

8.2 Authorisation escalation

  • Caller authorised for P1 attempts P0 → rejected.
  • Caller authorised for Kabul attempts Balkh → rejected.
  • Caller with expired notAfter row → rejected.

8.3 Audit tamper

  • UPDATE on cbc.audit → rejected by Postgres trigger.
  • DELETE on cbc.audit → rejected by Postgres trigger.
  • Manual INSERT with fake prev_hash → detected by verifier.

8.4 Dual-control bypass attempts

  • Single approver attempts to approve own initiation → rejected.
  • Approver's cert revoked between initiation and approval → rejected.
  • Approval outside 60 s window → rejected.

8.5 Injection tests

  • SQL injection in REST admin endpoints.
  • Path traversal in drill S3 reports.
  • XSS in NOC dashboard inputs.

9. Coverage Targets

LayerLineBranch
Domain≥ 90%≥ 80%
Application≥ 80%≥ 75%
Infrastructure≥ 60%≥ 60%
Value Objects100%95%

Mutation testing (stryker-js): ≥ 75% for aggregates, ≥ 85% for VOs.


10. CI Gates

  • TypeScript strict + ESLint domain-isolation.
  • OpenAPI / proto diff gate: no breaking changes without major bump.
  • Pact broker verification.
  • Event schema registry conformance.
  • Security tests must all pass; PKI-bypass corpus 0 bypasses.
  • 80% mutation tests survived.

Failing any gate blocks merge.