UNPKG

toxy

Version:

Hackable HTTP proxy to simulate server failure scenarios and network conditions

470 lines (406 loc) 12.5 kB
const toxy = require('../..') const expect = require('chai').expect const supertest = require('supertest') suite('http api', function () { var proxy = null const admin = toxy.admin() const ports = { proxy: 9898, admin: 9899 } const adminUrl = 'http://localhost:' + ports.admin admin.listen(ports.admin) function setup () { proxy = toxy() proxy .poison(function foo (req, res, next) { next() }) .poison(function bar (req, res, next) { next() }) .withRule(function bar (req, res, next) { next() }) proxy .rule(function foo (req, res, next) { next() }) .rule(function bar (req, res, next) { next() }) proxy .get('/foo') .rule(function foo (req, res, next) { next() }) .poison(function foo (req, res, next) { next() }) .withRule(function foo (req, res, next) { next() }) proxy .get('/bar') .rule(function bar (req, res, next) { next() }) .poison(function bar (req, res, next) { next() }) admin.manage(proxy) proxy.listen(ports.proxy) } function shutdown (done) { proxy.close(done) } test('root', function (done) { supertest(adminUrl) .get('/') .expect(200) .expect('Content-Type', 'application/json') .expect(function (res) { expect(res.body.version).to.be.equal(toxy.VERSION) expect(res.body.links).to.be.an('object') expect(res.body.links.self).to.be.deep.equal({ href: '/' }) expect(res.body.links.servers).to.be.deep.equal({ href: '/servers' }) }) .end(done) }) function assertServer (server) { expect(server.id).to.be.equal('bcc') expect(server.port).to.be.equal(ports.proxy) expect(server.totalPoisons).to.be.equal(2) expect(server.totalRules).to.be.equal(2) expect(server.totalRoutes).to.be.equal(2) expect(server.links).to.be.an('object') expect(server.links.self).to.be.deep.equal({ href: '/servers/' + server.id }) expect(server.links.routes).to.be.deep.equal({ href: '/servers/' + server.id + '/routes' }) expect(server.links.parent).to.be.deep.equal({ href: '/servers' }) } suite('servers', function () { test('setup', setup) test('get servers', function (done) { supertest(adminUrl) .get('/servers') .expect(200) .expect(function (res) { res.body.forEach(assertServer) }) .end(done) }) test('get server', function (done) { supertest(adminUrl) .get('/servers/bcc') .expect(200) .expect(function (res) { assertServer(res.body) expect(res.body.routes).to.have.length(2) }) .end(done) }) test('delete server', function (done) { supertest(adminUrl) .delete('/servers/bcc') .expect(204) .end(done) }) test('reset', shutdown) }) function assertDirective (directive, path) { expect(directive.name).to.be.a('string') expect(directive.enabled).to.be.true expect(directive.links).to.be.an('object') expect(directive.links.self).to.be.deep.equal({ href: path }) expect(directive.links.parent).to.be.deep.equal({ href: parentHref(path) }) } function assertPoison (poison, path) { assertDirective(poison, path) expect(poison.phase).to.be.equal('incoming') } suite('server poisons', function () { test('setup', setup) test('all', function (done) { const path = '/servers/bcc/poisons' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { expect(res.body).to.have.length(2) res.body.forEach(function (directive) { const name = directive.name + ':' + directive.phase assertPoison(directive, path + '/' + name) }) }) .end(done) }) test('delete by name', function (done) { const path = '/servers/bcc/poisons/foo:incoming' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('create', function (done) { const path = '/servers/bcc/poisons' supertest(adminUrl) .post(path) .send({ name: 'latency', options: { jitter: 1000 } }) .expect(201) .end(done) }) test('cannot create invalid poison', function (done) { const path = '/servers/bcc/poisons' supertest(adminUrl) .post(path) .send({ name: 'invalid' }) .expect(404) .end(done) }) test('get by name', function (done) { const path = '/servers/bcc/poisons/latency:incoming' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { assertPoison(res.body, path) }) .end(done) }) test('create outgoing', function (done) { const path = '/servers/bcc/poisons' supertest(adminUrl) .post(path) .send({ name: 'bandwidth', phase: 'outgoing', options: { jitter: 1000 } }) .expect(201) .end(done) }) test('get outgoing rule by name', function (done) { const path = '/servers/bcc/poisons/bandwidth:outgoing' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { assertDirective(res.body, path) expect(res.body.phase).to.be.equal('outgoing') }) .end(done) }) test('delete outgoing rule by name', function (done) { const path = '/servers/bcc/poisons/bandwidth:outgoing' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('delete all', function (done) { const path = '/servers/bcc/poisons' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('reset', shutdown) }) suite('server rules', function () { test('setup', setup) test('all', function (done) { const path = '/servers/bcc/rules' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { expect(res.body).to.have.length(2) assertDirective(res.body.shift(), path + '/foo') }) .end(done) }) test('delete by name', function (done) { const path = '/servers/bcc/rules/foo' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('create', function (done) { const path = '/servers/bcc/rules' supertest(adminUrl) .post(path) .send({ name: 'method', options: 'GET' }) .expect(201) .end(done) }) test('get by name', function (done) { const path = '/servers/bcc/rules/method' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { assertDirective(res.body, path) }) .end(done) }) test('reset', shutdown) }) function assertRoute (route, path) { expect(route.id).to.have.length(3) expect(route.path).to.be.a('string') expect(route.method).to.be.equal('GET') expect(route.links).to.be.an('object') expect(route.links.self).to.be.deep.equal({ href: '/servers/bcc/routes/' + route.id }) expect(route.links.poisons).to.be.deep.equal({ href: '/servers/bcc/routes/' + route.id + '/poisons' }) expect(route.links.rules).to.be.deep.equal({ href: '/servers/bcc/routes/' + route.id + '/rules' }) expect(route.links.parent).to.be.deep.equal({ href: '/servers/bcc/routes' }) } suite('routes', function () { test('setup', setup) test('all', function (done) { supertest(adminUrl) .get('/servers/bcc/routes') .expect(200) .expect(function (res) { expect(res.body).to.be.have.length(2) res.body.forEach(assertRoute) }) .end(done) }) test('delete by id', function (done) { supertest(adminUrl) .delete('/servers/bcc/routes/32f') .expect(204) .end(done) }) test('create', function (done) { supertest(adminUrl) .post('/servers/bcc/routes') .send({ path: '/foobar', method: 'GET', forward: 'http://localhost:8080' }) .expect(201) .end(done) }) test('get by id', function (done) { supertest(adminUrl) .get('/servers/bcc/routes/464') .expect(200) .expect(function (res) { expect(res.body.id).to.be.equal('464') assertRoute(res.body, '/foobar') }) .end(done) }) test('delete all', function (done) { supertest(adminUrl) .delete('/servers/bcc/routes') .expect(204) .end(done) }) test('check empty routes', function (done) { supertest(adminUrl) .get('/servers/bcc/routes') .expect(200) .expect([]) .end(done) }) test('reset', shutdown) }) suite('route poisons', function () { test('setup', setup) test('all', function (done) { const path = '/servers/bcc/routes/32f/poisons' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { expect(res.body).to.have.length(1) assertPoison(res.body.shift(), path + '/foo:incoming') }) .end(done) }) test('get by name', function (done) { const path = '/servers/bcc/routes/32f/poisons/foo:incoming' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { assertPoison(res.body, path) expect(res.body.rules).to.have.length(1) const nestedRule = res.body.rules.shift() assertDirective(nestedRule, path + '/rules/foo') }) .end(done) }) test('delete by name', function (done) { const path = '/servers/bcc/routes/32f/poisons/foo' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('delete all', function (done) { const path = '/servers/bcc/routes/32f/poisons' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('reset', shutdown) }) suite('route poison rules', function () { test('setup', setup) test('get all', function (done) { const path = '/servers/bcc/routes/32f/poisons/foo/rules' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { expect(res.body).to.have.length(1) assertDirective(res.body.shift(), path + '/foo') }) .end(done) }) test('get by name', function (done) { const path = '/servers/bcc/routes/32f/poisons/foo/rules/foo' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { assertDirective(res.body, path) }) .end(done) }) test('delete by name', function (done) { const path = '/servers/bcc/routes/32f/poisons/foo/rules/foo' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('delete all', function (done) { const path = '/servers/bcc/routes/32f/poisons/foo/rules' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('reset', shutdown) }) suite('route rules', function () { test('setup', setup) test('get all', function (done) { const path = '/servers/bcc/routes/32f/rules' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { expect(res.body).to.have.length(1) const rule = res.body[0] assertDirective(rule, path + '/foo') }) .end(done) }) test('get by name', function (done) { const path = '/servers/bcc/routes/32f/rules/foo' supertest(adminUrl) .get(path) .expect(200) .expect(function (res) { assertDirective(res.body, path) }) .end(done) }) test('delete by name', function (done) { const path = '/servers/bcc/routes/32f/rules/foo' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('delete all', function (done) { const path = '/servers/bcc/routes/32f/rules' supertest(adminUrl) .delete(path) .expect(204) .end(done) }) test('reset', shutdown) }) }) function parentHref (path) { return path.split('/').slice(0, -1).join('/') }