account-lookup-service 15.6.0-iso.2 → 15.6.0-iso.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.circleci/config.yml +1 -1
  2. package/.ncurc.yaml +1 -2
  3. package/audit-ci.jsonc +3 -1
  4. package/jest.config.js +2 -0
  5. package/package.json +15 -17
  6. package/src/constants.js +2 -1
  7. package/src/domain/oracle/oracle.js +63 -4
  8. package/src/domain/participants/participants.js +259 -133
  9. package/src/domain/parties/getPartiesByTypeAndID.js +36 -15
  10. package/src/domain/parties/parties.js +44 -14
  11. package/src/domain/parties/utils.js +13 -6
  12. package/src/domain/timeout/dto.js +4 -10
  13. package/src/domain/timeout/index.js +12 -1
  14. package/src/handlers/index.js +4 -4
  15. package/src/handlers/monitoring/index.js +1 -1
  16. package/src/interface/api-swagger-iso20022-parties.yaml +7 -6
  17. package/src/interface/api-swagger.yaml +7 -6
  18. package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2043 -1583
  19. package/src/lib/config.js +1 -1
  20. package/src/lib/index.js +1 -2
  21. package/src/models/currency/currency.js +10 -1
  22. package/src/models/endpointType/endpointType.js +10 -1
  23. package/src/models/oracle/facade.js +24 -3
  24. package/src/models/oracle/oracleEndpoint.js +64 -10
  25. package/src/models/oracle/oracleEndpointCached.js +22 -3
  26. package/src/models/participantEndpoint/facade.js +61 -23
  27. package/src/models/partyIdType/partyIdType.js +10 -1
  28. package/src/plugins.js +20 -9
  29. package/src/server.js +11 -19
  30. package/test/fixtures/index.js +30 -6
  31. package/test/fixtures/iso.js +1 -1
  32. package/test/unit/api/health.test.js +3 -0
  33. package/test/unit/api/participants/participants.test.js +5 -7
  34. package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +0 -3
  35. package/test/unit/api/participants/{Type}/{ID}.test.js +0 -3
  36. package/test/unit/api/participants.test.js +36 -3
  37. package/test/unit/domain/oracle/oracle.test.js +8 -0
  38. package/test/unit/domain/participants/participants.test.js +83 -48
  39. package/test/unit/domain/parties/parties.test.js +11 -3
  40. package/test/unit/domain/parties/utils.test.js +60 -0
  41. package/test/unit/domain/timeout/dto.test.js +1 -2
  42. package/test/unit/domain/timeout/index.test.js +8 -0
  43. package/test/unit/lib/TransformFacades.test.js +2 -1
  44. package/test/unit/lib/config.test.js +7 -0
  45. package/test/unit/models/participantEndpoint/facade.test.js +25 -8
  46. package/test/unit/plugins.test.js +4 -2
  47. package/test/util/apiClients/BasicApiClient.js +2 -2
  48. package/src/handlers/monitoring/plugins/metrics.js +0 -48
  49. package/src/lib/requestLogger.js +0 -54
  50. package/src/metrics/handler.js +0 -33
  51. package/src/metrics/plugin.js +0 -52
  52. package/src/metrics/routes.js +0 -43
  53. package/test/unit/lib/requestLogger.test.js +0 -115
@@ -74,7 +74,7 @@ const party40ChoiceDto = ({
74
74
 
75
75
  const assgnmtDto = () => ({
76
76
  MsgId: '123',
77
- CreDtTm: '2020-01-01T00:00:00Z',
77
+ CreDtTm: '2024-10-29T16:25:11.916Z',
78
78
  Assgnr: party40ChoiceDto(),
79
79
  Assgne: party40ChoiceDto()
80
80
  })
@@ -38,6 +38,7 @@ const Sinon = require('sinon')
38
38
  const MigrationLockModel = require('../../../src/models/misc/migrationLock')
39
39
  const Logger = require('@mojaloop/central-services-logger')
40
40
  const Config = require('../../../src/lib/config')
41
+ const Metrics = require('@mojaloop/central-services-metrics')
41
42
 
42
43
  Logger.isDebugEnabled = jest.fn(() => true)
43
44
  Logger.isErrorEnabled = jest.fn(() => true)
@@ -51,6 +52,7 @@ describe('/health', () => {
51
52
  sandbox = Sinon.createSandbox()
52
53
  sandbox.stub(Db, 'connect').returns(Promise.resolve({}))
53
54
  Config.API_PORT = await getPort()
55
+ Metrics.getDefaultRegister().clear()
54
56
  server = await initServer(Config)
55
57
  })
56
58
 
@@ -117,6 +119,7 @@ describe('/health', () => {
117
119
  Config.proxyMap = { proxied: 'proxy' }
118
120
  let serverWithProxy
119
121
  try {
122
+ Metrics.getDefaultRegister().clear()
120
123
  serverWithProxy = await initServer(Config)
121
124
  sandbox.stub(MigrationLockModel, 'getIsMigrationLocked').resolves(false)
122
125
  const mock = await Helper.generateMockRequest('/health', 'get')
@@ -35,16 +35,12 @@ const Helper = require('../../../util/helper')
35
35
  const participants = require('../../../../src/domain/participants')
36
36
  const initServer = require('../../../../src/server').initializeApi
37
37
  const getPort = require('get-port')
38
- const Logger = require('@mojaloop/central-services-logger')
39
38
  const Config = require('../../../../src/lib/config')
40
39
 
41
- Logger.isDebugEnabled = jest.fn(() => true)
42
- Logger.isErrorEnabled = jest.fn(() => true)
43
- Logger.isInfoEnabled = jest.fn(() => true)
44
- let server
45
- let sandbox
46
-
47
40
  describe('/participants', () => {
41
+ let server
42
+ let sandbox
43
+
48
44
  beforeAll(async () => {
49
45
  sandbox = Sinon.createSandbox()
50
46
  sandbox.stub(Db, 'connect').returns(Promise.resolve({}))
@@ -56,6 +52,7 @@ describe('/participants', () => {
56
52
  await server.stop()
57
53
  sandbox.restore()
58
54
  })
55
+
59
56
  const mock = {
60
57
  requestId: '3ede3c17-36aa-42f4-b6db-b0df2e42f31e',
61
58
  partyList: [{
@@ -79,6 +76,7 @@ describe('/participants', () => {
79
76
  ],
80
77
  currency: 'EUR'
81
78
  }
79
+
82
80
  it('postParticipantsBatch success', async () => {
83
81
  // Arrange
84
82
  const options = {
@@ -35,7 +35,6 @@ const Db = require('../../../../../../src/lib/db')
35
35
  const oracleEndpointCached = require('../../../../../../src/models/oracle/oracleEndpointCached')
36
36
  const participant = require('../../../../../../src/models/participantEndpoint/facade')
37
37
  const participants = require('../../../../../../src/domain/participants')
38
- const requestLogger = require('../../../../../../src/lib/requestLogger')
39
38
  const Helper = require('../../../../../util/helper')
40
39
  const initServer = require('../../../../../../src/server').initializeApi
41
40
  const Logger = require('@mojaloop/central-services-logger')
@@ -51,8 +50,6 @@ describe('/participants/{Type}/{ID}/{SubId}', () => {
51
50
  beforeAll(async () => {
52
51
  sandbox = Sinon.createSandbox()
53
52
  sandbox.stub(Db, 'connect').returns(Promise.resolve({}))
54
- sandbox.stub(requestLogger, 'logRequest').returns({})
55
- sandbox.stub(requestLogger, 'logResponse').returns({})
56
53
  Config.API_PORT = await getPort()
57
54
  server = await initServer(Config)
58
55
  })
@@ -40,7 +40,6 @@ const Db = require('../../../../../src/lib/db')
40
40
  const oracleEndpointCached = require('../../../../../src/models/oracle/oracleEndpointCached')
41
41
  const participant = require('../../../../../src/models/participantEndpoint/facade')
42
42
  const participants = require('../../../../../src/domain/participants')
43
- const requestLogger = require('../../../../../src/lib/requestLogger')
44
43
  const Helper = require('../../../../util/helper')
45
44
  const initServer = require('../../../../../src/server').initializeApi
46
45
  const Config = require('../../../../../src/lib/config')
@@ -55,8 +54,6 @@ describe('/participants/{Type}/{ID}', () => {
55
54
  beforeAll(async () => {
56
55
  sandbox = Sinon.createSandbox()
57
56
  sandbox.stub(Db, 'connect').returns(Promise.resolve({}))
58
- sandbox.stub(requestLogger, 'logRequest').returns({})
59
- sandbox.stub(requestLogger, 'logResponse').returns({})
60
57
  Config.API_PORT = await getPort()
61
58
  server = await initServer(Config)
62
59
  sandbox.stub(Logger)
@@ -36,6 +36,7 @@ const initServer = require('../../../src/server').initializeApi
36
36
  const Helper = require('../../util/helper')
37
37
  const Db = require('../../../src/lib/db')
38
38
  const Config = require('../../../src/lib/config')
39
+ const fixtures = require('../../fixtures')
39
40
 
40
41
  Logger.isDebugEnabled = jest.fn(() => true)
41
42
  Logger.isErrorEnabled = jest.fn(() => true)
@@ -44,14 +45,14 @@ let sandbox
44
45
  let server
45
46
 
46
47
  describe('/participants', () => {
47
- beforeEach(async () => {
48
+ beforeAll(async () => {
48
49
  sandbox = Sinon.createSandbox()
49
50
  sandbox.stub(Db, 'connect').returns(Promise.resolve({}))
50
51
  Config.API_PORT = await getPort()
51
52
  server = await initServer(Config)
52
53
  })
53
54
 
54
- afterEach(async () => {
55
+ afterAll(async () => {
55
56
  await server.stop()
56
57
  sandbox.restore()
57
58
  })
@@ -103,6 +104,38 @@ describe('/participants', () => {
103
104
 
104
105
  // Assert
105
106
  expect(response.statusCode).toBe(400)
106
- await server.stop()
107
+ })
108
+
109
+ it('should validate requestId in UUID format', async () => {
110
+ const reqOptions = {
111
+ method: 'post',
112
+ url: '/participants',
113
+ headers: fixtures.participantsCallHeadersDto(),
114
+ payload: fixtures.postParticipantsPayloadDto()
115
+ }
116
+ const response = await server.inject(reqOptions)
117
+ expect(response.statusCode).toBe(200)
118
+ })
119
+
120
+ it('should validate requestId in ULID format', async () => {
121
+ const reqOptions = {
122
+ method: 'post',
123
+ url: '/participants',
124
+ headers: fixtures.participantsCallHeadersDto(),
125
+ payload: fixtures.postParticipantsPayloadDto({ requestId: '01JE8SG3F4WNHY8B9876THQ344' })
126
+ }
127
+ const response = await server.inject(reqOptions)
128
+ expect(response.statusCode).toBe(200)
129
+ })
130
+
131
+ it('should fail requestId validation', async () => {
132
+ const reqOptions = {
133
+ method: 'post',
134
+ url: '/participants',
135
+ headers: fixtures.participantsCallHeadersDto(),
136
+ payload: fixtures.postParticipantsPayloadDto({ requestId: 'wrong format' })
137
+ }
138
+ const response = await server.inject(reqOptions)
139
+ expect(response.statusCode).toBe(400)
107
140
  })
108
141
  })
@@ -37,6 +37,7 @@ const partyIdType = require('../../../../src/models/partyIdType')
37
37
  const Db = require('../../../../src/lib/db')
38
38
  const oracleEndpointCached = require('../../../../src/models/oracle/oracleEndpointCached')
39
39
  const Logger = require('@mojaloop/central-services-logger')
40
+ const Metrics = require('@mojaloop/central-services-metrics')
40
41
 
41
42
  Logger.isDebugEnabled = jest.fn(() => true)
42
43
  Logger.isErrorEnabled = jest.fn(() => true)
@@ -90,6 +91,13 @@ let sandbox
90
91
  let SpanStub
91
92
 
92
93
  describe('Oracle tests', () => {
94
+ // Initialize Metrics for testing
95
+ Metrics.getCounter(
96
+ 'errorCount',
97
+ 'Error count',
98
+ ['code', 'system', 'operation', 'step']
99
+ )
100
+
93
101
  beforeEach(() => {
94
102
  sandbox = Sinon.createSandbox()
95
103
  Db.partyIdType = {
@@ -34,20 +34,28 @@ const Sinon = require('sinon')
34
34
  const Enums = require('@mojaloop/central-services-shared').Enum
35
35
  const Logger = require('@mojaloop/central-services-logger')
36
36
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
37
+ const Metrics = require('@mojaloop/central-services-metrics')
37
38
 
38
39
  const participantsDomain = require('../../../../src/domain/participants/participants')
39
40
  const participant = require('../../../../src/models/participantEndpoint/facade')
40
41
  const oracle = require('../../../../src/models/oracle/facade')
41
- const Helper = require('../../../util/helper')
42
42
  const Config = require('../../../../src/lib/config')
43
+ const { logger } = require('../../../../src/lib')
44
+ const { ERROR_MESSAGES } = require('../../../../src/constants')
45
+ const Helper = require('../../../util/helper')
46
+ const fixtures = require('../../../fixtures')
43
47
 
44
- Logger.isDebugEnabled = jest.fn(() => true)
45
- Logger.isErrorEnabled = jest.fn(() => true)
46
- Logger.isInfoEnabled = jest.fn(() => true)
48
+ const { Headers } = Enums.Http
47
49
 
48
50
  describe('participant Tests', () => {
49
51
  describe('getParticipantsByTypeAndID', () => {
50
52
  let sandbox
53
+ // Initialize Metrics for testing
54
+ Metrics.getCounter(
55
+ 'errorCount',
56
+ 'Error count',
57
+ ['code', 'system', 'operation', 'step']
58
+ )
51
59
 
52
60
  beforeEach(() => {
53
61
  sandbox = Sinon.createSandbox()
@@ -185,7 +193,7 @@ describe('participant Tests', () => {
185
193
  expect.hasAssertions()
186
194
  // Arrange
187
195
  participant.validateParticipant = sandbox.stub().resolves(null)
188
- const logErrorStub = sandbox.stub(Logger, 'error')
196
+ const logStub = sandbox.stub(logger.constructor.prototype, 'warn')
189
197
 
190
198
  participant.sendRequest = sandbox.stub()
191
199
  const args = [
@@ -199,8 +207,8 @@ describe('participant Tests', () => {
199
207
  await participantsDomain.getParticipantsByTypeAndID(...args)
200
208
 
201
209
  // Assert
202
- const firstCallArgs = logErrorStub.getCall(0).args
203
- expect(firstCallArgs[0]).toBe('Requester FSP not found')
210
+ const firstCallArgs = logStub.getCall(0).args
211
+ expect(firstCallArgs[0]).toBe(ERROR_MESSAGES.sourceFspNotFound)
204
212
  })
205
213
 
206
214
  it('fails when `oracleRequest` response is empty', async () => {
@@ -485,9 +493,8 @@ describe('participant Tests', () => {
485
493
  it('handles the case where `validateParticipant` returns null', async () => {
486
494
  expect.hasAssertions()
487
495
  // Arrange
496
+ const logStub = sandbox.stub(logger.constructor.prototype, 'error')
488
497
  participant.validateParticipant = sandbox.stub().resolves(null)
489
- sandbox.stub(Logger)
490
- Logger.error = sandbox.stub()
491
498
  participant.sendErrorToParticipant = sandbox.stub()
492
499
  const headers = {
493
500
  accept: 'application/vnd.interoperability.participants+json;version=1',
@@ -510,8 +517,7 @@ describe('participant Tests', () => {
510
517
  await participantsDomain.putParticipantsByTypeAndID(headers, params, method, payload)
511
518
 
512
519
  // Assert
513
- const loggerFirstCallArgs = Logger.error.getCall(0).args
514
- expect(loggerFirstCallArgs[0]).toBe('Requester FSP not found')
520
+ expect(logStub.getCall(0).args[1].message).toBe(ERROR_MESSAGES.sourceFspNotFound)
515
521
  })
516
522
 
517
523
  it('handles case where type is not in `PartyAccountTypes`', async () => {
@@ -739,9 +745,6 @@ describe('participant Tests', () => {
739
745
  it('handles PUT /error when SubId supplied but validateParticipant throws error', async () => {
740
746
  expect.hasAssertions()
741
747
  // Arrange
742
- sandbox.stub(Logger)
743
- Logger.info = sandbox.stub()
744
- Logger.error = sandbox.stub()
745
748
  participant.validateParticipant = sandbox.stub().throws(new Error('Validation failed'))
746
749
  oracle.oracleRequest = sandbox.stub().resolves(null)
747
750
  participant.sendErrorToParticipant = sandbox.stub()
@@ -771,15 +774,11 @@ describe('participant Tests', () => {
771
774
  expect(participant.sendErrorToParticipant.callCount).toBe(1)
772
775
  const firstCallArgs = participant.sendErrorToParticipant.getCall(0).args
773
776
  expect(firstCallArgs[1]).toBe(expectedCallbackEndpointType)
774
- expect(Logger.error.callCount).toBe(1)
775
777
  })
776
778
 
777
779
  it('handles PUT /error when `sendErrorToParticipant` throws error', async () => {
778
780
  expect.hasAssertions()
779
781
  // Arrange
780
- sandbox.stub(Logger)
781
- Logger.info = sandbox.stub()
782
- Logger.error = sandbox.stub()
783
782
  participant.validateParticipant = sandbox.stub().resolves({})
784
783
  participant.sendErrorToParticipant = sandbox.stub().throws(new Error('sendErrorToParticipant failed'))
785
784
  const expectedCallbackEndpointType = Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR
@@ -809,15 +808,11 @@ describe('participant Tests', () => {
809
808
  const secondCallArgs = participant.sendErrorToParticipant.getCall(1).args
810
809
  expect(firstCallArgs[1]).toBe(expectedCallbackEndpointType)
811
810
  expect(secondCallArgs[0]).toBe(Config.HUB_NAME)
812
- expect(Logger.error.callCount).toBe(2)
813
811
  })
814
812
 
815
813
  it('handles PUT /error when SubId is supplied and `sendErrorToParticipant` throws error', async () => {
816
814
  expect.hasAssertions()
817
815
  // Arrange
818
- sandbox.stub(Logger)
819
- Logger.info = sandbox.stub()
820
- Logger.error = sandbox.stub()
821
816
  participant.validateParticipant = sandbox.stub().resolves({})
822
817
  participant.sendErrorToParticipant = sandbox.stub().throws(new Error('sendErrorToParticipant failed'))
823
818
  const expectedCallbackEndpointType = Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR
@@ -848,7 +843,6 @@ describe('participant Tests', () => {
848
843
  const secondCallArgs = participant.sendErrorToParticipant.getCall(1).args
849
844
  expect(firstCallArgs[1]).toBe(expectedCallbackEndpointType)
850
845
  expect(secondCallArgs[0]).toBe(Config.HUB_NAME)
851
- expect(Logger.error.callCount).toBe(2)
852
846
  })
853
847
  })
854
848
 
@@ -1048,9 +1042,8 @@ describe('participant Tests', () => {
1048
1042
  it('handles the case where `validateParticipant` returns null', async () => {
1049
1043
  expect.hasAssertions()
1050
1044
  // Arrange
1045
+ const logStub = sandbox.stub(logger.constructor.prototype, 'error')
1051
1046
  participant.validateParticipant = sandbox.stub().resolves(null)
1052
- sandbox.stub(Logger)
1053
- Logger.error = sandbox.stub()
1054
1047
  participant.sendErrorToParticipant = sandbox.stub()
1055
1048
  const headers = {
1056
1049
  accept: 'application/vnd.interoperability.participants+json;version=1',
@@ -1072,8 +1065,7 @@ describe('participant Tests', () => {
1072
1065
  await participantsDomain.postParticipants(headers, 'get', params, payload)
1073
1066
 
1074
1067
  // Assert
1075
- const loggerFirstCallArgs = Logger.error.getCall(0).args
1076
- expect(loggerFirstCallArgs[0]).toBe('Requester FSP not found')
1068
+ expect(logStub.getCall(0).args[0]).toBe(ERROR_MESSAGES.sourceFspNotFound)
1077
1069
  })
1078
1070
 
1079
1071
  it('handles case where type is not in `PartyAccountTypes`', async () => {
@@ -1202,7 +1194,7 @@ describe('participant Tests', () => {
1202
1194
 
1203
1195
  const headers = {
1204
1196
  accept: 'application/vnd.interoperability.participants+json;version=1',
1205
- 'fspiop-destination': Config.HUB_NAME,
1197
+ // 'fspiop-destination': Config.HUB_NAME,
1206
1198
  'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
1207
1199
  date: '2019-05-24 08:52:19',
1208
1200
  'fspiop-source': 'fsp1'
@@ -1318,15 +1310,23 @@ describe('participant Tests', () => {
1318
1310
  const expected = {
1319
1311
  currency: 'USD',
1320
1312
  partyList: [
1321
- ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND, undefined, undefined, undefined, [{
1322
- key: Enums.Accounts.PartyAccountTypes.MSISDN,
1323
- value: undefined
1324
- }]).toApiErrorObject(Config.ERROR_HANDLING),
1325
- ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, undefined, undefined, undefined, [{
1326
- key: 'NOT_A_VALID_PARTY_ID',
1327
- value: undefined
1328
- }]).toApiErrorObject(Config.ERROR_HANDLING),
1329
- { partyId: { currency: undefined } }
1313
+ {
1314
+ ...ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND, undefined, undefined, undefined, [{
1315
+ key: Enums.Accounts.PartyAccountTypes.MSISDN,
1316
+ value: undefined
1317
+ }]).toApiErrorObject(Config.ERROR_HANDLING),
1318
+ partyId: payload.partyList[1]
1319
+ },
1320
+ {
1321
+ ...ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, undefined, undefined, undefined, [{
1322
+ key: 'NOT_A_VALID_PARTY_ID',
1323
+ value: undefined
1324
+ }]).toApiErrorObject(Config.ERROR_HANDLING),
1325
+ partyId: payload.partyList[2]
1326
+ },
1327
+ {
1328
+ partyId: { currency: undefined }
1329
+ }
1330
1330
  ]
1331
1331
  }
1332
1332
 
@@ -1342,10 +1342,10 @@ describe('participant Tests', () => {
1342
1342
  it('handles error when `validateParticipant` fails and `sendErrorToParticipant` throws', async () => {
1343
1343
  expect.hasAssertions()
1344
1344
  // Arrange
1345
- sandbox.stub(Logger)
1346
- Logger.error = sandbox.stub()
1345
+ const logStub = sandbox.stub(logger.constructor.prototype, 'error')
1347
1346
  participant.validateParticipant = sandbox.stub().resolves(null)
1348
- participant.sendErrorToParticipant = sandbox.stub().throws(new Error('unknown error'))
1347
+ const cbError = new Error('unknown error')
1348
+ participant.sendErrorToParticipant = sandbox.stub().throws(cbError)
1349
1349
 
1350
1350
  const headers = {
1351
1351
  accept: 'application/vnd.interoperability.participants+json;version=1',
@@ -1368,10 +1368,8 @@ describe('participant Tests', () => {
1368
1368
  await participantsDomain.postParticipantsBatch(headers, 'get', payload, Helper.mockSpan())
1369
1369
 
1370
1370
  // Assert
1371
- const firstCallArgs = Logger.error.getCall(0).args
1372
- const thirdCallArgs = Logger.error.getCall(2).args
1373
- expect(firstCallArgs[0]).toBe('Requester FSP not found')
1374
- expect(thirdCallArgs[0].message).toBe('unknown error')
1371
+ expect(logStub.getCall(0).firstArg).toBe(ERROR_MESSAGES.sourceFspNotFound)
1372
+ expect(logStub.getCall(2).lastArg).toEqual(cbError)
1375
1373
  })
1376
1374
 
1377
1375
  it('handles error when `oracleBatchRequest` returns no result', async () => {
@@ -1447,6 +1445,44 @@ describe('participant Tests', () => {
1447
1445
  expect(firstCallArgs[4].partyList[1].errorInformation).toBeDefined()
1448
1446
  expect(firstCallArgs[4].partyList[2].errorInformation).toBeDefined()
1449
1447
  })
1448
+
1449
+ it('should not call oracle if source-header and fspId in payload are different, and no destination [CSI-938]', async () => {
1450
+ const headers = fixtures.participantsCallHeadersDto({ destination: '' })
1451
+ const payload = {
1452
+ requestId: '0e21b07e-3117-46ca-ae22-6ee370895697',
1453
+ currency: 'MWK',
1454
+ partyList: [
1455
+ {
1456
+ fspId: 'test-mwk-dfsp',
1457
+ partyIdType: 'MSISDN',
1458
+ partyIdentifier: '16665551002'
1459
+ }
1460
+ ]
1461
+ }
1462
+ expect(headers.source).not.toBe(payload.partyList[0].fspId)
1463
+ expect(headers.destination).toBeUndefined()
1464
+
1465
+ participant.validateParticipant = sandbox.stub().resolves({})
1466
+ participant.sendRequest = sandbox.stub()
1467
+ participant.sendErrorToParticipant = sandbox.stub().resolves({})
1468
+ oracle.oracleBatchRequest = sandbox.stub().resolves({})
1469
+
1470
+ await participantsDomain.postParticipantsBatch(headers, 'put', payload, Helper.mockSpan())
1471
+
1472
+ expect(oracle.oracleBatchRequest.callCount).toBe(0)
1473
+ expect(participant.sendErrorToParticipant.callCount).toBe(0)
1474
+ expect(participant.sendRequest.callCount).toBe(1)
1475
+
1476
+ const { args } = participant.sendRequest.getCall(0)
1477
+ expect(args[0][Headers.FSPIOP.DESTINATION]).toBe(headers[Headers.FSPIOP.SOURCE])
1478
+ expect(args[0][Headers.FSPIOP.SOURCE]).toBe(Config.HUB_NAME)
1479
+ expect(args[1]).toBe(headers[Headers.FSPIOP.SOURCE])
1480
+
1481
+ const { partyList } = args[4]
1482
+ expect(partyList.length).toBe(1)
1483
+ expect(partyList[0].errorInformation).toBeDefined()
1484
+ expect(partyList[0].partyId).toBe(payload.partyList[0])
1485
+ })
1450
1486
  })
1451
1487
 
1452
1488
  describe('deleteParticipants', () => {
@@ -1602,9 +1638,8 @@ describe('participant Tests', () => {
1602
1638
  it('handles the case where `validateParticipant` returns null', async () => {
1603
1639
  expect.hasAssertions()
1604
1640
  // Arrange
1641
+ const logStub = sandbox.stub(logger.constructor.prototype, 'error')
1605
1642
  participant.validateParticipant = sandbox.stub().resolves(null)
1606
- sandbox.stub(Logger)
1607
- Logger.error = sandbox.stub()
1608
1643
  participant.sendErrorToParticipant = sandbox.stub()
1609
1644
  const headers = {
1610
1645
  accept: 'application/vnd.interoperability.participants+json;version=1',
@@ -1625,8 +1660,8 @@ describe('participant Tests', () => {
1625
1660
  await participantsDomain.deleteParticipants(headers, params, method, query)
1626
1661
 
1627
1662
  // Assert
1628
- const loggerFirstCallArgs = Logger.error.getCall(0).args
1629
- expect(loggerFirstCallArgs[0]).toBe('Requester FSP not found')
1663
+ expect(logStub.getCall(0).firstArg).toBe(ERROR_MESSAGES.sourceFspNotFound)
1664
+ // expect(logStub.getCall()]).toBe(ERROR_MESSAGES.sourceFspNotFound)
1630
1665
  })
1631
1666
 
1632
1667
  it('handles case where type is not in `PartyAccountTypes`', async () => {
@@ -37,6 +37,7 @@ const { createProxyCache } = require('@mojaloop/inter-scheme-proxy-cache-lib')
37
37
  const { Enum, Util } = require('@mojaloop/central-services-shared')
38
38
  const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
39
39
  const Logger = require('@mojaloop/central-services-logger')
40
+ const Metrics = require('@mojaloop/central-services-metrics')
40
41
 
41
42
  const Config = require('../../../../src/lib/config')
42
43
  const Db = require('../../../../src/lib/db')
@@ -65,6 +66,13 @@ let sandbox
65
66
  describe('Parties Tests', () => {
66
67
  let proxyCache
67
68
 
69
+ // Initialize Metrics for testing
70
+ Metrics.getCounter(
71
+ 'errorCount',
72
+ 'Error count',
73
+ ['code', 'system', 'operation', 'step']
74
+ )
75
+
68
76
  beforeEach(async () => {
69
77
  await Util.Endpoints.initializeCache(Config.CENTRAL_SHARED_ENDPOINT_CACHE_CONFIG, libUtil.hubNameConfig)
70
78
  sandbox = Sinon.createSandbox()
@@ -613,7 +621,7 @@ describe('Parties Tests', () => {
613
621
  it('handles error when `participant.validateParticipant()` returns no participant', async () => {
614
622
  expect.hasAssertions()
615
623
  // Arrange
616
- const loggerStub = sandbox.stub(logger, 'error')
624
+ const loggerStub = sandbox.stub(logger.constructor.prototype, 'error')
617
625
  participant.sendErrorToParticipant = sandbox.stub().resolves()
618
626
 
619
627
  const payload = JSON.stringify({ testPayload: true })
@@ -874,7 +882,7 @@ describe('Parties Tests', () => {
874
882
  it('handles error when `validateParticipant()` fails', async () => {
875
883
  expect.hasAssertions()
876
884
  // Arrange)
877
- const loggerStub = sandbox.stub(logger.mlLogger, 'error')
885
+ const loggerStub = sandbox.stub(logger.constructor.prototype, 'error')
878
886
  participant.validateParticipant = sandbox.stub().throws(new Error('Validation fails'))
879
887
  participant.sendErrorToParticipant = sandbox.stub().resolves({})
880
888
  const payload = JSON.stringify({ errorPayload: true })
@@ -894,7 +902,7 @@ describe('Parties Tests', () => {
894
902
  expect.hasAssertions()
895
903
  // Arrange
896
904
 
897
- const loggerStub = sandbox.stub(logger.mlLogger, 'error')
905
+ const loggerStub = sandbox.stub(logger.constructor.prototype, 'error')
898
906
  participant.validateParticipant = sandbox.stub().throws(new Error('Validation fails'))
899
907
  participant.sendErrorToParticipant = sandbox.stub().resolves({})
900
908
  const payload = JSON.stringify({ errorPayload: true })
@@ -0,0 +1,60 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2017 Bill & Melinda Gates Foundation
5
+ The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
8
+
9
+ Contributors
10
+ --------------
11
+ This is the official list of the Mojaloop project contributors for this file.
12
+ Names of the original copyright holders (individuals or organizations)
13
+ should be listed with a '*' in the first column. People who have
14
+ contributed from an organization can be listed under the organization
15
+ that actually holds the copyright for their contributions (see the
16
+ Gates Foundation organization for an example). Those individuals should have
17
+ their names indented and be marked with a '-'. Email address can be added
18
+ optionally within square brackets <email>.
19
+ * Gates Foundation
20
+ - Name Surname <name.surname@gatesfoundation.com>
21
+
22
+ * Eugen Klymniuk <eugen.klymniuk@infitx.com>
23
+ --------------
24
+ **********/
25
+
26
+ const mockSendRequest = jest.fn()
27
+
28
+ jest.mock('@mojaloop/central-services-shared', () => ({
29
+ ...jest.requireActual('@mojaloop/central-services-shared'),
30
+ Util: {
31
+ ...jest.requireActual('@mojaloop/central-services-shared').Util,
32
+ Endpoints: { getEndpoint: jest.fn() },
33
+ Request: { sendRequest: mockSendRequest }
34
+ }
35
+ }))
36
+
37
+ const { API_TYPES } = require('@mojaloop/central-services-shared').Util.Hapi
38
+ const { logger } = require('../../../../src/lib')
39
+ const utils = require('../../../../src/domain/parties/utils')
40
+ const config = require('../../../../src/lib/config')
41
+ const fixtures = require('../../../fixtures')
42
+
43
+ describe('parties utils Tests -->', () => {
44
+ test('should send error party callback in ISO format', async () => {
45
+ const isoConfig = { ...config, API_TYPE: API_TYPES.iso20022 }
46
+ const err = new Error('test error')
47
+ const source = 'dfsp1'
48
+ const headers = fixtures.partiesCallHeadersDto({ source })
49
+ const params = { ID: '1234', Type: 'MSISDN' }
50
+
51
+ const handleError = utils.createErrorHandlerOnSendingCallback(isoConfig, logger)
52
+ await handleError(err, headers, params, source)
53
+
54
+ expect(mockSendRequest).toHaveBeenCalledTimes(1)
55
+ const { payload } = mockSendRequest.mock.calls[0][0]
56
+ expect(payload.Rpt.Rsn.Cd).toBe('2001')
57
+ expect(payload.Rpt.OrgnlId).toBe(`${params.Type}/${params.ID}`)
58
+ expect(payload.Assgnmt.Assgnr.Agt.FinInstnId.Othr.Id).toBe(source)
59
+ })
60
+ })
@@ -9,8 +9,7 @@ describe('timeoutCallbackDto Tests -->', () => {
9
9
  config.API_TYPE = realApiType
10
10
  })
11
11
 
12
- // todo: unskip after fixing transformLib SubId issue for parties.putError
13
- test.skip('should produce ISO payload', async () => {
12
+ test('should produce ISO payload', async () => {
14
13
  config.API_TYPE = API_TYPES.iso20022
15
14
  const destination = 'D1'
16
15
  const partyId = 'P1'
@@ -33,8 +33,16 @@
33
33
 
34
34
  const Participant = require('../../../../src/models/participantEndpoint/facade')
35
35
  const TimeoutDomain = require('../../../../src/domain/timeout')
36
+ const Metrics = require('@mojaloop/central-services-metrics')
36
37
 
37
38
  describe('Timeout Domain', () => {
39
+ // Initialize Metrics for testing
40
+ Metrics.getCounter(
41
+ 'errorCount',
42
+ 'Error count',
43
+ ['code', 'system', 'operation', 'step']
44
+ )
45
+
38
46
  beforeEach(() => {
39
47
  jest.clearAllMocks()
40
48
  jest.spyOn(Participant, 'validateParticipant').mockResolvedValue({})
@@ -5,10 +5,11 @@ describe('TransformFacades Tests -->', () => {
5
5
  test('should transform PUT /parties error callback payload to ISO format', async () => {
6
6
  const body = errorCallbackResponseDto()
7
7
  const headers = partiesCallHeadersDto()
8
+ TransformFacades.FSPIOP.configure({ isTestingMode: true })
8
9
  const isoPayload = await TransformFacades.FSPIOP.parties.putError({
9
10
  body,
10
11
  headers,
11
- params: { IdPath: '123456789' }
12
+ params: { Type: 'MSISDN', ID: '123456789' }
12
13
  })
13
14
  expect(isoPayload.body).toBeTruthy()
14
15
  expect(isoPayload.body.Assgnmt).toBeTruthy()
@@ -105,4 +105,11 @@ describe('Config tests', () => {
105
105
  expect(isSuccess).toBe(false)
106
106
  expect(error.message).toBe('File doesn\'t exist')
107
107
  })
108
+
109
+ it('should have FSPIOP_SOURCE_TO_SIGN config defined', () => {
110
+ process.env.ALS_ENDPOINT_SECURITY__JWS__JWS_SIGN = 'false' // to avoid error in config getFileContent()
111
+ const config = require(configImport)
112
+ expect(config.FSPIOP_SOURCE_TO_SIGN).toBeDefined()
113
+ expect(config.FSPIOP_SOURCE_TO_SIGN).toBe(config.HUB_NAME)
114
+ })
108
115
  })