openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
317 lines (268 loc) • 9.96 kB
JavaScript
/* eslint-env mocha */
import request from 'supertest'
import { ChannelModelAPI } from '../../src/model/channels'
import { ClientModelAPI } from '../../src/model/clients'
import { EventModel } from '../../src/model'
import * as testUtils from '../utils'
import * as server from '../../src/server'
import { config } from '../../src/config'
import { promisify } from 'util'
import * as constants from '../constants'
import sinon from 'sinon'
import {ObjectId} from 'mongodb'
config.authentication = config.get('authentication')
config.tlsClientLookup = config.get('tlsClientLookup')
const { SERVER_PORTS } = constants
const { HTTP_BASE_URL: baseUrl } = constants
describe('Events API Integration Tests', () => {
let mockServer = null
let mockServer2 = null
let mockServer3 = null
const mediatorPortPlus40 = constants.PORT_START + 40
const mediatorPortPlus41 = constants.PORT_START + 41
const mediatorPortPlus42 = constants.PORT_START + 42
let authDetails = {}
let slowSpy
let sandbox
const channelName = 'TEST DATA - Mock endpoint'
const primaryRouteName = 'test route'
const secRouteName = 'Test secondary route'
const mockResponse = {
'x-mediator-urn': 'urn:mediator:test',
status: 'Successful',
response: {
status: 200,
body: 'test for events',
timestamp: new Date()
}
}
before(async () => {
config.authentication.enableMutualTLSAuthentication = false
config.authentication.enableBasicAuthentication = true
// Setup some test data
await new ChannelModelAPI({
name: channelName,
urlPattern: 'test/mock',
allow: ['PoC'],
routes: [
{
name: primaryRouteName,
host: 'localhost',
port: mediatorPortPlus40,
primary: true
}, {
name: secRouteName,
host: 'localhost',
port: mediatorPortPlus41
}
],
rewriteUrls: true,
updatedBy: {
id: new ObjectId(),
name: 'Test'
}
}).save()
await new ChannelModelAPI({
name: `${channelName}-slow`,
urlPattern: 'test/slow',
allow: ['PoC'],
routes: [
{
name: primaryRouteName,
host: 'localhost',
port: mediatorPortPlus40,
primary: true
}, {
name: secRouteName,
host: 'localhost',
port: mediatorPortPlus42
}
],
updatedBy: {
id: new ObjectId(),
name: 'Test'
}
}).save()
const testAppDoc = {
clientID: 'testApp',
clientDomain: 'test-client.jembi.org',
name: 'TEST Client',
roles: [
'OpenMRS_PoC',
'PoC'
],
passwordAlgorithm: 'sha512',
passwordHash: '28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea',
passwordSalt: '1234567890',
cert: ''
}
await new ClientModelAPI(testAppDoc).save()
await testUtils.setupTestUsers()
// Create mock endpoint to forward requests to
mockServer = await testUtils.createMockHttpMediator(mockResponse, mediatorPortPlus40, 200)
mockServer2 = await testUtils.createMockHttpMediator(mockResponse, mediatorPortPlus41, 200)
sandbox = sinon.createSandbox()
slowSpy = sandbox.spy(async () => {
await testUtils.wait(200)
return mockResponse
})
mockServer3 = await testUtils.createMockHttpMediator(slowSpy, mediatorPortPlus42, 200)
// slow server
})
after(async () => {
sandbox.restore()
await Promise.all([
ChannelModelAPI.deleteOne({ name: 'TEST DATA - Mock endpoint' }),
ClientModelAPI.deleteOne({ clientID: 'testApp' }),
testUtils.cleanupTestUsers(),
mockServer.close(),
mockServer2.close(),
mockServer3.close()
])
})
beforeEach(async () => {
await promisify(server.start)({ httpPort: SERVER_PORTS.httpPort, apiPort: SERVER_PORTS.apiPort })
authDetails = await testUtils.getAuthDetails()
await EventModel.deleteMany({})
})
afterEach(async () => {
sandbox.reset()
await promisify(server.stop)()
})
it('should create events', async () => {
const startTime = await new Date()
await request(baseUrl)
.get('/test/mock')
.auth('testApp', 'password')
.expect(200)
const res = await request(constants.BASE_URL)
.get(`/events/${+startTime}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
res.body.should.have.property('events')
res.body.events.length.should.be.exactly(6)
// TODO : double check what this is supposed to be checking against
// for (const ev of Array.from(res.body)) {
// ev.channelID.should.be.exactly(channel1._id);
// }
const events = await (res.body.events.map(event => `${event.type}-${event.name}-${event.event}`))
events.should.containEql(`channel-${channelName}-start`)
events.should.containEql(`channel-${channelName}-end`)
events.should.containEql(`primary-${primaryRouteName}-start`)
events.should.containEql(`primary-${primaryRouteName}-end`)
events.should.containEql(`route-${secRouteName}-start`)
events.should.containEql(`route-${secRouteName}-end`)
})
it('should sort events according to \'normalizedTimestamp\' field ascending', async () => {
const startTime = new Date()
await request(baseUrl)
.get('/test/mock')
.auth('testApp', 'password')
.expect(200)
const res = await request(constants.BASE_URL)
.get(`/events/${+startTime}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
res.body.should.have.property('events')
res.body.events.length.should.be.exactly(6)
const timestampArray = await res.body.events.map(event => event.normalizedTimestamp)
for (let i = 0; i < timestampArray.length - 1; i++) {
(timestampArray[i] <= timestampArray[i + 1]).should.be.true()
}
})
it('should set the event status as a string', async () => {
const startTime = await new Date()
await request(baseUrl)
.get('/test/mock')
.auth('testApp', 'password')
.expect(200)
const res = await request(constants.BASE_URL)
.get(`/events/${+startTime}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
res.body.should.have.property('events')
res.body.events.length.should.be.exactly(6)
const events = await (res.body.events.map(event => event.statusType))
events.should.containEql('success')
})
it('should add mediator info', async () => {
const startTime = await new Date()
await request(baseUrl)
.get('/test/mock')
.auth('testApp', 'password')
.expect(200)
const res = await request(constants.BASE_URL)
.get(`/events/${+startTime}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
res.body.should.have.property('events')
res.body.events.length.should.be.exactly(6)
let seen = false
for (const ev of Array.from(res.body.events)) {
if (ev.type === 'primary') {
ev.mediator.should.be.exactly('urn:mediator:test')
seen = true
}
}
(seen).should.be.true()
})
it('should create events for slow secondary routes', async () => {
const startTime = await new Date()
await request(baseUrl)
.get('/test/slow')
.auth('testApp', 'password')
.expect(200)
await testUtils.pollCondition(() => EventModel.countDocuments().then(c => c === 6))
const res = await request(constants.BASE_URL)
.get(`/events/${+startTime}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
res.body.should.have.property('events')
res.body.events.length.should.be.exactly(6)
// TODO : double check what this is supposed to be checking against
// for (const ev of Array.from(res.body)) {
// ev.channelID.should.be.exactly(channel1._id);
// }
const events = await (res.body.events.map((event) => `${event.type}-${event.name}-${event.event}`))
events.should.containEql(`channel-${channelName}-slow-start`)
events.should.containEql(`channel-${channelName}-slow-end`)
events.should.containEql(`primary-${primaryRouteName}-start`)
events.should.containEql(`primary-${primaryRouteName}-end`)
events.should.containEql(`route-${secRouteName}-start`)
events.should.containEql(`route-${secRouteName}-end`)
})
it('should add mediator info for slow secondary routes', async () => {
const startTime = await new Date()
await request(baseUrl)
.get('/test/slow')
.auth('testApp', 'password')
.expect(200)
await testUtils.pollCondition(() => EventModel.countDocuments().then(c => c === 6))
const res = await request(constants.BASE_URL)
.get(`/events/${+startTime}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
res.body.should.have.property('events')
res.body.events.length.should.be.exactly(6)
let seen = false
for (const ev of Array.from(res.body.events)) {
if (ev.type === 'route') {
ev.mediator.should.be.exactly('urn:mediator:test')
seen = true
}
}
(seen).should.be.true()
})
})