test/http.js
const fs = require('fs')
const http = require('http')
const crypto = require('crypto')
const connect = require('connect')
const sinon = require('sinon')
const request = require('request')
const supertest = require('supertest')
const expect = require('chai').expect
const rocky = require('..')
const ports = { target: 9890, proxy: 9891, replay: 9892 }
const baseUrl = 'http://127.0.0.1'
const proxyUrl = baseUrl + ':' + ports.proxy
const targetUrl = baseUrl + ':' + ports.target
const replayUrl = baseUrl + ':' + ports.replay
suite('http', function () {
var proxy, replay, server
beforeEach(function () {
proxy = replay = server = null
})
afterEach(function (done) {
if (replay) replay.close()
if (server) server.close()
if (proxy && proxy.server) {
proxy.server.close()
}
setTimeout(done, 20)
})
test('simple forward', function (done) {
proxy = rocky()
.forward(targetUrl)
.listen(ports.proxy)
server = createTestServer(assert)
proxy.get('/test')
http.get(proxyUrl + '/test', noop)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
done()
}
})
test('forward and replay', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy.get('/test')
replay = createReplayServer(assertReplay)
server = createTestServer(assert)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
}
})
test('forward and replay to multiple backends', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.replay(replayUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy.get('/test')
replay = createReplayServer(assertReplay)
server = createTestServer(assert)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(noop)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
}
var asserts = 0
function assertReplay (req, res) {
asserts++
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
if (asserts > 2) done()
}
})
test('forward and replay with payload', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.bufferBody()
.listen(ports.proxy)
proxy.post('/test')
replay = createReplayServer(assertReplay)
server = createTestServer(assert)
supertest(proxyUrl)
.post('/test')
.send({ hello: 'world' })
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(noop)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(req.body).to.be.equal('{"hello":"world"}')
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
expect(req.body).to.be.equal('{"hello":"world"}')
done()
}
})
test('forward and replay large payload', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy.post('/test')
replay = createReplayServer(assertReplay)
server = createTestServer(assert)
var replays = 0
var body = fs.readFileSync('test/fixtures/data.json').toString()
supertest(proxyUrl)
.post('/test')
.type('text/plain')
.send(body)
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(noop)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(req.body).to.be.equal(body)
}
function assertReplay (req, res) {
replays += 1
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
expect(req.body).to.be.equal(body)
if (replays === 2) done()
}
})
test('forward and replay large payload as stream', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy.post('/test')
replay = createReplayServer(assertReplay)
server = createTestServer(assert)
var body = fs.readFileSync('test/fixtures/data.json').toString()
fs.createReadStream('test/fixtures/data.json')
.pipe(request.post(proxyUrl + '/test'))
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(req.body).to.be.equal(body)
}
var replays = 0
function assertReplay (req, res) {
replays += 1
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
expect(req.body).to.be.equal(body)
if (replays > 1) done()
}
})
// Temporary disabled due to stream incompatibilities with latest node versions
test.skip('proxy forward with retry', function (done) {
var v = process.version.slice(1)
if (+v.charAt(0) === 5 && +v.charAt(2) >= 6) return done()
var spy = sinon.spy()
proxy = rocky()
.forward('http://foobar')
.options({ timeout: 100 })
.retry({
retries: 3,
factor: 1,
minTimeout: 150,
maxTimeout: 500,
randomize: true
})
.on('proxy:retry', spy)
.listen(ports.proxy)
proxy.get('/test')
supertest(proxyUrl)
.get('/test')
.expect(502)
.expect('Content-Type', 'application/json')
.end(assert)
function assert (err, res) {
expect(err).to.be.null
expect(res.statusCode).to.be.equal(502)
expect(spy.args.length).to.be.equal(3)
done()
}
})
// Temporary disabled due to stream incompatibilities with latest node versions
test.skip('proxy replay with retry', function (done) {
var spy = sinon.spy()
server = createTestServer()
proxy = rocky()
.forward(targetUrl)
.replay('http://127.0.0.1:9999')
.retry({
retries: 3,
factor: 2,
minTimeout: 100,
maxTimeout: 30 * 1000,
randomize: true
})
.on('replay:retry', assert)
.listen(ports.proxy)
proxy.all('/test')
supertest(proxyUrl)
.post('/test')
.send({ hello: 'world' })
.expect(200)
.expect('Content-Type', 'application/json')
.end(noop)
var calls = 0
function assert (err, res) {
spy(err, res); calls += 1
if (calls < 3) return
expect(err.code).to.be.equal('ECONNREFUSED')
expect(spy.args.length).to.be.equal(3)
done()
}
})
test('global middleware', function (done) {
proxy = rocky().forward(targetUrl)
server = createTestServer(assert)
var spy = sinon.spy()
proxy.use(function (req, res, next) {
spy(req, res)
next()
})
var routespy = sinon.spy()
proxy.get('/test')
.use(function (req, res, next) {
routespy(req, res)
next()
})
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(spy.calledOnce).to.be.true
expect(routespy.calledOnce).to.be.true
expect(spy.args[0][0].rocky).to.be.an('object')
expect(spy.args[0][0].rocky.options).to.be.an('object')
expect(spy.args[0][0].rocky.proxy).to.be.an('object')
expect(spy.args[0][0].rocky.route).to.be.an('object')
}
})
test('forward middleware', function (done) {
var spy = sinon.spy()
proxy = rocky().forward(targetUrl)
server = createTestServer(assert)
proxy.useForward(middlewareFn)
proxy.get('/test')
.useForward(middlewareFn)
function middlewareFn (req, res, next) {
spy(req, res)
next()
}
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(spy.calledTwice).to.be.true
expect(spy.args[0][0].rocky).to.be.an('object')
expect(spy.args[0][0].rocky.options).to.be.an('object')
expect(spy.args[0][0].rocky.proxy).to.be.an('object')
expect(spy.args[0][0].rocky.route).to.be.an('object')
}
})
test('replay middleware', function (done) {
proxy = rocky().forward(targetUrl)
server = createTestServer()
replay = createReplayServer(assert)
var spy = sinon.spy()
proxy.replay(replayUrl)
proxy.useReplay(middlewareFn)
proxy.get('/test')
.useReplay(middlewareFn)
function middlewareFn (req, res, next) {
spy(req, res)
next()
}
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
expect(spy.calledTwice).to.be.true
expect(spy.args[0][0].rocky).to.be.an('object')
expect(spy.args[0][0].rocky.options).to.be.an('object')
expect(spy.args[0][0].rocky.proxy).to.be.an('object')
expect(spy.args[0][0].rocky.route).to.be.an('object')
}
})
test('param middleware', function (done) {
var spy = sinon.spy()
proxy = rocky().forward(targetUrl)
server = createTestServer(assert)
proxy.useParam('id', middlewareFn)
proxy.get('/:id')
function middlewareFn (req, res, next) {
spy(req, res)
next()
}
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/1')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/1')
expect(res.statusCode).to.be.equal(200)
expect(spy.calledOnce).to.be.true
}
})
test('response middleware', function (done) {
proxy = rocky().forward(targetUrl)
server = createTestServer()
proxy.get('/test')
.useResponse(middlewareFn)
function middlewareFn (req, res, next) {
res.setHeader('x-custom', '1.0')
res.removeHeader('content-type')
assert(req, res)
next()
}
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('{"hello":"world"}')
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.getHeader('x-custom')).to.be.equal('1.0')
expect(res.getHeader('content-type')).to.not.exist
expect(res.statusCode).to.be.equal(200)
expect(res.body.toString()).to.be.equal('{"hello":"world"}')
}
})
test('overwrite forward options via middleware', function (done) {
var spy = sinon.spy()
proxy = rocky().forward('http://invalid')
server = createTestServer(assert)
proxy.get('/test')
.use(middlewareFn)
function middlewareFn (req, res, next) {
spy(req, res)
req.rocky.options.target = targetUrl
next()
}
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(spy.calledOnce).to.be.true
}
})
test('overwrite replay options via middleware', function (done) {
var spy = sinon.spy()
proxy = rocky()
.forward(targetUrl)
.replay('http://invalid')
.on('replay:start', spy)
.on('replay:error', spy)
server = createTestServer()
replay = createReplayServer(assert)
proxy.get('/test')
.useReplay(middlewareFn)
function middlewareFn (req, res, next) {
spy(req, res)
req.rocky.options.target = replayUrl
next()
}
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(function (err) {
setTimeout(function () {
expect(spy.calledThrice).to.be.true
done(err)
}, 10)
})
function assert (req, res) {
spy(req, res)
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
expect(spy.args[0][0].url).to.be.equal('/test')
expect(spy.args[0][0].rocky.options.target).to.be.deep.equal(replayUrl)
}
})
test('forward events', function (done) {
var spy = sinon.spy()
server = createTestServer(assert)
replay = createReplayServer(assertReplay)
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.on('proxyRes', spy)
.on('proxyReq', spy)
.on('replay:start', spy)
.on('replay:error', spy)
.on('route:error', spy)
.on('error', spy)
proxy.get('/test')
.on('proxyRes', spy)
.on('proxyReq', spy)
.on('replay:start', spy)
.on('replay:error', spy)
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(end)
function end (err) {
expect(err).to.be.null
expect(spy.args.length).to.be.equal(6)
done()
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
}
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
}
})
test('body buffer forwaring original body', function (done) {
proxy = rocky()
.forward(targetUrl, { forwardOriginalBody: true })
.replay(replayUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy
.post('/payload')
.bufferBody()
.transformRequestBody(function (req, res, next) {
var body = JSON.parse(req.body.toString())
var newBody = JSON.stringify({ salutation: 'hello ' + body.hello })
next(null, newBody)
})
server = createTestServer(assert)
replay = createReplayServer(assertReplay)
supertest(proxyUrl)
.post('/payload')
.send({ hello: 'world' })
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ salutation: 'hello world' })
.end(noop)
function assert (req, res) {
expect(req.url).to.be.equal('/payload')
expect(req.body).to.be.equal('{"hello":"world"}')
expect(res.statusCode).to.be.equal(200)
}
var calls = 0
function assertReplay (req, res) {
calls++
expect(req.url).to.be.equal('/payload')
expect(req.body).to.be.equal('{"salutation":"hello world"}')
expect(res.statusCode).to.be.equal(204)
if (calls === 2) done()
}
})
test('intercept and transform response payload', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy
.post('/payload')
.transformResponseBody(function (req, res, next) {
var body = JSON.parse(res.body.toString())
var newBody = JSON.stringify({ salutation: 'hello ' + body.hello })
next(null, newBody)
})
replay = createReplayServer(assert)
server = createTestServer(assert)
supertest(proxyUrl)
.post('/payload')
.type('application/json')
.send('{"hello": "world"}')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ salutation: 'hello world' })
.end(function (err) {
if (err) done(err)
})
var calls = 0
function assert (req, res) {
calls++
expect(req.url).to.be.equal('/payload')
expect(res.statusCode).to.match(/200|204/)
if (calls > 2) done()
}
})
test('intercept and transform request payload', function (done) {
proxy = rocky()
.forward(targetUrl)
.replay({ target: replayUrl, replayOriginalBody: true })
.replay({ target: replayUrl, replayOriginalBody: true })
.listen(ports.proxy)
proxy
.post('/payload')
.transformRequestBody(function (req, res, next) {
var body = JSON.parse(req.body.toString())
var newBody = JSON.stringify({ salutation: 'hello ' + body.hello })
next(null, newBody)
})
replay = createReplayServer(assertReplay)
server = createTestServer(assert)
supertest(proxyUrl)
.post('/payload')
.type('application/json')
.send('{"hello":"world"}')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({'hello': 'world'})
.end(end)
function end (err) {
setTimeout(function () { done(err) }, 50)
}
function assert (req, res) {
expect(req.url).to.be.equal('/payload')
expect(res.statusCode).to.be.equal(200)
expect(req.body).to.be.equal('{"salutation":"hello world"}')
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/payload')
expect(res.statusCode).to.be.equal(204)
expect(req.body).to.be.equal('{"hello":"world"}')
}
})
test('route', function (done) {
var spy = sinon.spy()
proxy = rocky()
server = createTestServer(assert)
replay = createReplayServer(assertReplay)
proxy.get('/test')
.forward(targetUrl)
.replay(replayUrl)
.options({ hostRewrite: true })
.on('proxyReq', spy)
.on('replay:start', spy)
.on('error', spy)
.use(function (req, res, next) {
req.headers['X-Test'] = 'rocky'
next()
})
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(end)
function end () {
expect(spy.calledTwice).to.be.true
done()
}
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
expect(req.headers['x-test']).to.be.equal('rocky')
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
expect(req.headers['x-test']).to.be.equal('rocky')
}
})
test('missing target', function (done) {
var spy = sinon.spy()
proxy = rocky()
proxy.get('/test')
.on('error', spy)
.on('proxyReq', spy)
.on('route:error', spy)
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(502)
.expect('Content-Type', 'application/json')
.end(assert)
function assert (err, res) {
var errorMsg = /missing target URL/i
expect(err).to.be.null
expect(spy.calledTwice).to.be.true
expect(res.statusCode).to.be.equal(502)
expect(spy.args[0][0].message).to.match(errorMsg)
expect(spy.args[0][1].url).to.be.equal('/test')
expect(res.body.message).to.match(errorMsg)
done()
}
})
test('missing route', function (done) {
var spy = sinon.spy()
proxy = rocky()
proxy
.on('route:missing', spy)
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(end)
function end (err, res) {
expect(err).to.not.be.null
expect(spy.calledOnce).to.be.true
expect(res.statusCode).to.be.equal(502)
expect(res.body.message).to.match(/^Route not configured/i)
done()
}
})
test('replay after forward', function (done) {
var spy = sinon.spy()
proxy = rocky()
server = createTestServer(spy, 100)
replay = createReplayServer(assertReplay)
proxy.options({ replayAfterForward: true })
proxy.get('/test')
.forward(targetUrl)
.replay(replayUrl)
proxy.listen(ports.proxy)
var start = Date.now()
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(function (err) {
if (err) done(err)
})
function assertReplay () {
expect(spy.calledOnce).to.be.true
expect((Date.now() - start) >= 100).to.be.true
done()
}
})
test.skip('replay after forward with large payload', function (done) {
var spy = sinon.spy()
proxy = rocky()
server = createTestServer(assertForward, 100)
replay = createReplayServer(assertReplay, 10)
proxy.post('/test')
.replayAfterForward()
.forward(targetUrl)
.replay(replayUrl)
proxy.listen(ports.proxy)
var start = Date.now()
var body = longString(10 * 1024)
supertest(proxyUrl)
.post('/test')
.send(body)
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(function (err, res) {
if (err) done(err)
})
function assertForward (req, res) {
expect(req.body).to.be.equal(body)
spy()
done()
}
function assertReplay (req, res) {
expect(spy.calledOnce).to.be.true
expect(req.body).to.be.equal(body)
expect((Date.now() - start) >= 100).to.be.true
done()
}
})
test('sequential replay', function (done) {
var spy = sinon.spy()
var spyReplay = sinon.spy()
proxy = rocky()
server = createTestServer(spy, 100)
replay = createReplayServer(assertReplay, 100)
proxy.post('/test')
.replayAfterForward()
.replaySequentially()
.forward(targetUrl)
.replay(replayUrl)
.replay(replayUrl)
.replay(replayUrl)
proxy.listen(ports.proxy)
var start = Date.now()
var startReplay = Date.now()
var body = longString(1024 * 1024)
supertest(proxyUrl)
.post('/test')
.send(body)
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(function (err) {
if (err) done(err)
})
function assertReplay (req, res) {
spyReplay(req, res)
expect(spy.calledOnce).to.be.true
expect(req.body).to.be.equal(body)
expect((Date.now() - start) >= 100).to.be.true
if (spyReplay.calledThrice) {
expect((Date.now() - startReplay) >= 175).to.be.true
done()
}
}
})
test('do not replay if forward fails', function (done) {
var spy = sinon.spy()
proxy = rocky()
replay = createReplayServer(spy)
proxy.options({ replayAfterForward: true })
proxy
.get('/test')
.forward('http://invalid')
.replay(replayUrl)
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(502)
.expect('Content-Type', 'application/json')
.end(function (err) {
setTimeout(function () {
expect(spy.calledOnce).to.be.false
done(err)
}, 50)
})
})
test('unavailable forward server', function (done) {
var spy = sinon.spy()
proxy = rocky()
proxy.get('/test')
.forward('http://invalid.server')
.on('proxyReq', spy)
.on('proxy:error', spy)
proxy.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(502)
.expect('Content-Type', 'application/json')
.expect(/ENOTFOUND/)
.end(end)
function end (err, res) {
expect(err).to.be.null
expect(spy.calledTwice).to.be.true
expect(spy.args[1][0].message).to.match(/ENOTFOUND/)
done()
}
})
test('replay without forwarding', function (done) {
var spy = sinon.spy()
replay = createReplayServer(assertReplay)
proxy = rocky()
.replay(replayUrl)
.listen(ports.proxy)
proxy.get('/test')
.on('proxyReq', spy)
.on('route:error', spy)
supertest(proxyUrl)
.get('/test')
.expect(502)
.expect('Content-Type', 'application/json')
.expect(/Cannot forward/i)
.end(end)
function end (err, res) {
expect(err).to.be.null
expect(spy.calledTwice).to.be.true
expect(spy.args[0][0].message).to.match(/Target URL/i)
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
done()
}
})
test('streaming data', function (done) {
var spy = sinon.spy()
var endSpy = sinon.spy()
var assert = assertData()
var assertReplay = assertData()
server = createStreamingServer(ports.target, assert, assertEnd)
replay = createStreamingServer(ports.replay, assertReplay, assertEndReplay)
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy.all('/*')
.on('proxyReq', spy)
.on('replay:start', spy)
var opts = { method: 'POST', host: '127.0.0.1', port: ports.proxy }
var req = http.request(opts, function (res) {
res.setEncoding('utf8')
res.on('data', assertData())
res.on('end', end)
})
req.on('error', done)
// Write body asynchronously
setTimeout(function () {
req.write('foo')
}, 100)
setTimeout(function () {
req.write('bar')
}, 200)
setTimeout(function () {
req.write('far')
}, 300)
setTimeout(function () {
req.end()
}, 400)
function assertData () {
var count = 0
spy()
return function (data) {
var e = expect(data)
switch (count) {
case 0: e.to.be.equal('foo')
break
case 1: e.to.be.equal('foobar')
break
case 2: e.to.be.equal('foobarfar')
break
}
count += 1
}
}
function end () {
endSpy()
if (endSpy.args.length === 3) return done()
}
function assertEnd (req, res) {
expect(req.body).to.be.equal('foobarfar')
end()
}
function assertEndReplay (req, res) {
expect(req.body).to.be.equal('foobarfar')
end()
}
function createStreamingServer (port, onData, onEnd) {
var server = http.createServer(function (req, res) {
process.nextTick(handler)
function handler () {
req.setEncoding('utf8')
res.writeHead(200, { 'Content-Type': 'text/plain' })
var body = ''
req.on('data', function (data) {
body += data
onData(body, req, res)
setTimeout(function () {
res.write(body)
}, 10)
})
req.on('end', function () {
req.body = body
end()
})
}
function end () {
onEnd(req, res)
res.end()
}
})
server.listen(port)
return server
}
})
test('next route', function (done) {
var spy = sinon.spy()
replay = createTestServer(assert)
proxy = rocky()
.forward(targetUrl)
.listen(ports.proxy)
proxy.get('/test')
.use(function (req, res, next) {
next('route')
})
proxy.get('/*')
.on('proxyReq', spy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.end(end)
function end (err, res) {
expect(err).to.be.null
}
function assert (req, res) {
expect(spy.calledOnce).to.be.true
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
done()
}
})
test('unregister route', function (done) {
var spy = sinon.spy()
replay = createTestServer(assert)
proxy = rocky()
.forward(targetUrl)
.listen(ports.proxy)
proxy.get('/test')
.use(function (req, res, next) {
throw new Error('Noo!')
})
.unregister()
proxy.get('/*')
.on('proxyReq', spy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.end(end)
function end (err, res) {
expect(err).to.be.null
}
function assert (req, res) {
expect(spy.calledOnce).to.be.true
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
done()
}
})
test('timeout', function (done) {
var spy = sinon.spy()
var serverSpy = sinon.spy()
replay = createReplayServer(assertReplay)
server = createTimeoutServer()
proxy = rocky()
.forward(targetUrl)
.replay(replayUrl)
.listen(ports.proxy)
proxy.get('/test')
.options({ timeout: 50 })
.on('proxyReq', spy)
.on('proxy:error', spy)
supertest(proxyUrl)
.get('/test')
.end(end)
function end (err, res) {
expect(err).to.not.be.null
expect(spy.calledOnce).to.be.true
expect(serverSpy.calledOnce).to.be.true
expect(err.code).to.be.equal('ECONNRESET')
done()
}
function assertReplay (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(204)
serverSpy()
}
})
test('balancer', function (done) {
var spy1 = sinon.spy()
var spy2 = sinon.spy()
var spy3 = sinon.spy()
createServer(9893, 200, spy1)
createServer(9894, 201, spy2)
createServer(9895, 202, spy3)
proxy = rocky()
proxy
.get('/test')
.balance([
'http://localhost:9893',
'http://localhost:9894',
'http://localhost:9895'
])
proxy.listen(ports.proxy)
var count = 0
request()
function request () {
count += 1
supertest(proxyUrl)
.get('/test')
.expect(200 + count)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(count === 3 ? assert : request)
}
function assert () {
expect(spy1.calledOnce).to.be.true
expect(spy2.calledOnce).to.be.true
expect(spy3.calledOnce).to.be.true
done()
}
})
test('connect middleware', function (done) {
proxy = rocky().forward(targetUrl)
server = createTestServer(assert)
proxy.get('/test')
connect()
.use(proxy.middleware())
.listen(ports.proxy)
supertest(proxyUrl)
.get('/test')
.expect(200)
.expect('Content-Type', 'application/json')
.expect({ 'hello': 'world' })
.end(done)
function assert (req, res) {
expect(req.url).to.be.equal('/test')
expect(res.statusCode).to.be.equal(200)
}
})
})
function createTestServer (assert, timeout) {
return createServer(ports.target, 200, assert, timeout)
}
function createReplayServer (assert, timeout) {
return createServer(ports.replay, 204, assert, timeout)
}
function createTimeoutServer (assert) {
return createServer(ports.target, 503, assert, 30 * 1000)
}
function createServer (port, code, assert, timeout) {
var server = http.createServer(function (req, res) {
setTimeout(handler, +timeout || 1)
function handler () {
res.writeHead(code, { 'Content-Type': 'application/json' })
res.write(JSON.stringify({ 'hello': 'world' }))
var body = ''
req.on('data', function (data) {
body += data
})
req.on('end', function () {
req.body = body
end()
})
}
function end () {
if (assert) assert(req, res)
res.end()
}
})
server.listen(port)
return server
}
function longString (x) {
return JSON.stringify(crypto.randomBytes(+x || 1024 * 1024))
}
function noop () {}