diff --git a/README.md b/README.md index 6132090..df05b82 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ connect-chaos ============= +[![Circle CI](https://circleci.com/gh/Dakuan/connect-chaos.svg?style=svg&circle-token=be329dbcfa94b3635df9ae15d1f89133e5b05a95)](https://circleci.com/gh/Dakuan/connect-chaos) + ## Connect / Express middleware that causes chaos @@ -31,7 +33,9 @@ app.use(chaos({ delay: 300 }); -// requests might return a 500 (default) +// requests might return an error code +// Client error codes: 400, 401, 402, 403, 404, 405, 406, 407, 407, 409, 410, 411, 412, 413, 414, 415, 416, 417 +// Server Error codes: 500, 501, 502, 503, 504, 505 app.use(chaos({ error: true }); @@ -41,7 +45,17 @@ app.use(chaos({ error: 401 }); -// requests might return 500 or be delayed by 6000ms +// requests might return a code in the array +app.use(chaos({ + error: [404, 500] +})); + +// requests might return a code that matches the regex +app.use(chaos(){ + error: /^40/ +}); + +// requests might return an erro code or be delayed by 6000ms app.use(chaos({ error: true, delay: 6000 diff --git a/example/index.js b/example/index.js index 3e99292..b7a7c37 100644 --- a/example/index.js +++ b/example/index.js @@ -1,6 +1,6 @@ var express = require('express'), app = express(), - chaos = require('../index'); + chaos = require('../src/index'); app.use(chaos()); diff --git a/package.json b/package.json index e2d5cb2..d91d446 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "connect-chaos", - "version": "0.1.0", + "version": "0.2.0", "description": "connect / express middleware that causes chaos", - "main": "index.js", + "main": "src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha tests/**/*-spec.js" }, "repository": { "type": "git", @@ -14,7 +14,7 @@ "chaos", "express", "chaos monkey", - "testing", + "testing", "connect" ], "author": { @@ -29,5 +29,8 @@ "homepage": "https://github.com/Dakuan/connect-chaos", "dependencies": { "ramda": "^0.8.0" + }, + "devDependencies": { + "mocha": "^2.1.0" } } diff --git a/src/handlers/error.js b/src/handlers/error.js index e48d4a0..0b55f10 100644 --- a/src/handlers/error.js +++ b/src/handlers/error.js @@ -1,17 +1,37 @@ var R = require('ramda'), - runOnProp = require('../util/run-on-prop'); + randomElement = require('../util/random-element'), + runOnProp = require('../util/run-on-prop'); + +var clientErrors = R.range(400, 418); +var serverErrors = R.range(500, 506); +var all = R.concat(clientErrors, serverErrors); + +var codeMatchingRegex = function(regex) { + return R.find(function(c) { + return R.func('test', regex, c); + }, all); +}; + +var parseOpt = R.cond( + [R.is(Number), R.I], // if number then that pick that error code + [R.is(Array), randomElement], // if array pick from those + [R.is(RegExp), codeMatchingRegex], // if regex then code matching that regex + [R.alwaysTrue, function() { + return randomElement.call(null, all); + }] // random error code +); // sends an error code function _error(code) { - var code = code || 500; - return function _errorHandler(req, res, next) { - console.log('CHAOS: throwing ' + code); - res.status(code); + return function(req, res, next) { + var toThrow = parseOpt(code); + console.log('CHAOS: throwing ' + toThrow); + res.status(toThrow); res.end(); } } module.exports = { - predicate: R.has('error'), - factory: runOnProp(_error, 'error') -}; \ No newline at end of file + predicate: R.has('error'), + factory: runOnProp(_error, 'error') +}; diff --git a/index.js b/src/index.js similarity index 95% rename from index.js rename to src/index.js index 2a9f66b..200f897 100644 --- a/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ var R = require('ramda'), - handlers = require('./src/handlers/handlers'); + handlers = require('../src/handlers/handlers'); // picks random element from an array function _randomElement(array) { @@ -11,6 +11,7 @@ function _truthy(val) { return !!val; } + // calls a method on a object with the args // flipped to accept the object last var _flipFunc = R.curry(function(method, args, obj) { diff --git a/src/util/random-element.js b/src/util/random-element.js new file mode 100644 index 0000000..16c53f7 --- /dev/null +++ b/src/util/random-element.js @@ -0,0 +1,6 @@ +// picks random element from an array +function _randomElement(array) { + return array[Math.floor(Math.random() * array.length)]; +} + +module.exports = _randomElement; \ No newline at end of file diff --git a/src/util/run-on-prop.js b/src/util/run-on-prop.js index 0fc9ac0..4b5ee71 100644 --- a/src/util/run-on-prop.js +++ b/src/util/run-on-prop.js @@ -7,7 +7,8 @@ function _runOnProp(fn, prop) { return R.compose( fn, // apply the function R.prop('value'), // unwrap the monad - R.map(R.ifElse(R.is(Number), R.I, R.always())), // if the prop isn't a number use undefined + // R.map(R.I), + // R.map(R.ifElse(R.is(Number), R.I, R.always())), // if the prop isn't a number use undefined R.map(R.prop(prop)), // get the prop if the argument is truthy Maybe // Maybe null ); diff --git a/tests/handlers/errors-spec.js b/tests/handlers/errors-spec.js new file mode 100644 index 0000000..bce2942 --- /dev/null +++ b/tests/handlers/errors-spec.js @@ -0,0 +1,55 @@ +var subject = require('../../src/handlers/error'), + R = require('ramda'), + assert = require('assert'); + +function assertStatus(handler, expectedCode) { + handler(null, { + status: function(code) { + assert(code === expectedCode); + }, + end: function() {} + }); +} + +describe("Error handler", function() { + describe("when a valid number is provided ", function() { + it("should use that error code", function() { + var handler = subject.factory({ + error: 420 + }); + assertStatus(handler, 420); + }); + }); + + describe("when an array is provided", function() { + it("should use a value from the array", function() { + var handler = subject.factory({ + error: [123] + }); + assertStatus(handler, 123); + }); + }); + + describe("when a regex is provided", function() { + it("should use a value that matches the regex", function() { + var handler = subject.factory({ + error: /^400/ + }); + assertStatus(handler, 400); + }); + }); + + describe("when nothing is provided", function() { + it("should use a valid error code", function() { + var handler = subject.factory(); + handler(null, { + status: function(code) { + assert(code >= 400); + assert(code <= 506); + assert(R.is(Number, code)); + }, + end: function() {} + }); + }); + }); +});