account-lookup-service 15.6.0-snapshot.4 → 16.1.0-iso.0

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 (66) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE.md +3 -4
  3. package/README.md +2 -0
  4. package/audit-ci.jsonc +2 -27
  5. package/config/default.json +1 -0
  6. package/docker/mock-proxy/README.md +21 -0
  7. package/docker/mock-proxy/src/config.ts +7 -0
  8. package/docs/Proxy/Discovery.md +20 -0
  9. package/docs/Proxy/FXAPI_POC_payer_conversion_RECEIVE.plantuml +577 -0
  10. package/docs/Proxy/FXAPI_POC_payer_conversion_SEND.plantuml +1423 -0
  11. package/docs/Proxy/P2P.md +11 -0
  12. package/docs/Proxy/Proxy pattern - Happy path.plantuml +98 -0
  13. package/docs/Proxy/Proxy pattern - Lazy Discovery - No Oracles.plantuml +105 -0
  14. package/docs/Proxy/Proxy pattern - Lazy Discovery - No Oracles.png +0 -0
  15. package/docs/Proxy/Proxy pattern - Lazy Discovery - Oracles.plantuml +130 -0
  16. package/docs/Proxy/Proxy pattern - Lazy Discovery - Oracles.png +0 -0
  17. package/docs/Proxy/Proxy pattern - Lazy Discovery Identifier Cache Invalid.plantuml +72 -0
  18. package/docs/Proxy/Proxy pattern - Lazy Discovery Identifier Cache Invalid.png +0 -0
  19. package/docs/Proxy/Proxy pattern - P2P.plantuml +186 -0
  20. package/docs/Proxy/Proxy pattern - P2P.png +0 -0
  21. package/docs/Proxy/Proxy pattern - Unhappy path.plantuml +103 -0
  22. package/docs/Proxy/Proxy pattern - Unhappy path.png +0 -0
  23. package/docs/Proxy/Proxy pattern - happy path.png +0 -0
  24. package/docs/Proxy/Readme.md +39 -0
  25. package/docs/Proxy/SettingUpProxys.plantuml +31 -0
  26. package/docs/Proxy/SettingUpProxys.png +0 -0
  27. package/package.json +33 -18
  28. package/src/constants.js +2 -1
  29. package/src/domain/oracle/oracle.js +63 -4
  30. package/src/domain/participants/participants.js +246 -129
  31. package/src/domain/parties/getPartiesByTypeAndID.js +28 -7
  32. package/src/domain/parties/parties.js +32 -3
  33. package/src/domain/timeout/index.js +12 -1
  34. package/src/handlers/monitoring/index.js +1 -1
  35. package/src/interface/api-swagger-iso20022-parties.yaml +7 -6
  36. package/src/interface/api-swagger.yaml +7 -6
  37. package/src/lib/config.js +2 -1
  38. package/src/lib/db.js +2 -1
  39. package/src/models/currency/currency.js +10 -1
  40. package/src/models/endpointType/endpointType.js +10 -1
  41. package/src/models/oracle/facade.js +42 -16
  42. package/src/models/oracle/oracleEndpoint.js +65 -10
  43. package/src/models/oracle/oracleEndpointCached.js +29 -9
  44. package/src/models/participantEndpoint/facade.js +40 -4
  45. package/src/models/partyIdType/partyIdType.js +10 -1
  46. package/src/plugins.js +8 -21
  47. package/src/server.js +11 -0
  48. package/test/fixtures/index.js +30 -6
  49. package/test/unit/api/health.test.js +3 -0
  50. package/test/unit/api/participants/participants.test.js +5 -7
  51. package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +0 -3
  52. package/test/unit/api/participants/{Type}/{ID}.test.js +0 -3
  53. package/test/unit/api/participants.test.js +36 -3
  54. package/test/unit/domain/oracle/oracle.test.js +8 -0
  55. package/test/unit/domain/participants/participants.test.js +83 -48
  56. package/test/unit/domain/parties/parties.test.js +8 -0
  57. package/test/unit/domain/timeout/index.test.js +8 -0
  58. package/test/unit/lib/config.test.js +7 -0
  59. package/test/unit/mocks.js +16 -11
  60. package/test/unit/models/oracle/oracleEndpointCached.test.js +32 -0
  61. package/test/unit/plugins.test.js +2 -2
  62. package/src/lib/requestLogger.js +0 -54
  63. package/src/metrics/handler.js +0 -33
  64. package/src/metrics/plugin.js +0 -52
  65. package/src/metrics/routes.js +0 -43
  66. package/test/unit/lib/requestLogger.test.js +0 -115
@@ -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()
@@ -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({})
@@ -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
  })
@@ -1,10 +1,14 @@
1
1
  /*****
2
2
  License
3
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.
4
+ Copyright © 2020-2024 Mojaloop Foundation
5
+
6
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0
7
+ (the "License") and you may not use these files except in compliance with the [License](http://www.apache.org/licenses/LICENSE-2.0).
8
+
9
+ You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
10
+
11
+ 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](http://www.apache.org/licenses/LICENSE-2.0).
8
12
 
9
13
  Contributors
10
14
  --------------
@@ -16,6 +20,7 @@
16
20
  Gates Foundation organization for an example). Those individuals should have
17
21
  their names indented and be marked with a '-'. Email address can be added
18
22
  optionally within square brackets <email>.
23
+
19
24
  * Gates Foundation
20
25
  - Name Surname <name.surname@gatesfoundation.com>
21
26
 
@@ -26,13 +31,13 @@
26
31
  const RedisMock = require('ioredis-mock')
27
32
 
28
33
  /*
29
- ioredis-mock doesn't provide a status-field, so we need to override it here
30
- */
34
+ ioredis-mock doesn't provide a status-field, so we need to override it here
35
+ */
31
36
  class MockIoRedis extends RedisMock {
32
37
  connected = false
33
38
  /**
34
- @param opts RedisOptions
35
- */
39
+ @param opts RedisOptions
40
+ */
36
41
  constructor (opts) {
37
42
  super(opts)
38
43
  this.lazyConnect = Boolean(opts?.lazyConnect)
@@ -45,9 +50,9 @@ class MockIoRedis extends RedisMock {
45
50
 
46
51
  class IoRedisMockCluster extends MockIoRedis {
47
52
  /**
48
- @param nodesList BasicConnectionConfig[]
49
- @param redisOptions RedisClusterOptions
50
- */
53
+ @param nodesList BasicConnectionConfig[]
54
+ @param redisOptions RedisClusterOptions
55
+ */
51
56
  constructor (nodesList, redisOptions) {
52
57
  super(redisOptions)
53
58
  this._nodes = []
@@ -58,6 +58,7 @@ describe('ParticipantCurrency cached model', () => {
58
58
  sandbox.stub(OracleEndpointUncached, 'getOracleEndpointByTypeAndCurrency').returns(oracleEndpoints)
59
59
  sandbox.stub(OracleEndpointUncached, 'getOracleEndpointByCurrency').returns(oracleEndpoints)
60
60
  sandbox.stub(OracleEndpointUncached, 'getOracleEndpointByType').returns(oracleEndpoints)
61
+ sandbox.stub(OracleEndpointUncached, 'assertPendingAcquires').returns()
61
62
  })
62
63
 
63
64
  afterEach(() => {
@@ -150,4 +151,35 @@ describe('ParticipantCurrency cached model', () => {
150
151
  await Model.getOracleEndpointByTypeAndCurrency('MSISDN', 'USD')
151
152
  expect(cacheClient.get.called).toBeTruthy()
152
153
  })
154
+ it('getOracleEndpointCached calls assertPendingAcquire when assertPendingAcquire is true', async () => {
155
+ let cache = null
156
+ const cacheClient = {
157
+ createKey: sandbox.stub().returns({}),
158
+ get: () => cache,
159
+ set: (key, x) => {
160
+ cache = { item: x } // the cache returns {item: <data>} structure
161
+ }
162
+ }
163
+ Cache.registerCacheClient.returns(cacheClient)
164
+ await Model.initialize()
165
+
166
+ await Model.getOracleEndpointByTypeAndCurrency('MSISDN', 'USD', true)
167
+ expect(OracleEndpointUncached.assertPendingAcquires.calledOnce).toBeTruthy()
168
+ })
169
+
170
+ it('getOracleEndpointCached does not call assertPendingAcquire when assertPendingAcquire is false', async () => {
171
+ let cache = null
172
+ const cacheClient = {
173
+ createKey: sandbox.stub().returns({}),
174
+ get: () => cache,
175
+ set: (key, x) => {
176
+ cache = { item: x } // the cache returns {item: <data>} structure
177
+ }
178
+ }
179
+ Cache.registerCacheClient.returns(cacheClient)
180
+ await Model.initialize()
181
+
182
+ await Model.getOracleEndpointByTypeAndCurrency('MSISDN', 'USD', false)
183
+ expect(OracleEndpointUncached.assertPendingAcquires.called).toBeFalsy()
184
+ })
153
185
  })
@@ -64,7 +64,7 @@ describe('Plugin Tests', () => {
64
64
  await registerPlugins(server, api)
65
65
 
66
66
  // Assert
67
- expect(server.register.callCount).toBe(10)
67
+ expect(server.register.callCount).toBe(11)
68
68
  const firstCallArgs = server.register.getCall(1).args
69
69
  expect(firstCallArgs[0].options.document.info.title.includes('Open API for FSP Interoperability (FSPIOP) (Implementation Friendly Version)')).toBe(true)
70
70
  })
@@ -86,6 +86,6 @@ describe('Plugin Tests', () => {
86
86
  await registerPlugins(server, api)
87
87
 
88
88
  // Assert
89
- expect(server.register.callCount).toBe(9)
89
+ expect(server.register.callCount).toBe(10)
90
90
  })
91
91
  })
@@ -1,54 +0,0 @@
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
- Contributors
9
- --------------
10
- This is the official list of the Mojaloop project contributors for this file.
11
- Names of the original copyright holders (individuals or organizations)
12
- should be listed with a '*' in the first column. People who have
13
- contributed from an organization can be listed under the organization
14
- that actually holds the copyright for their contributions (see the
15
- Gates Foundation organization for an example). Those individuals should have
16
- their names indented and be marked with a '-'. Email address can be added
17
- optionally within square brackets <email>.
18
- * Gates Foundation
19
-
20
- * Rajiv Mothilal <rajiv.mothilal@modusbox.com>
21
-
22
- --------------
23
- ******/
24
-
25
- 'use strict'
26
-
27
- const { logger, asyncStorage } = require('./index')
28
-
29
- const logRequest = function (request) {
30
- const { path, method, headers, payload, query } = request
31
- const requestId = request.info.id = `${request.info.id}__${headers.traceid}`
32
- asyncStorage.enterWith({ requestId })
33
-
34
- logger.isInfoEnabled && logger.info(`[==> req] ${method.toUpperCase()} ${path}`, { headers, payload, query })
35
- }
36
-
37
- const logResponse = function (request) {
38
- if (logger.isInfoEnabled) {
39
- const { path, method, headers, payload, query, response } = request
40
- const { received } = request.info
41
-
42
- const statusCode = response instanceof Error
43
- ? response.output?.statusCode
44
- : response.statusCode
45
- const respTimeSec = ((Date.now() - received) / 1000).toFixed(3)
46
-
47
- logger.info(`[<== ${statusCode}][${respTimeSec} s] ${method.toUpperCase()} ${path}`, { headers, payload, query })
48
- }
49
- }
50
-
51
- module.exports = {
52
- logRequest,
53
- logResponse
54
- }
@@ -1,33 +0,0 @@
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
- Contributors
9
- --------------
10
- This is the official list of the Mojaloop project contributors for this file.
11
- Names of the original copyright holders (individuals or organizations)
12
- should be listed with a '*' in the first column. People who have
13
- contributed from an organization can be listed under the organization
14
- that actually holds the copyright for their contributions (see the
15
- Gates Foundation organization for an example). Those individuals should have
16
- their names indented and be marked with a '-'. Email address can be added
17
- optionally within square brackets <email>.
18
- * Gates Foundation
19
- - Name Surname <name.surname@gatesfoundation.com>
20
-
21
- - Pedro Barreto <pedrob@crosslaketech.com>
22
- - Rajiv Mothilal <rajivmothilal@gmail.com>
23
- - Shashikant Hirugade <shashikant.hirugade@modusbox.com>
24
- --------------
25
- ******/
26
-
27
- 'use strict'
28
-
29
- const Metrics = require('@mojaloop/central-services-metrics')
30
-
31
- exports.metrics = async function (request, h) {
32
- return h.response(await Metrics.getMetricsForPrometheus()).code(200)
33
- }
@@ -1,52 +0,0 @@
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
-
7
- http://www.apache.org/licenses/LICENSE-2.0
8
-
9
- 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.
10
-
11
- Contributors
12
- --------------
13
- This is the official list of the Mojaloop project contributors for this file.
14
- Names of the original copyright holders (individuals or organizations)
15
- should be listed with a '*' in the first column. People who have
16
- contributed from an organization can be listed under the organization
17
- that actually holds the copyright for their contributions (see the
18
- Gates Foundation organization for an example). Those individuals should have
19
- their names indented and be marked with a '-'. Email address can be added
20
- optionally within square brackets <email>.
21
-
22
- * Gates Foundation
23
- - Name Surname <name.surname@gatesfoundation.com>
24
-
25
- * Lazola Lucas <lazola.lucas@modusbox.com>
26
- * Rajiv Mothilal <rajiv.mothilal@modusbox.com>
27
- * Miguel de Barros <miguel.debarros@modusbox.com>
28
- * Shashikant Hirugade <shashikant.hirugade@modusbox.com>
29
-
30
- --------------
31
-
32
- ******/
33
- 'use strict'
34
-
35
- /**
36
- * @module src/metrics/plugin
37
- */
38
-
39
- /**
40
- * @function Register Handler Routes HAPI
41
- *
42
- * @async
43
- * @description Registers registers plugins on HAPI server. This retrieves all routes to be exposed from the routes.js file
44
- * @returns {Promise} - Returns a promise: resolve if successful, or rejection if failed
45
- */
46
-
47
- exports.plugin = {
48
- name: 'handler metrics routes',
49
- register: function (server) {
50
- server.route(require('./routes'))
51
- }
52
- }
@@ -1,43 +0,0 @@
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
- Contributors
9
- --------------
10
- This is the official list of the Mojaloop project contributors for this file.
11
- Names of the original copyright holders (individuals or organizations)
12
- should be listed with a '*' in the first column. People who have
13
- contributed from an organization can be listed under the organization
14
- that actually holds the copyright for their contributions (see the
15
- Gates Foundation organization for an example). Those individuals should have
16
- their names indented and be marked with a '-'. Email address can be added
17
- optionally within square brackets <email>.
18
- * Gates Foundation
19
- - Name Surname <name.surname@gatesfoundation.com>
20
-
21
- - Pedro Barreto <pedrob@crosslaketech.com>
22
- - Rajiv Mothilal <rajivmothilal@gmail.com>
23
- - Shashikant Hirugade <shashikant.hirugade@modusbox.com>
24
- --------------
25
- ******/
26
-
27
- 'use strict'
28
-
29
- const Handler = require('./handler')
30
- const tags = ['api', 'metrics']
31
-
32
- module.exports = [
33
- {
34
- method: 'GET',
35
- path: '/metrics',
36
- handler: Handler.metrics,
37
- config: {
38
- tags,
39
- description: 'Prometheus metrics endpoint',
40
- id: 'metrics'
41
- }
42
- }
43
- ]