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
| Module | Test Case |
|---|---|
HmacSigner | HMAC-SHA256 signature matches reference implementation |
HmacSigner | Different body produces different signature |
HmacSigner | Same body + same secret always produces same signature (deterministic) |
RetryScheduler | Attempt 1 → no delay (immediate) |
RetryScheduler | Attempt 2 → +30 s |
RetryScheduler | Attempt 3 → +5 min |
RetryScheduler | Attempt 4 → +30 min |
RetryScheduler | Attempt 5 → +2 h |
RetryScheduler | Attempt 5 (failed) → null (dead-letter) |
EventTypeMapper | All 6 DlrStatus → WebhookEventType mappings |
WebhookConfigService | Rejects non-HTTPS URL |
WebhookConfigService | Rejects secret shorter than 16 chars |
WebhookConfigService | Returns 422 when account has 10 active webhooks |
DeliveryService | Does not follow 3xx redirects |
DeliveryService | 2xx response marks delivery SUCCESS |
DeliveryService | Timeout marks delivery FAILED_RETRY |
DeliveryService | 4xx marks delivery FAILED_RETRY |
3. Integration Tests
Framework: Jest + Testcontainers (PostgreSQL 15, NATS) + mock HTTP server (nock / msw)
| Scenario | Steps |
|---|---|
| Happy path delivery | Publish webhook.dispatch → assert delivery_attempts row SUCCESS, HTTP server received correct headers + signature |
| Signature verification | Verify X-Ghasi-Signature header in received request matches manual HMAC computation |
| No active webhooks | Publish event for account with no webhooks → assert no delivery_attempts row; NATS Acked |
| Event filter mismatch | Account has webhook with events: ['DLR_DELIVERED']; publish DLR_FAILED event → assert no delivery attempt |
| Retry scheduling | Mock endpoint returns 500 → assert delivery_attempts row FAILED_RETRY with correct next_retry_at |
| Dead-letter | Simulate 5 consecutive failures → assert DEAD_LETTER status + webhook.dispatch.deadletter NATS event |
| Idempotent NATS processing | Publish same eventId twice → assert single delivery_id (idempotent) |
| REST API CRUD | Full 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-Eventheader X-Ghasi-Signatureheader verifiable with known secretX-Ghasi-Delivery-Idconsistent across retries
5. Contract Tests (Pact)
| Contract | Consumer | Provider |
|---|---|---|
webhook.dispatch schema | webhook-dispatcher | dlr-processor |
webhook.dispatch.deadletter schema | alert-service | webhook-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
secretfield 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