diff --git a/src/models/behaviors.js b/src/models/behaviors.js
index a11c7d103..d7b4d5caa 100644
--- a/src/models/behaviors.js
+++ b/src/models/behaviors.js
@@ -106,6 +106,28 @@ const fromSchema = {
_required: true,
_allowedTypes: { string: {} },
_additionalContext: 'a JavaScript function'
+ },
+ chaos: {
+ errorRate: {
+ _required: false,
+ _allowedTypes: { number: {} },
+ _additionalContext: 'probability between 0 and 1 of injecting an error response'
+ },
+ errorStatusCode: {
+ _required: false,
+ _allowedTypes: { number: { nonNegativeInteger: true } },
+ _additionalContext: 'the status code to return when injecting an error (defaults to 500)'
+ },
+ latencyRate: {
+ _required: false,
+ _allowedTypes: { number: {} },
+ _additionalContext: 'probability between 0 and 1 of injecting random latency'
+ },
+ maxLatencyMs: {
+ _required: false,
+ _allowedTypes: { number: { nonNegativeInteger: true } },
+ _additionalContext: 'maximum latency in milliseconds when injecting'
+ }
}
};
@@ -509,6 +531,52 @@ async function lookup (originalRequest, response, lookupConfig, logger) {
return response;
}
+async function maybeInjectLatency (config, logger) {
+ const latencyRate = config.latencyRate || 0,
+ maxLatencyMs = config.maxLatencyMs || 0;
+
+ if (latencyRate <= 0 || maxLatencyMs <= 0) {
+ return;
+ }
+ if (Math.random() >= latencyRate) {
+ return;
+ }
+
+ const delay = Math.floor(Math.random() * maxLatencyMs);
+ logger.debug(`chaos: injecting ${delay}ms latency`);
+ await new Promise(resolve => setTimeout(resolve, delay));
+}
+
+function maybeInjectError (config, response, logger) {
+ const errorRate = config.errorRate || 0,
+ errorStatusCode = config.errorStatusCode || 500;
+
+ if (errorRate <= 0 || Math.random() >= errorRate) {
+ return;
+ }
+
+ logger.debug(`chaos: injecting error status ${errorStatusCode}`);
+ response.statusCode = errorStatusCode;
+ response.body = '';
+}
+
+/**
+ * Probabilistically injects faults into the response, useful for chaos engineering
+ * and resilience testing. Supports injecting errors (replacing the response with an
+ * error status code) and latency (delaying the response by a random amount up to maxLatencyMs).
+ * Both probabilities are independent and default to 0 (no chaos).
+ * @param {Object} request - The request
+ * @param {Object} response - The response
+ * @param {Object} config - The chaos configuration
+ * @param {Object} logger - The mountebank logger
+ * @returns {Promise
line flag must be set to support this behavior.
+
+
chaos
+
Probabilistically injects faults into the response. Useful for chaos engineering
+ and resilience testing: random error responses, random latency, or both. All parameters
+ are optional and default to a no-op, so you can enable just the parts you need.
+
Multiple behaviors can be added to a response, and they will be executed in array order. While
@@ -136,6 +142,15 @@ response transformation.
The probability that the response will be replaced with an error.
+ Defaults to 0 (no error injection).
+
+
+
errorStatusCode
+
A non-negative integer
+
The status code to return when injecting an error. Defaults to 500.
+
+
+
latencyRate
+
A number between 0 and 1
+
The probability that random latency will be added to the response.
+ Defaults to 0 (no latency injection).
+
+
+
maxLatencyMs
+
A non-negative integer
+
The maximum latency in milliseconds. When triggered, the injected latency
+ is a uniformly random value between 0 and this maximum.
+
+
+
+
The chaos behavior probabilistically injects faults into a response,
+making it useful for resilience and chaos engineering tests. Error injection and
+latency injection are independent: you can enable either or both. Every other field
+is optional, defaulting to a behavior that does nothing.
+
+
Here is a stub that returns a 503 on roughly 10% of calls and adds up to 1
+second of latency on roughly 5% of calls:
Since the behavior is non-deterministic by design, repeated calls against the
+same imposter will produce a mix of successful and faulty responses. This is the
+whole point: it lets you exercise retry logic, circuit breakers, and timeout
+handling in the system under test without standing up a separate fault-injection
+proxy.
+
+
If both errorRate and latencyRate trigger on the same
+request, latency is added first and then the response is replaced with the error.