diff --git a/src/api/__tests__/health.test.js b/src/api/__tests__/health.test.js index f99a9dd8..80289cb5 100644 --- a/src/api/__tests__/health.test.js +++ b/src/api/__tests__/health.test.js @@ -9,19 +9,19 @@ jest.mock('../../middleware/logging'); // Mocked so need to get real for expectedHealthCheckBase ?? describe('GET /health', () => { it('should return 200 and the response from getHealthCheck', done => { - getHealthCheck.mockReturnValue(Promise.resolve(expectedHealthCheckBase(true))); + getHealthCheck.mockReturnValue(Promise.resolve(expectedHealthCheckBase())); request(app) .get('/health') .expect(200) .expect(res => { - expect(res.body).toEqual(expectedHealthCheckBase(true)); + expect(res.body).toEqual(expectedHealthCheckBase()); }) .end(done); }); it('should call health check service with no parameters', done => { - getHealthCheck.mockReturnValue(Promise.resolve(expectedHealthCheckBase(true))); + getHealthCheck.mockReturnValue(Promise.resolve(expectedHealthCheckBase())); request(app) .get('/health') diff --git a/src/api/health-record-requests/__tests__/health-record-requests.test.js b/src/api/health-record-requests/__tests__/health-record-requests.test.js index b42925c8..6d152abe 100644 --- a/src/api/health-record-requests/__tests__/health-record-requests.test.js +++ b/src/api/health-record-requests/__tests__/health-record-requests.test.js @@ -164,7 +164,27 @@ describe('POST /health-record-requests/:nhsNumber', () => { }); describe('ODS code safe list', () => { - it('should return 422 status if ods code is not safe listed', done => { + it('should return 422 status if ods code is not in the safe list array', done => { + initializeConfig.mockReturnValueOnce({ + requestEhrOnlyForSafeListedOdsCodesToggle: true, + safeListedOdsCodes: ['SAFE08', 'SAFE09'], + nhsNumberPrefix: '123' + }); + request(app) + .post('/health-record-requests/1234567890') + .expect(res => { + expect(res.status).toEqual(422); + expect(res.body).toEqual( + expect.objectContaining({ + errors: 'The ODS code provided is not safe listed.' + }) + ); + }) + .send(body) + .end(done); + }); + + it('should return 422 status if ods code is not in safe list consisting of one string', done => { initializeConfig.mockReturnValueOnce({ requestEhrOnlyForSafeListedOdsCodesToggle: true, safeListedOdsCodes: 'SAFE09', @@ -184,7 +204,16 @@ describe('POST /health-record-requests/:nhsNumber', () => { .end(done); }); - it('should return 204 status if ods code is safe listed', done => { + it('should return 204 status if ods code is in the safe list array', done => { + initializeConfig.mockReturnValueOnce({ + requestEhrOnlyForSafeListedOdsCodesToggle: true, + safeListedOdsCodes: ['SAFE08', 'practice_ods_code'], + nhsNumberPrefix: '123' + }); + request(app).post('/health-record-requests/1234567890').expect(204).send(body).end(done); + }); + + it('should return 204 status if ods code is in the safe list consisting of one string', done => { initializeConfig.mockReturnValueOnce({ requestEhrOnlyForSafeListedOdsCodesToggle: true, safeListedOdsCodes: 'practice_ods_code', diff --git a/src/api/health-record-requests/health-record-requests.js b/src/api/health-record-requests/health-record-requests.js index 814b9219..200c74ee 100644 --- a/src/api/health-record-requests/health-record-requests.js +++ b/src/api/health-record-requests/health-record-requests.js @@ -117,9 +117,14 @@ const odsCodeNotInSafeList = ( logInfo( 'process only safe listed ODS code toggle is : ' + requestEhrOnlyForSafeListedOdsCodesToggle ); - if (requestEhrOnlyForSafeListedOdsCodesToggle) { - const caseInsensitiveOdsCode = new RegExp(practiceOdsCode, 'i'); - return !caseInsensitiveOdsCode.test(safeListedOdsCodes); - } - return false; + if (!requestEhrOnlyForSafeListedOdsCodesToggle) return false; + + return Array.isArray(safeListedOdsCodes) + ? !safeListedOdsCodes.some(safeListedOdsCode => + compareOdsCodesCaseInsensitive(safeListedOdsCode, practiceOdsCode) + ) + : !compareOdsCodesCaseInsensitive(safeListedOdsCodes, practiceOdsCode); }; + +const compareOdsCodesCaseInsensitive = (odsCode1, odsCode2) => + odsCode1.toLowerCase() === odsCode2.toLowerCase(); diff --git a/src/api/health-record-requests/send-continue-message.js b/src/api/health-record-requests/send-continue-message.js index 38cc3b80..15686c2a 100644 --- a/src/api/health-record-requests/send-continue-message.js +++ b/src/api/health-record-requests/send-continue-message.js @@ -25,7 +25,7 @@ export const sendContinueMessage = async (req, res) => { try { const practiceAsid = await getPracticeAsid(gpOdsCode, serviceId); - const message = await generateContinueRequest({ + const message = generateContinueRequest({ messageId, receivingAsid: practiceAsid, sendingAsid: config.repoAsid, diff --git a/src/api/health-record-requests/send-ehr-acknowledgement-controller.js b/src/api/health-record-requests/send-ehr-acknowledgement-controller.js index cba84b81..30bec0d9 100644 --- a/src/api/health-record-requests/send-ehr-acknowledgement-controller.js +++ b/src/api/health-record-requests/send-ehr-acknowledgement-controller.js @@ -26,7 +26,7 @@ export const sendEhrAcknowledgement = async (req, res) => { const practiceAsid = await getPracticeAsid(odsCode, serviceId); setCurrentSpanAttributes({ conversationId, messageId: ehrCoreMessageId }); - const message = await buildEhrAcknowledgementPayload({ + const message = buildEhrAcknowledgementPayload({ acknowledgementMessageId: conversationId, receivingAsid: practiceAsid, sendingAsid: repositoryAsid, diff --git a/src/middleware/__tests__/logging.test.js b/src/middleware/__tests__/logging.test.js index 4549056a..ff514893 100644 --- a/src/middleware/__tests__/logging.test.js +++ b/src/middleware/__tests__/logging.test.js @@ -44,7 +44,7 @@ describe('logging', () => { }; eventFinished(mockReq, mockRes); - expect(logger.info).toBeCalledTimes(1); + expect(logger.info).toBeCalledTimes(2); }); it('should log with level error if status code is not successful', () => { diff --git a/src/middleware/logging.js b/src/middleware/logging.js index cc487601..3a0d792d 100644 --- a/src/middleware/logging.js +++ b/src/middleware/logging.js @@ -5,7 +5,7 @@ export const logError = (status, error) => logger.error(status, { error }); export const logWarning = status => logger.warn(status); -export const logInfo = status => logger.info(status); +export const logInfo = (...logs) => logs.forEach(log => logger.info(log)); export const logDebug = status => logger.debug(status); diff --git a/src/services/health-check/__tests__/get-health-check.test.js b/src/services/health-check/__tests__/get-health-check.test.js index 12a36569..899e4c43 100644 --- a/src/services/health-check/__tests__/get-health-check.test.js +++ b/src/services/health-check/__tests__/get-health-check.test.js @@ -7,13 +7,13 @@ describe('get-health-check', () => { describe('getHealthCheck', () => { it('should resolve when both checks are ok', () => { return getHealthCheck().then(result => { - return expect(result).toStrictEqual(expectedHealthCheckBase(true)); + return expect(result).toStrictEqual(expectedHealthCheckBase()); }); }); it('should resolve when MHS is not ok', () => { return getHealthCheck().then(result => { - return expect(result).toStrictEqual(expectedHealthCheckBase(false)); + return expect(result).toStrictEqual(expectedHealthCheckBase()); }); }); }); diff --git a/src/services/mhs/__tests__/mhs-outbound-client.test.js b/src/services/mhs/__tests__/mhs-outbound-client.test.js index 89f17b0e..0a88c494 100644 --- a/src/services/mhs/__tests__/mhs-outbound-client.test.js +++ b/src/services/mhs/__tests__/mhs-outbound-client.test.js @@ -7,6 +7,7 @@ import generatePdsRetrievalQuery from '../../../templates/generate-pds-retrieval import testData from '../../../templates/__tests__/testData.json'; import { sendMessage, stripXMLMessage } from '../mhs-outbound-client'; import { sendToQueue } from '../../sqs/sqs-client'; +import expect from 'expect'; jest.mock('axios'); jest.mock('../../../config/logging'); @@ -366,9 +367,21 @@ describe('stripXMLMessage', () => { expect(stripXMLMessage(pdsRetrievalQuery).match(/> + { + it('should trim the whitespace at the beginning and end of the message', async () => { + // given const pdsRetrievalQuery = await generatePdsRetrievalQuery(pdsQueryArguments); - expect(stripXMLMessage(` ${pdsRetrievalQuery} `).match(/^ +| +$/)).toBe(null); + const XMLWithLeadingAndTrailingWhitespace = ` ${pdsRetrievalQuery} `; + // identifies trailing whitespace, content, and leading whitespace in 3 capture groups + const whitespaceRegex = '^(s*)(.*?)(s*)$'; + + // when + const strippedXML = stripXMLMessage(XMLWithLeadingAndTrailingWhitespace); + const regexMatches = strippedXML.match(whitespaceRegex); + + // then + expect(regexMatches[1]).toBe(''); + expect(regexMatches[2]).not.toBe(''); // should be pdsRetrievalQuery with new lines stripped + expect(regexMatches[3]).toBe(''); }); it('should remove new lines (/n) and carriage return characters (/r)', async () => { diff --git a/src/services/parser/xml-parser/xml-parser.js b/src/services/parser/xml-parser/xml-parser.js index c4023534..8bfa7b13 100644 --- a/src/services/parser/xml-parser/xml-parser.js +++ b/src/services/parser/xml-parser/xml-parser.js @@ -42,20 +42,30 @@ XmlParser.prototype.findFirst = function (key) { return foundAll[0]; }; +/** + * recursively search the XML to find a key (to a maximum depth), all values that are found will be returned as an array + */ const searchData = (object, key, maxDepth, found = []) => { let param; + // if we've recursed deeply enough for maxDepth to have been reached, return if (maxDepth-- === 0) { return found; } + // if we've found the key we're looking for, add the associated value(s) to 'found' if (key in object) { - Array.isArray(object[key]) ? found.push(...object[key]) : found.push(object[key]); + const value = object[key]; + + Array.isArray(value) + ? found.push(...value) + : found.push(value); } + // for each child node of this one, recurse for (param in object) { if (Object.prototype.hasOwnProperty.call(object, param) && typeof object[param] === 'object') { - found.concat(searchData(object[param], key, maxDepth, found)); + searchData(object[param], key, maxDepth, found); } } diff --git a/src/services/pds/pds-response-handler.js b/src/services/pds/pds-response-handler.js index 78294727..3009d4cb 100644 --- a/src/services/pds/pds-response-handler.js +++ b/src/services/pds/pds-response-handler.js @@ -1,5 +1,4 @@ -import { extractPdsId } from '../parser/pds'; -import { extractSerialChangeNumber } from '../parser/pds'; +import { extractPdsId, extractSerialChangeNumber } from '../parser/pds'; import { extractOdsCode } from '../parser/pds/extract-ods-code'; export const handlePdsResponse = async message => { diff --git a/src/templates/__tests__/generate-pds-retrieval-request.test.js b/src/templates/__tests__/generate-pds-retrieval-request.test.js index 9d33fc30..f13e50dd 100644 --- a/src/templates/__tests__/generate-pds-retrieval-request.test.js +++ b/src/templates/__tests__/generate-pds-retrieval-request.test.js @@ -38,7 +38,7 @@ describe('generatePdsRetrievalQuery', () => { const pdsRequestQuery = await generatePdsRetrievalQuery(testObjectComplete); const checkEntries = object => { - Object.keys(object).map(key => { + Object.keys(object).forEach(key => { if (typeof object[key] === 'object') { checkEntries(object[key]); } else { diff --git a/src/templates/generate-update-ods-request.js b/src/templates/generate-update-ods-request.js index 8eb92181..5af7139d 100644 --- a/src/templates/generate-update-ods-request.js +++ b/src/templates/generate-update-ods-request.js @@ -37,7 +37,7 @@ const template = ({ timestamp, receivingService: { asid: receivingAsid }, sendingService: { asid: sendingAsid }, - newOdsCode: newOdsCode, + newOdsCode, patient: { nhsNumber, pdsId, pdsUpdateChangeNumber } }) => ` diff --git a/src/templates/utils/check_params.js b/src/templates/utils/check_params.js index c683e12f..2f27f0d0 100644 --- a/src/templates/utils/check_params.js +++ b/src/templates/utils/check_params.js @@ -1,4 +1,4 @@ -const recursiveTemplateCheck = (inputObject, maxDepth = 10, errorMessages) => { +const recursiveTemplateCheck = (inputObject, errorMessages, maxDepth = 10) => { if (maxDepth-- === 0) { throw new Error('maxDepth reached, exiting'); } @@ -12,14 +12,14 @@ const recursiveTemplateCheck = (inputObject, maxDepth = 10, errorMessages) => { errorMessages.push(` ${key} is undefined`); } if (typeof inputObject[key] === 'object') { - recursiveTemplateCheck(inputObject[key], maxDepth, errorMessages); + recursiveTemplateCheck(inputObject[key], errorMessages, maxDepth); } }); }; const checkTemplateArguments = (inputObject, maxDepth) => { const errorMessages = []; - recursiveTemplateCheck(inputObject, maxDepth, errorMessages); + recursiveTemplateCheck(inputObject, errorMessages, maxDepth); if (errorMessages.length > 0) throw new Error(`Check template parameter error:${errorMessages}`); }; diff --git a/utils/generate-messages.js b/utils/generate-messages.js deleted file mode 100644 index 02ff4fb0..00000000 --- a/utils/generate-messages.js +++ /dev/null @@ -1,123 +0,0 @@ -const { v4: uuid } = require('uuid'); -const dateFormat = require('dateformat'); -const generateEhrRequestQuery = require('../src/templates/ehr-request-template'); -const generateUpdatePdsRequest = require('../src/templates/generate-update-ods-request'); -const generatePdsRetrievalQuery = require('../src/templates/pds-retrieval-template'); -const generateContinueRequest = require('../src/templates/generate-continue-request'); - -// receiving_asid_2: '200000000631', -const emisPatient = { - title: 'Miss', - gender: 'Female', - firstName: 'Emma', - lastName: 'Fergus', - dob: '20170104', - nhsNumber: '9651221577', - pdsId: '273B24A9', - conversationId: 'hhh' -}; - -// receiving_asid_2: '200000000631', -const tppPatient = { - gender: 'Female', - firstName: 'Justice', - lastName: 'Sadare', - dob: '19701202', - nhsNumber: '9442964410', - pdsId: 'cppz', - conversationId: '', - serialChaneNumber: '138' // + 1 each time -}; - -const emisPractise = { - name: 'Walton Village R', - odsCode: 'N82668', - asid: '200000000205' -}; - -const tppPractise = { - name: '', - odsCode: 'M85019', - asid: '' -}; - -const mhs = { - name: 'Deductions MHS', - odsCode: 'B86041', - asid: '200000001161' -}; - -const pds = { - name: 'PDS', - odsCode: 'YES', - asid: '928942012545' -}; - -// pdsASID: -// conversationId: '6A073022-182F-4106-92CC-86E933F71A3E' - -console.log(dateFormat(Date.now(), 'yyyymmddHHMMss')); - -const advancePdsRequest = generateAdvancePdsRequest( - uuid(), - dateFormat(Date.now(), 'yyyymmddHHMMss'), - patient.mhsASID, - patient.pdsASID, - genderCode(patient.patientGender), - patient.patientTitle, - patient.patientFirstName, - patient.patientLastName, - patient.patientDOB -); - -const gp2gpRequest = generateEhrRequestQuery({ - id: uuid(), - timestamp: dateFormat(Date.now(), 'yyyymmddHHMMss'), - patient: { - nhsNumber: emisPatient.nhsNumber - }, - receivingService: { - asid: emisPractise.asid, - odsCode: emisPractise.odsCode - }, - sendingService: { - asid: mhs.asid, - odsCode: mhs.odsCode - } -}); - -const pdsUpdateRequestToUs = generateUpdatePdsRequest({ - id: uuid(), - timestamp: dateFormat(Date.now(), 'yyyymmddHHMMss'), - receivingService: { asid: pds.asid }, - sendingService: { asid: mhs.asid, odsCode: mhs.odsCode }, - patient: { - nhsNumber: tppPatient.nhsNumber, - pdsId: tppPatient.pdsId, - pdsUpdateChangeNumber: tppPatient.serialChaneNumber - } -}); - -const pdsRetrevalQuery = generatePdsRetrievalQuery({ - id: uuid(), - timestamp: dateFormat(Date.now(), 'yyyymmddHHMMss'), - receivingService: { asid: pds.asid }, - sendingService: { asid: mhs.asid }, - patient: { nhsNumber: tppPatient.nhsNumber } -}); - -const gp2gpContinueMessage = generateContinueRequest( - uuid(), - dateFormat(Date.now(), 'yyyymmddHHMMss'), - patient.receiving_asid_2, - patient.mhsASID, - patient.conversationId, - patient.practiseODSCode, - patient.mhsODSCode -); - -//console.log('AdvancePDS:\n', advancePdsRequest); -//console.log('GP2GP Request:\n', gp2gpRequest); -//console.log('Retreival querr PDS:\n', pdsRetrevalQuery); -console.log('PDS Update GP -> Us:\n', pdsUpdateRequestToUs); -//console.log('Continue Message:\n', gp2gpContinueMessage);