chaos-injector
Version:
Chaos engineering middleware for testing API resilience
115 lines (101 loc) • 3.41 kB
JavaScript
// ChaosInjector/middlewareWrapper.js
// Import middleware functions directly
const randomFailure = require('./middlewares/randomFailure');
const responseDelay = require('./middlewares/responseDelay');
const emptyResponse = require('./middlewares/emptyResponse');
const timeout = require('./middlewares/timeout'); // Import timeout
// Define predefined chaos profiles
const chaosProfiles = {
'flakyNetwork': {
delayRange: [300, 1500],
failureRate: 0.25,
errorTypes: ['503', '504']
},
'overloadedServer': {
delayRange: [1200, 4000],
failureRate: 0.6,
errorTypes: ['500', '502', '503']
},
'gremlinAttack': {
failureRate: 0.4,
errorTypes: ['400', '401', '403', '404', '500'],
emptyType: 'empty_object'
},
'intermittentEmpty': {
failureRate: 0.8,
emptyType: 'empty'
},
'timeoutScenario': {
failureRate: 0.95,
simulateTimeout: true
},
'latencySpike': {
delayRange: [2000, 8000],
failureRate: 0.0
},
'errorStorm': {
failureRate: 0.7,
errorTypes: ['500', '502', '503', '504']
},
'emptyTrap': {
failureRate: 0.6,
emptyType: 'empty_object'
}
};
function withChaos(profileName, userConfig = {}) {
let profileConfig = {};
if (typeof profileName === 'string' && chaosProfiles[profileName]) {
profileConfig = chaosProfiles[profileName];
} else {
userConfig = profileName || {}; // If profileName is not a string, assume it's the userConfig
}
// Merge profile config with user config, giving user config priority
const config = { ...profileConfig, ...userConfig };
return (req, res, next) => {
const { failureRate, delayRange, errorTypes, emptyType, simulateTimeout } = config || {};
// 1. Timeout Simulation
if (simulateTimeout && Math.random() < failureRate) {
console.log('Simulating timeout...');
return; // Stop further middleware execution
}
// 2. Delayed Response with Intermittent Failures
if (delayRange && failureRate && errorTypes && errorTypes.length > 0) {
const delayOptions = {
delayRange: delayRange
};
const failureOptions = {
failureRate: failureRate,
errorTypes: errorTypes
};
return responseDelay(delayOptions)(req, res, () => {
if (Math.random() < failureRate) {
return randomFailure(failureOptions)(req, res, next); // randomFailure handles next()
} else {
next(); // Proceed to the route handler
}
});
}
// 3. Random Failure
if (failureRate && errorTypes && errorTypes.length > 0) {
const failureOptions = {
failureRate: failureRate,
errorTypes: errorTypes
};
return randomFailure(failureOptions)(req, res, next); // randomFailure handles next()
}
// 4. Empty Response
if (emptyType && Math.random() < failureRate) {
return emptyResponse({ type: emptyType })(req, res, next); // emptyResponse handles next()
}
// 5. Response Delay
if (delayRange) {
const delayOptions = {
delayRange: delayRange
};
return responseDelay(delayOptions)(req, res, next); // responseDelay handles next()
}
// 6. If no chaos is injected, proceed to the route handler
next();
};
}
module.exports = withChaos;