# Chaos Mode Inject controlled failures into contract tests to validate resilience guarantees. 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. ## Usage ```javascript const result = await fastify.apophis.contract({ runs: 50, chaos: { delay: { probability: 0.1, minMs: 100, maxMs: 500 }, error: { probability: 0.1, statusCode: 503 }, dropout: { probability: 0.05 }, corruption: { probability: 0.1 }, }, }); ``` ## Event Types ### Delay Adds artificial latency. Tests timeout contracts: ```apostl response_time(this) < 1000 ``` **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. ### Error Forces HTTP status codes. Tests error-handling contracts: ```apostl // Behavioral: when the service is unavailable, the client receives a valid retry signal if status:503 then response_headers(this).retry-after > 0 ``` ### Dropout Simulates network failure (status 0). Tests fallback contracts: ```apostl // Behavioral: partial failure must still return previously cached data if status:0 then response_body(this).cached_data == previous(response_body(GET /cache/{request_params(this).key})) ``` ### Corruption Mutates response bodies. Tests parsing robustness: ```apostl // Behavioral: corrupted requests maintain traceability for debugging if status:400 then response_body(this).request_id == request_headers(this).x-request-id ``` ## Corruption Strategies Built-in strategies are content-type agnostic: | 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. ## Custom Corruption via Extensions ```javascript const myExtension = { name: 'custom-corrupt', corruptionStrategies: { 'application/vnd.api+json': (data) => ({ ...data, 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 is only available in test environment. Set NODE_ENV=test to enable quality features. ``` ## Interpreting Results Failed tests include chaos events in diagnostics: ```json { "statusCode": 503, "error": "Contract violation: if status:503 then response_headers(this).retry-after > 0", "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_code(GET /health) == 200` 4. **Use seeds for reproducibility**: `seed: 42` makes chaos deterministic ## Example: Testing Retry Logic ```javascript fastify.get('/data', { schema: { 'x-ensures': [ 'if status:503 then response_headers(this).retry-after > 0', 'redirect_count(this) <= 3', ], }, }, handler); // Test const result = await fastify.apophis.contract({ chaos: { error: { probability: 0.2, statusCode: 503 }, }, }); ```