3.1 KiB
3.1 KiB
Chaos Mode
Inject controlled failures into contract tests to validate resilience guarantees.
Usage
const result = await fastify.apophis.contract({
depth: 'standard',
chaos: {
probability: 0.1, // 10% of requests get chaos
delay: { probability: 1, minMs: 100, maxMs: 500 },
error: { probability: 1, statusCode: 503 },
dropout: { probability: 1 },
corruption: { probability: 1 },
},
})
Event Types
Delay
Adds artificial latency. Tests timeout contracts:
timeout_occurred(this) == false
response_time(this) < 1000
Error
Forces HTTP status codes. Tests error-handling contracts:
if status:503 then response_body(this).retry_after != null
Dropout
Simulates network failure (status 0). Tests fallback contracts:
status:200 || status:0
Corruption
Mutates response bodies. Tests parsing robustness:
response_body(this).id != null
Content-Type Aware Corruption
Built-in strategies for common formats:
| Content-Type | Strategy | Effect |
|---|---|---|
application/json |
Truncate or null field | Removes fields or sets random field to null |
application/x-ndjson |
Chunk corrupt | Corrupts one NDJSON chunk |
text/event-stream |
Event corrupt | Adds malformed SSE line |
multipart/form-data |
Field corrupt | Replaces field with corrupted data |
text/plain |
Truncate | Cuts string in half |
Custom Corruption via Extensions
const myExtension = {
name: 'custom-corrupt',
corruptionStrategies: {
'application/vnd.api+json': (data) => ({
...data as object,
corrupted: true,
}),
'text/*': (data) => `CORRUPTED:${String(data)}`,
},
}
await fastify.register(apophis, {
extensions: [myExtension],
})
Extension strategies take precedence over built-ins. Wildcard patterns (text/*) match any subtype.
Environment Guard
Low-level contract chaos APIs require NODE_ENV=test. For CLI qualification, environment policy controls whether chaos gates may run.
Error: Chaos mode is only available in test environment.
Interpreting Results
Failed tests include chaos events in diagnostics:
{
"statusCode": 503,
"error": "Contract violation: status:200",
"chaosEvents": [
{
"type": "error",
"injected": true,
"details": {
"statusCode": 503,
"reason": "Chaos error: overridden 200 with 503"
}
}
]
}
Best Practices
- Start small:
probability: 0.05(5% of requests) - Test one failure mode at a time: Comment out other chaos types
- Verify contracts handle chaos:
if status:503 then response_body(this).error != null - Use seeds for reproducibility:
seed: 42makes chaos deterministic
Example: Testing Retry Logic
fastify.get('/data', {
schema: {
'x-ensures': [
'if status:503 then response_headers(this).retry-after != null',
'redirect_count(this) <= 3',
],
},
}, handler)
// Test
const result = await fastify.apophis.contract({
chaos: {
probability: 0.2,
error: { probability: 1, statusCode: 503 },
},
})