Skip to main content

Webhook Dispatcher — Testing Strategy

Status: populated Owner: Platform Engineering Last updated: 2026-04-18 Companion: APPLICATION_LOGIC · API_CONTRACTS

1. Coverage Target

≥ 80% line coverage.

2. Unit Tests

Framework: Jest + ts-jest

ModuleTest Case
HmacSignerHMAC-SHA256 signature matches reference implementation
HmacSignerDifferent body produces different signature
HmacSignerSame body + same secret always produces same signature (deterministic)
RetrySchedulerAttempt 1 → no delay (immediate)
RetrySchedulerAttempt 2 → +30 s
RetrySchedulerAttempt 3 → +5 min
RetrySchedulerAttempt 4 → +30 min
RetrySchedulerAttempt 5 → +2 h
RetrySchedulerAttempt 5 (failed) → null (dead-letter)
EventTypeMapperAll 6 DlrStatus → WebhookEventType mappings
WebhookConfigServiceRejects non-HTTPS URL
WebhookConfigServiceRejects secret shorter than 16 chars
WebhookConfigServiceReturns 422 when account has 10 active webhooks
DeliveryServiceDoes not follow 3xx redirects
DeliveryService2xx response marks delivery SUCCESS
DeliveryServiceTimeout marks delivery FAILED_RETRY
DeliveryService4xx marks delivery FAILED_RETRY

3. Integration Tests

Framework: Jest + Testcontainers (PostgreSQL 15, NATS) + mock HTTP server (nock / msw)

ScenarioSteps
Happy path deliveryPublish webhook.dispatch → assert delivery_attempts row SUCCESS, HTTP server received correct headers + signature
Signature verificationVerify X-Ghasi-Signature header in received request matches manual HMAC computation
No active webhooksPublish event for account with no webhooks → assert no delivery_attempts row; NATS Acked
Event filter mismatchAccount has webhook with events: ['DLR_DELIVERED']; publish DLR_FAILED event → assert no delivery attempt
Retry schedulingMock endpoint returns 500 → assert delivery_attempts row FAILED_RETRY with correct next_retry_at
Dead-letterSimulate 5 consecutive failures → assert DEAD_LETTER status + webhook.dispatch.deadletter NATS event
Idempotent NATS processingPublish same eventId twice → assert single delivery_id (idempotent)
REST API CRUDFull create/read/update/delete cycle via HTTP

4. End-to-End Tests

Scope: Platform smoke test suite. DLR Processor → webhook.dispatch → Webhook Dispatcher → mock customer endpoint. Assert:

  • Webhook received with correct X-Ghasi-Event header
  • X-Ghasi-Signature header verifiable with known secret
  • X-Ghasi-Delivery-Id consistent across retries

5. Contract Tests (Pact)

ContractConsumerProvider
webhook.dispatch schemawebhook-dispatcherdlr-processor
webhook.dispatch.deadletter schemaalert-servicewebhook-dispatcher

6. Security Tests

  • Verify SSRF prevention: attempt to register http://169.254.169.254/ URL → expect 400 or NetworkPolicy block.
  • Verify no secret in API response: POST webhook → GET webhook → assert no secret field in response.
  • Verify HMAC signature: tamper with payload → customer endpoint should reject (tested in contract docs, not enforced by service).

7. CI Pipeline

lint → type-check → unit tests → integration tests (Testcontainers) → contract tests → build → trivy scan