Skip to content
This repository was archived by the owner on Nov 19, 2023. It is now read-only.

Commit 1d9df94

Browse files
committed
feat: first commit
0 parents  commit 1d9df94

18 files changed

+254
-0
lines changed

.codeclimate.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
languages:
2+
JavaScript: true
3+
exclude_paths:
4+
- "examples/*.js"

.editorconfig

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true
10+
11+
[Makefile]
12+
charset = utf-8
13+
indent_style = tabs
14+
indent_size = 2
15+
end_of_line = lf
16+
trim_trailing_whitespace = true
17+
insert_final_newline = true
18+
19+
[*.sh]
20+
insert_final_newline = false

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
.DS_Store
3+
npm-debug.log
4+
test/.tmp
5+
*.nar

.npmignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test/fixtures
2+
*.nar

.travis.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
language: node_js
2+
node_js:
3+
- "0.12"
4+
- "iojs"
5+
- "iojs-v1.6.0"
6+

LICENSE

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
The MIT License
2+
3+
Copyright (c) Tomas Aparicio and contributors
4+
5+
Permission is hereby granted, free of charge, to any person
6+
obtaining a copy of this software and associated documentation
7+
files (the "Software"), to deal in the Software without
8+
restriction, including without limitation the rights to use,
9+
copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the
11+
Software is furnished to do so, subject to the following
12+
conditions:
13+
14+
The above copyright notice and this permission notice shall be
15+
included in all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24+
OTHER DEALINGS IN THE SOFTWARE.

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# toxify
2+
3+
Hackable HTTP proxy to simulate system failure conditions. Built for [node.js](http://nodejs.org)/[io.js](https://iojs.org)
4+
5+
**Work in progress**
6+
7+
## Built-in poisons
8+
9+
- [x] Delay
10+
- [_] Server error
11+
- [_] Close socket
12+
- [_] Bandwidth
13+
- [_] Throttle
14+
- [_] Debounce
15+
- [_] Rate limit
16+
- [_] Slow close
17+
- [_] Slicer
18+
19+
## License
20+
21+
MIT - Tomas Aparicio

bin/toxify

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env node
2+
3+
const toxify = require('..')
4+
5+
toxify({})

examples/server.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const toxify = require('..')
2+
3+
const proxy = toxify()
4+
5+
proxy.percentage(80)
6+
proxy.delay({ max: 1000, min: 100 })
7+
proxy.throttle(100)
8+
9+
proxy
10+
.forward('http://httpbin.org')
11+
.all('/*')
12+
13+
proxy.listen(8089)

index.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const Toxify = require('./lib/toxify')
2+
3+
module.exports = toxify
4+
5+
function toxify(opts) {
6+
return new Toxify(opts)
7+
}
8+
9+
toxify.poisons = require('./lib/poisons')
10+
toxify.VERSION = require('./package.json').version

lib/poisons/abort.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = function (filter) {
2+
return function (req, res, next) {
3+
req.socket.destroy()
4+
}
5+
}

lib/poisons/delay.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module.exports = function delay(opts, filter) {
2+
opts = opts || {}
3+
var max = +opts.max || 1000
4+
var min = +opts.min || 100
5+
6+
return function (req, res, next) {
7+
var defer = delay(req, next)
8+
9+
if (filter) {
10+
return filter(req, res, defer)
11+
}
12+
13+
defer()
14+
}
15+
16+
function delay(req, next) {
17+
return function (err, invalid) {
18+
if (err) return next(err)
19+
if (invalid) return next()
20+
21+
var timeout = setTimeout(next, calculateDelay())
22+
req.once('close', cleanTimeout)
23+
24+
function cleanTimeout() {
25+
clearTimeout(timeout)
26+
}
27+
28+
function clean() {
29+
req.removeEventListener('close', cleanTimeout)
30+
next()
31+
}
32+
}
33+
}
34+
35+
function calculateDelay() {
36+
if (opts.jitter) return opts.jitter
37+
return Math.random() * (max - min) + min
38+
}
39+
}

lib/poisons/error.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = function (opts, filter) {
2+
return function (req, res, next) {
3+
res.writeHead(+opts.code || 500, opts.headers)
4+
res.end()
5+
}
6+
}

lib/poisons/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
delay: require('./delay'),
3+
error: require('./error'),
4+
abort: require('./abort'),
5+
throttle: require('./throttle')
6+
}

lib/poisons/throttle.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const Throttle = require('throttle')
2+
3+
module.exports = function throttle(opts, filter) {
4+
return function (req, res, next) {
5+
res.pipe(new Throttle(opts))
6+
next()
7+
}
8+
}

lib/toxify.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const rocky = require('rocky')
2+
const Base = rocky.Base
3+
const Rocky = rocky.Rocky
4+
const poisons = require('./poisons')
5+
6+
module.exports = Toxify
7+
8+
function Toxify(opts) {
9+
Rocky.call(this, opts)
10+
}
11+
12+
Toxify.prototype = Object.create(Rocky.prototype)
13+
14+
Base.prototype.percentage = function (percent) {
15+
this.opts.percentage = Math.max(percent, 100)
16+
return this
17+
}
18+
19+
Base.prototype.usePoison = function (poison) {
20+
var percent = this.opts.percentage
21+
22+
if (!percent) {
23+
this.use(poison)
24+
return this
25+
}
26+
27+
this.use(function (req, res, next) {
28+
var rand = (Math.random() * 10) | 0
29+
var perc = (percent * 0.1) | 0
30+
if (rand > perc) return next()
31+
poison(req, res, next)
32+
})
33+
34+
return this
35+
}
36+
37+
Object.keys(poisons).forEach(function (poison) {
38+
var fn = poisons[poison]
39+
Base.prototype[fn.name || poison] = function () {
40+
this.usePoison(fn.apply(null, arguments))
41+
}
42+
})

package.json

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "toxify",
3+
"version": "0.1.0",
4+
"description": "Hackable HTTP proxy to simulate system failure conditions",
5+
"repository": "h2non/rocky",
6+
"author": "Tomas Aparicio",
7+
"license": "MIT",
8+
"keywords": [
9+
"http",
10+
"proxy",
11+
"toxic",
12+
"fault",
13+
"tolerant",
14+
"testing",
15+
"resilency",
16+
"fuzz",
17+
"evil",
18+
"testing"
19+
],
20+
"engines": {
21+
"node": ">= 0.12"
22+
},
23+
"scripts": {
24+
"test": "./node_modules/.bin/mocha --timeout 5000 --reporter spec --ui tdd test/*"
25+
},
26+
"dependencies": {
27+
"rocky": "^0.3.2",
28+
"throttle": "^1.0.3",
29+
"yargs": "^3.15.0"
30+
},
31+
"devDependencies": {
32+
"chai": "^3.0.0",
33+
"mocha": "^2.2.5",
34+
"request": "^2.58.0",
35+
"sinon": "^1.15.3",
36+
"supertest": "^1.0.1"
37+
}
38+
}

test/tofixy.js

Whitespace-only changes.

0 commit comments

Comments
 (0)