test(httpProxy): add tests for server/httpProxy

This commit is contained in:
Christopher Astfalk
2020-09-26 19:27:15 +02:00
parent ab5dbfcb27
commit aa1814cbe3
7 changed files with 175 additions and 12 deletions
+1 -1
View File
@@ -235,7 +235,7 @@ api.use((err, req, res, next) => {
const format = anError => ({
status: getStatus(anError),
title: anError.title || anError.name,
detail: anError.detail || anError.message
detail: anError.reason || anError.detail || anError.message
})
if (Array.isArray(err)) {
+34 -5
View File
@@ -9,12 +9,12 @@ module.exports = router
const proxy = httpProxy.createProxyServer({})
proxy.on('proxyReq', (proxyReq, req, res, options) => {
proxy.on('proxyReq', (proxyReq, _req, _res, _options) => {
// Remove the internal session id
proxyReq.setHeader('x-andromeda-session-id', '')
proxyReq.removeHeader('x-andromeda-session-id')
})
proxy.on('error', (err, req, res) => {
proxy.on('error', (err, _req, res) => {
res.statusCode = 500
res.setHeader('content-type', 'application/json')
res.write(JSON.stringify({
@@ -45,13 +45,42 @@ router.all('/:protocol/:hostname/:path(*$)', validateSession, (req, res) => {
})
})
// Error handler
// This transforms the different error styles into application/vnd.api+json errors.
router.use((err, _req, res, next) => {
if (!err) {
next()
return
}
res.type('application/vnd.api+json')
const getStatus = anError => Number(anError.status || anError.statusCode) || 500
const format = anError => ({
status: getStatus(anError),
title: anError.title || anError.name,
detail: anError.reason || anError.detail || anError.message
})
if (Array.isArray(err)) {
res.status(getStatus(err[0]))
res.json({
errors: err.map(format)
})
} else {
res.status(getStatus(err))
res.json({
errors: [format(err)]
})
}
})
/**
* Validate if the request is made by a logged in user.
* @param {express.Request} req Express Request Object.
* @param {express.Response} res Express Response Object.
* @param {express.Response} _res Express Response Object.
* @param {express.NextFunction} next Call next middleware.
*/
function validateSession (req, res, next) {
function validateSession (req, _res, next) {
try {
const sessionId = req.headers['x-andromeda-session-id']
const checkSession = req.app.get('checkSession')
+2 -1
View File
@@ -33,4 +33,5 @@ const server = app.listen(port, () => {
webSocketBridge.createWebSocketServer(app, server, '/api/bridge')
module.exports = server
exports.app = app
exports.server = server
+1 -1
View File
@@ -263,7 +263,7 @@ function sendError (res, error) {
errors: [{
status: error.status || error.statusCode || 500,
title: error.title || error.name,
detail: error.detail || error.message
detail: error.reason || error.detail || error.message
}]
})
}
+4 -3
View File
@@ -33,7 +33,7 @@ describe('account', function () {
usersDbCreateIndex.resolves()
server = proxyquire('../server/index', {
const backend = proxyquire('../server/index', {
'./db': {
'@global': true,
usersDB: {
@@ -52,6 +52,7 @@ describe('account', function () {
},
'node-fetch': fetch
})
server = backend.server
})
afterEach('close server', function (done) {
@@ -220,7 +221,7 @@ describe('account', function () {
{
status: 409,
title: 'conflict',
detail: 'Document update conflict'
detail: 'An account with that id already exists'
}
]
}, done)
@@ -294,7 +295,7 @@ describe('account', function () {
{
status: 409,
title: 'conflict',
detail: 'Document update conflict'
detail: 'An account with that username already exists'
}
]
}, done)
+131
View File
@@ -0,0 +1,131 @@
const assert = require('assert')
const express = require('express')
const proxyquire = require('proxyquire')
const sinon = require('sinon')
const request = require('supertest')
const uuid = require('uuid')
describe('httpProxy', function () {
let testServer
let testServerPort
let clock
let server // express server
let app // express app
beforeEach(function (done) {
const testApp = express()
testApp.use((req, res) => {
for (const [key, value] of Object.entries(req.headers)) {
res.setHeader(key, value)
}
res.setHeader('x-request-method', req.method)
res.send({ something: 'Hello World!' })
})
testServer = testApp.listen(() => {
testServerPort = testServer.address().port
done()
})
})
beforeEach(function () {
clock = sinon.useFakeTimers(Date.now())
})
beforeEach(function () {
const backend = proxyquire('../server/index', {})
app = backend.app
server = backend.server
})
afterEach('close server', function (done) {
server.close(done)
})
afterEach('restore timers', function () {
clock.restore()
})
afterEach('close test target server', function (done) {
testServer.close(done)
})
it('should fail if the user in not logged in', function (done) {
request(server)
.get(`/api/proxy/http/127.0.0.1:${testServerPort}/`)
.expect('Content-Type', 'application/vnd.api+json; charset=utf-8')
.expect(403, {
errors: [
{
status: 403,
title: 'forbidden',
detail: '"x-andromeda-session-id" is wrong'
}
]
}, done)
})
it('should proxy the requests to the passed address', function (done) {
const id = uuid.v4()
app.get('gridSessions').set(id, 'active')
request(server)
.get(`/api/proxy/http/127.0.0.1:${testServerPort}/somePath`)
.set('x-andromeda-session-id', id)
.expect('x-request-method', 'GET')
.expect(res => {
assert.strictEqual(res.headers['x-andromeda-session-id'], undefined)
})
.expect(200, { something: 'Hello World!' }, done)
})
it('should proxy the request the the passed path-less address', function (done) {
const id = uuid.v4()
app.get('gridSessions').set(id, 'active')
request(server)
.get(`/api/proxy/http/127.0.0.1:${testServerPort}/`)
.set('x-andromeda-session-id', id)
.expect('x-request-method', 'GET')
.expect(res => {
assert.strictEqual(res.headers['x-andromeda-session-id'], undefined)
})
.expect(200, { something: 'Hello World!' }, done)
})
describe('methods', function () {
for (const method of ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'TRACE', 'PATCH']) {
it(`should handle ${method} requests`, function (done) {
const id = uuid.v4()
app.get('gridSessions').set(id, 'active')
let req = request(server)
[method.toLowerCase()](`/api/proxy/http/127.0.0.1:${testServerPort}/`)
.set('x-andromeda-session-id', id)
// Methods with body
if (['POST', 'PUT', 'PATCH'].includes(method)) {
req.send({ data: 'moar' })
.expect('x-request-method', method)
.expect(res => {
assert.strictEqual(res.headers['x-andromeda-session-id'], undefined)
})
.expect(200, { something: 'Hello World!' }, done)
} else {
req
.expect('x-request-method', method)
.expect(res => {
assert.strictEqual(res.headers['x-andromeda-session-id'], undefined)
})
.expect(
200,
method === 'HEAD'
? {}
: { something: 'Hello World!' },
done
)
}
})
}
})
})
+2 -1
View File
@@ -27,7 +27,7 @@ describe('login', function () {
usersDbCreateIndex.resolves()
server = proxyquire('../server/index', {
const backend = proxyquire('../server/index', {
'./db': {
'@global': true,
usersDB: {
@@ -43,6 +43,7 @@ describe('login', function () {
},
'node-fetch': fetch
})
server = backend.server
})
afterEach('close server', function (done) {