2026-03-10 00:00:00 -07:00
# Chaos Mode
Inject controlled failures into contract tests to validate resilience guarantees.
2026-04-30 11:34:00 -07:00
Chaos testing applies the invariant-driven verification approach from [Invariant-Driven Automated Testing ](https://arxiv.org/abs/2602.23922 ) (Malhado Ribeiro, 2021) under adverse conditions: if a contract must hold, it should still hold when dependencies fail, responses are delayed, or payloads are corrupted.
2026-03-10 00:00:00 -07:00
## Usage
2026-04-30 11:25:30 -07:00
``` javascript
2026-03-10 00:00:00 -07:00
const result = await fastify . apophis . contract ( {
2026-04-30 13:56:39 -07:00
runs : 50 ,
2026-03-10 00:00:00 -07:00
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 } ,
} ,
2026-04-30 11:25:30 -07:00
} ) ;
2026-03-10 00:00:00 -07:00
```
## Event Types
### Delay
Adds artificial latency. Tests timeout contracts:
``` apostl
timeout_occurred(this) == false
response_time(this) < 1000
```
2026-04-30 11:50:39 -07:00
**Note ** : Delay events are generated by the chaos arbitrary but the inbound delay handler is currently a no-op. Use this for timeout contract documentation; actual delay injection requires the outbound delay strategy or a custom handler.
2026-03-10 00:00:00 -07:00
### Error
Forces HTTP status codes. Tests error-handling contracts:
``` apostl
if status:503 then response_body(this).retry_after != null
```
### Dropout
Simulates network failure (status 0). Tests fallback contracts:
``` apostl
status:200 || status:0
```
### Corruption
Mutates response bodies. Tests parsing robustness:
``` apostl
response_body(this).id != null
```
2026-04-30 11:25:30 -07:00
## Corruption Strategies
2026-03-10 00:00:00 -07:00
2026-04-30 11:25:30 -07:00
Built-in strategies are content-type agnostic:
2026-03-10 00:00:00 -07:00
2026-04-30 11:25:30 -07:00
| Strategy | Effect |
|----------|--------|
| `truncate` | Cuts response body short |
| `malformed` | Invalidates structural boundaries (e.g., unclosed JSON, bad headers) |
| `field-corrupt` | Replaces a random field value with corrupted data |
Extension strategies can add content-type-specific behavior if needed.
2026-03-10 00:00:00 -07:00
## Custom Corruption via Extensions
2026-04-30 11:25:30 -07:00
``` javascript
2026-03-10 00:00:00 -07:00
const myExtension = {
name : 'custom-corrupt' ,
corruptionStrategies : {
'application/vnd.api+json' : ( data ) => ( {
2026-04-30 11:25:30 -07:00
... data ,
2026-03-10 00:00:00 -07:00
corrupted : true ,
} ) ,
'text/*' : ( data ) => ` CORRUPTED: ${ String ( data ) } ` ,
} ,
2026-04-30 11:25:30 -07:00
} ;
2026-03-10 00:00:00 -07:00
await fastify . register ( apophis , {
extensions : [ myExtension ] ,
2026-04-30 11:25:30 -07:00
} ) ;
2026-03-10 00:00:00 -07:00
```
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.
```
2026-04-30 11:25:30 -07:00
Error: chaos is only available in test environment. Set NODE_ENV=test to enable quality features.
2026-03-10 00:00:00 -07:00
```
## Interpreting Results
Failed tests include chaos events in diagnostics:
``` json
{
"statusCode" : 503 ,
"error" : "Contract violation: status:200" ,
"chaosEvents" : [
{
"type" : "error" ,
"injected" : true ,
"details" : {
"statusCode" : 503 ,
"reason" : "Chaos error: overridden 200 with 503"
}
}
]
}
```
## Best Practices
1. **Start small ** : `probability: 0.05` (5% of requests)
2. **Test one failure mode at a time ** : Comment out other chaos types
3. **Verify contracts handle chaos ** : `if status:503 then response_body(this).error != null`
4. **Use seeds for reproducibility ** : `seed: 42` makes chaos deterministic
## Example: Testing Retry Logic
2026-04-30 11:25:30 -07:00
``` javascript
2026-03-10 00:00:00 -07:00
fastify . get ( '/data' , {
schema : {
'x-ensures' : [
'if status:503 then response_headers(this).retry-after != null' ,
'redirect_count(this) <= 3' ,
] ,
} ,
2026-04-30 11:25:30 -07:00
} , handler ) ;
2026-03-10 00:00:00 -07:00
// Test
const result = await fastify . apophis . contract ( {
chaos : {
probability : 0.2 ,
error : { probability : 1 , statusCode : 503 } ,
} ,
2026-04-30 11:25:30 -07:00
} ) ;
2026-03-10 00:00:00 -07:00
```