openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
330 lines (300 loc) • 14.5 kB
JavaScript
/* eslint-env mocha */
/* eslint no-unused-expressions:0 */
import should from 'should'
import request from 'supertest'
import * as server from '../../src/server'
import { AuditModel, AuditMetaModel } from '../../src/model'
import * as testUtils from '../utils'
import * as constants from '../constants'
import { config } from '../../src/config'
import { promisify } from 'util'
describe('API Integration Tests', () => {
const router = config.get('router')
const api = config.get('api')
let authDetails
before(async () => {
await testUtils.setupTestUsers()
await promisify(server.start)({ apiPort: constants.SERVER_PORTS.apiPort })
authDetails = testUtils.getAuthDetails()
})
after(async () => {
await Promise.all([
promisify(server.stop)(),
testUtils.cleanupTestUsers()
])
})
afterEach(async () => {
await Promise.all([
AuditModel.deleteMany({}),
AuditMetaModel.deleteMany({})
])
})
describe('Audits REST Api testing', () => {
const auditData = Object.freeze({
rawMessage: 'This will be the raw ATNA message that gets received to be used as a backup reference',
eventIdentification: {
eventDateTime: '2015-02-20T15:38:25.282Z',
eventOutcomeIndicator: '0',
eventActionCode: 'E',
eventID: {
code: '110112',
displayName: 'Query',
codeSystemName: 'DCM'
},
eventTypeCode: {
code: 'ITI-9',
displayName: 'PIX Query',
codeSystemName: 'IHE Transactions'
}
},
activeParticipant: [
{
userID: 'pix|pix',
alternativeUserID: '2100',
userIsRequestor: 'false',
networkAccessPointID: 'localhost',
networkAccessPointTypeCode: '1',
roleIDCode: {
code: '110152',
displayName: 'Destination',
codeSystemName: 'DCM'
}
}, {
userID: 'pix|pix',
alternativeUserID: '2100',
userIsRequestor: 'false',
networkAccessPointID: 'localhost',
networkAccessPointTypeCode: '1',
roleIDCode: {
code: '110152',
displayName: 'Destination',
codeSystemName: 'DCM'
}
}
],
auditSourceIdentification: {
auditSourceID: 'openhim'
},
participantObjectIdentification: [
{
participantObjectID: '975cac30-68e5-11e4-bf2a-04012ce65b02^^^ECID&ECID&ISO',
participantObjectTypeCode: '1',
participantObjectTypeCodeRole: '1',
participantObjectIDTypeCode: {
code: '2',
displayName: 'PatientNumber',
codeSystemName: 'RFC-3881'
}
}, {
participantObjectID: 'dca6c09e-cc92-4bc5-8741-47bd938fa405',
participantObjectTypeCode: '2',
participantObjectTypeCodeRole: '24',
participantObjectIDTypeCode: {
code: 'ITI-9',
displayName: 'PIX Query',
codeSystemName: 'IHE Transactions'
},
participantObjectQuery: 'TVNIfF5+XCZ8b3BlbmhpbXxvcGVuaGltLW1lZGlhdG9yLW9oaWUteGRzfHBpeHxwaXh8MjAxNTAyMjAxNTM4MjUrMDIwMHx8UUJQXlEyM15RQlBfUTIxfDEwMDQxYWQ5LTkyNDAtNDEyNS04ZDMwLWZiYzczNGEwOTMwMXxQfDIuNQ1RUER8SUhFIFBJWCBRdWVyeXw1OTRhNDVkYS0zOTY5LTQzOTAtODE2Ni01MjhkZDFmNWU0ZTF8NzZjYzc2NWE0NDJmNDEwXl5eJjEuMy42LjEuNC4xLjIxMzY3LjIwMDUuMy43JklTT15QSXxeXl5FQ0lEJkVDSUQmSVNPXlBJDVJDUHxJDQ==',
participantObjectDetail: {
type: 'MSH-10',
value: 'MTAwNDFhZDktOTI0MC00MTI1LThkMzAtZmJjNzM0YTA5MzAx'
}
}
]
})
describe('*addAudit()', () => {
it('should add a audit and return status 201 - audit created', async () => {
await request(constants.BASE_URL)
.post('/audits')
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.send(auditData)
.expect(201)
const newAudit = await AuditModel.findOne({ 'eventIdentification.eventDateTime': '2015-02-20T15:38:25.282Z' })
should(newAudit != null).true()
newAudit.eventIdentification.eventActionCode.should.equal('E')
newAudit.eventIdentification.eventID.code.should.equal('110112')
newAudit.eventIdentification.eventID.displayName.should.equal('Query')
newAudit.eventIdentification.eventID.codeSystemName.should.equal('DCM')
newAudit.activeParticipant.length.should.equal(2)
newAudit.activeParticipant[0].userID.should.equal('pix|pix')
newAudit.activeParticipant[0].networkAccessPointID.should.equal('localhost')
newAudit.auditSourceIdentification.auditSourceID.should.equal('openhim')
newAudit.participantObjectIdentification.length.should.equal(2)
newAudit.participantObjectIdentification[0].participantObjectID.should.equal('975cac30-68e5-11e4-bf2a-04012ce65b02^^^ECID&ECID&ISO')
newAudit.participantObjectIdentification[0].participantObjectIDTypeCode.codeSystemName.should.equal('RFC-3881')
newAudit.participantObjectIdentification[1].participantObjectID.should.equal('dca6c09e-cc92-4bc5-8741-47bd938fa405')
newAudit.participantObjectIdentification[1].participantObjectIDTypeCode.codeSystemName.should.equal('IHE Transactions')
})
it('should only allow admin users to add audits', async () => {
await request(constants.BASE_URL)
.post('/audits')
.set('auth-username', testUtils.nonRootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.send(auditData)
.expect(403)
})
})
describe('*getAudits()', () => {
it('should call getAudits ', async () => {
const countBefore = await AuditModel.countDocuments()
await new AuditModel(auditData).save()
const res = await request(constants.BASE_URL)
.get('/audits?filterPage=0&filterLimit=10&filters={}')
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
res.body.length.should.equal(countBefore + 1)
})
it('should call getAudits with filter paramaters ', async () => {
let filters = {}
filters['eventIdentification.eventDateTime'] = '{ "$gte": "2015-02-20T00:00:00.000Z","$lte": "2015-02-21T00:00:00.000Z" }'
filters = JSON.stringify(filters)
const countBefore = await AuditModel.countDocuments()
await new AuditModel(auditData).save()
const res = await request(constants.BASE_URL)
.get(`/audits?filterPage=0&filterLimit=10&filters=${encodeURIComponent(filters)}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
res.body.length.should.equal(countBefore + 1)
})
it('should generate an \'audit log used\' audit when using non-basic representation', async () => {
const result = await new AuditModel(auditData).save()
await request(constants.BASE_URL)
.get('/audits?filterRepresentation=full')
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
await testUtils.pollCondition(() => AuditModel.countDocuments().then(c => c === 2))
const newAudits = await AuditModel.find()
// needs to wait?
newAudits.length.should.be.exactly(2)
if (newAudits[0].eventIdentification.eventID.displayName === 'Audit Log Used') {
newAudits[0].participantObjectIdentification.length.should.be.exactly(1)
newAudits[0].participantObjectIdentification[0].participantObjectID.should.be.exactly(`https://localhost:8080/audits/${result._id}`)
} else {
newAudits[1].eventIdentification.eventID.displayName === 'Audit Log Used'
newAudits[1].participantObjectIdentification.length.should.be.exactly(1)
newAudits[1].participantObjectIdentification[0].participantObjectID.should.be.exactly(`https://localhost:8080/audits/${result._id}`)
}
})
it('should NOT generate an \'audit log used\' audit when using basic (default) representation', async () => {
await new AuditModel(auditData).save()
await request(constants.BASE_URL)
.get('/audits')
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
const auditCount = await AuditModel.countDocuments()
auditCount.should.eql(1)
})
})
describe('*getAuditById (auditId)', () => {
it('should fetch a audit by ID - admin user', async () => {
const audit = await new AuditModel(auditData).save()
const auditId = audit._id
const res = await request(constants.BASE_URL)
.get(`/audits/${auditId}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
res.body.eventIdentification.eventDateTime.should.equal('2015-02-20T15:38:25.282Z')
res.body.eventIdentification.eventActionCode.should.equal('E')
res.body.eventIdentification.eventID.code.should.equal('110112')
res.body.eventIdentification.eventID.displayName.should.equal('Query')
res.body.eventIdentification.eventID.codeSystemName.should.equal('DCM')
res.body.activeParticipant.length.should.equal(2)
res.body.activeParticipant[0].userID.should.equal('pix|pix')
res.body.activeParticipant[0].networkAccessPointID.should.equal('localhost')
res.body.auditSourceIdentification.auditSourceID.should.equal('openhim')
res.body.participantObjectIdentification.length.should.equal(2)
res.body.participantObjectIdentification[0].participantObjectID.should.equal('975cac30-68e5-11e4-bf2a-04012ce65b02^^^ECID&ECID&ISO')
res.body.participantObjectIdentification[0].participantObjectIDTypeCode.codeSystemName.should.equal('RFC-3881')
res.body.participantObjectIdentification[1].participantObjectID.should.equal('dca6c09e-cc92-4bc5-8741-47bd938fa405')
res.body.participantObjectIdentification[1].participantObjectIDTypeCode.codeSystemName.should.equal('IHE Transactions')
})
it('should NOT return a audit that a user is not allowed to view', async () => {
const audit = await new AuditModel(auditData).save()
const auditId = audit._id
await request(constants.BASE_URL)
.get(`/audits/${auditId}`)
.set('auth-username', testUtils.nonRootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(403)
})
it('should generate an \'audit log used\' audit', async () => {
const audit = await new AuditModel(auditData).save()
const auditId = audit._id
await request(constants.BASE_URL)
.get(`/audits/${auditId}`)
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
await testUtils.pollCondition(() => AuditModel.countDocuments().then(c => c === 2))
const newAudits = await AuditModel.find()
newAudits.length.should.eql(2)
const participantObjectID = `https://${router.externalHostname}:${api.httpsPort}/audits/${auditId}`
if (newAudits[0].eventIdentification.eventID.displayName === 'Audit Log Used') {
newAudits[0].participantObjectIdentification.length.should.be.exactly(1)
newAudits[0].participantObjectIdentification[0].participantObjectID.should.be.exactly(participantObjectID)
} else {
newAudits[1].eventIdentification.eventID.displayName === 'Audit Log Used'
newAudits[1].participantObjectIdentification.length.should.be.exactly(1)
newAudits[1].participantObjectIdentification[0].participantObjectID.should.be.exactly(participantObjectID)
}
})
})
describe('*getAuditsFilterOptions', () => {
it('should fetch dropdown filter options - admin user', async () => {
await request(constants.BASE_URL)
.post('/audits')
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.send(auditData)
.expect(201)
const res = await request(constants.BASE_URL)
.get('/audits-filter-options')
.set('auth-username', testUtils.rootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(200)
res.body.eventType.length.should.equal(1)
res.body.eventID.length.should.equal(1)
res.body.activeParticipantRoleID.length.should.equal(1)
res.body.participantObjectIDTypeCode.length.should.equal(2)
})
it('should NOT return a filter dropdown object if user is not admin', async () => {
await new AuditModel(auditData).save()
await request(constants.BASE_URL)
.get('/audits-filter-options')
.set('auth-username', testUtils.nonRootUser.email)
.set('auth-ts', authDetails.authTS)
.set('auth-salt', authDetails.authSalt)
.set('auth-token', authDetails.authToken)
.expect(403)
})
})
})
})