account-lookup-service 17.7.0-snapshot.5 → 17.8.0-snapshot.6
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.
- package/CHANGELOG.md +7 -0
- package/package.json +2 -2
- package/src/domain/parties/services/BasePartiesService.js +8 -2
- package/src/domain/parties/services/TimeoutPartiesService.js +84 -0
- package/src/domain/parties/services/index.js +3 -1
- package/src/domain/timeout/createSpan.js +55 -0
- package/src/domain/timeout/index.js +21 -43
- package/test/fixtures/index.js +8 -0
- package/test/integration/domain/timeout/index.test.js +83 -28
- package/test/unit/domain/parties/services/BasePartiesService.test.js +1 -1
- package/test/unit/domain/parties/services/GetPartiesService.test.js +1 -1
- package/test/unit/domain/parties/services/PutPartiesErrorService.test.js +1 -0
- package/test/unit/domain/parties/services/TimeoutPartiesService.test.js +72 -0
- package/test/unit/domain/timeout/index.test.js +12 -7
- package/test/util/apiClients/BasicApiClient.js +33 -6
- package/test/util/apiClients/ProxyApiClient.js +46 -1
- package/test/util/mockDeps.js +9 -0
- package/src/domain/timeout/dto.js +0 -54
- package/test/unit/domain/timeout/dto.test.js +0 -24
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
4
4
|
|
5
|
+
## [17.7.0](https://github.com/mojaloop/account-lookup-service/compare/v17.6.0...v17.7.0) (2025-03-26)
|
6
|
+
|
7
|
+
|
8
|
+
### Features
|
9
|
+
|
10
|
+
* update dependencies to latest versions ([#542](https://github.com/mojaloop/account-lookup-service/issues/542)) ([8867742](https://github.com/mojaloop/account-lookup-service/commit/8867742e5e599f9a0de05eae095e2bd12e37d149))
|
11
|
+
|
5
12
|
## [17.6.0](https://github.com/mojaloop/account-lookup-service/compare/v17.5.0...v17.6.0) (2025-03-19)
|
6
13
|
|
7
14
|
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "account-lookup-service",
|
3
3
|
"description": "Account Lookup Service is used to validate Party and Participant lookups.",
|
4
|
-
"version": "17.
|
4
|
+
"version": "17.8.0-snapshot.6",
|
5
5
|
"license": "Apache-2.0",
|
6
6
|
"author": "ModusBox",
|
7
7
|
"contributors": [
|
@@ -106,7 +106,7 @@
|
|
106
106
|
"ajv-keywords": "5.1.0",
|
107
107
|
"blipp": "4.0.2",
|
108
108
|
"commander": "13.1.0",
|
109
|
-
"cron": "4.1.
|
109
|
+
"cron": "4.1.1",
|
110
110
|
"fast-safe-stringify": "^2.1.1",
|
111
111
|
"hapi-auth-bearer-token": "8.0.0",
|
112
112
|
"joi": "17.13.3",
|
@@ -186,9 +186,8 @@ class BasePartiesService {
|
|
186
186
|
}
|
187
187
|
|
188
188
|
static overrideDestinationHeader (headers, destination) {
|
189
|
-
const { [Headers.FSPIOP.DESTINATION]: _, ...restHeaders } = headers || {}
|
190
189
|
return {
|
191
|
-
...
|
190
|
+
...BasePartiesService.headersWithoutDestination(headers),
|
192
191
|
...(destination && { [Headers.FSPIOP.DESTINATION]: destination })
|
193
192
|
}
|
194
193
|
}
|
@@ -204,6 +203,13 @@ class BasePartiesService {
|
|
204
203
|
})
|
205
204
|
}
|
206
205
|
|
206
|
+
static createHubErrorCallbackHeaders (hubName, destination) {
|
207
|
+
return {
|
208
|
+
[Headers.FSPIOP.SOURCE]: hubName,
|
209
|
+
[Headers.FSPIOP.DESTINATION]: destination
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
207
213
|
static enums () {
|
208
214
|
return {
|
209
215
|
FspEndpointTypes,
|
@@ -0,0 +1,84 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
29
|
+
const { AuditEventAction } = require('@mojaloop/event-sdk')
|
30
|
+
const createSpan = require('../../timeout/createSpan') // todo: think, how to avoid this external deps
|
31
|
+
const PutPartiesErrorService = require('./PutPartiesErrorService')
|
32
|
+
|
33
|
+
class TimeoutPartiesService extends PutPartiesErrorService {
|
34
|
+
/**
|
35
|
+
* Should be used to get TimeoutPartiesService instance
|
36
|
+
*
|
37
|
+
* @param deps {PartiesDeps}
|
38
|
+
* @param cacheKey {string}
|
39
|
+
* @param spanName {string}
|
40
|
+
* @returns {TimeoutPartiesService}
|
41
|
+
*/
|
42
|
+
static createInstance (deps, cacheKey, spanName) {
|
43
|
+
const { destination, partyType, partyId } = TimeoutPartiesService.parseExpiredKey(cacheKey)
|
44
|
+
const headers = TimeoutPartiesService.createHubErrorCallbackHeaders(deps.config.HUB_NAME, destination)
|
45
|
+
const params = { Type: partyType, ID: partyId } // todo: think, if we need to handle party SubId
|
46
|
+
const childSpan = createSpan(spanName, headers, params)
|
47
|
+
|
48
|
+
return new TimeoutPartiesService({ ...deps, childSpan }, { headers, params })
|
49
|
+
}
|
50
|
+
|
51
|
+
async handleExpiredKey () {
|
52
|
+
const { errorInfo, headers, params } = await this.prepareErrorInformation()
|
53
|
+
this.#spanAuditStart(errorInfo)
|
54
|
+
|
55
|
+
await this.identifyDestinationForErrorCallback()
|
56
|
+
return super.sendErrorCallback({ errorInfo, headers, params })
|
57
|
+
}
|
58
|
+
|
59
|
+
async prepareErrorInformation () {
|
60
|
+
const { headers, params } = this.inputs
|
61
|
+
const error = TimeoutPartiesService.createFSPIOPExpiredError()
|
62
|
+
const errorInfo = await this.deps.partiesUtils.makePutPartiesErrorPayload(
|
63
|
+
this.deps.config, error, headers, params
|
64
|
+
)
|
65
|
+
this.log.verbose('prepareErrorInformation is done', { errorInfo, headers, params })
|
66
|
+
return { errorInfo, headers, params }
|
67
|
+
}
|
68
|
+
|
69
|
+
#spanAuditStart (errorInformation) {
|
70
|
+
const { headers } = this.inputs
|
71
|
+
this.deps.childSpan?.audit({ errorInformation, headers }, AuditEventAction.start)
|
72
|
+
}
|
73
|
+
|
74
|
+
static parseExpiredKey (cacheKey) {
|
75
|
+
const [destination, partyType, partyId] = cacheKey.split(':').slice(-3)
|
76
|
+
return { destination, partyType, partyId }
|
77
|
+
}
|
78
|
+
|
79
|
+
static createFSPIOPExpiredError () {
|
80
|
+
return ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.EXPIRED_ERROR)
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
module.exports = TimeoutPartiesService
|
@@ -28,9 +28,11 @@
|
|
28
28
|
const GetPartiesService = require('./GetPartiesService')
|
29
29
|
const PutPartiesService = require('./PutPartiesService')
|
30
30
|
const PutPartiesErrorService = require('./PutPartiesErrorService')
|
31
|
+
const TimeoutPartiesService = require('./TimeoutPartiesService')
|
31
32
|
|
32
33
|
module.exports = {
|
33
34
|
GetPartiesService,
|
34
35
|
PutPartiesService,
|
35
|
-
PutPartiesErrorService
|
36
|
+
PutPartiesErrorService,
|
37
|
+
TimeoutPartiesService
|
36
38
|
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const {
|
29
|
+
Events: { Event },
|
30
|
+
Tags: { QueryTags }
|
31
|
+
} = require('@mojaloop/central-services-shared').Enum
|
32
|
+
const { Tracer } = require('@mojaloop/event-sdk')
|
33
|
+
const EventFrameworkUtil = require('@mojaloop/central-services-shared').Util.EventFramework
|
34
|
+
|
35
|
+
const { getSpanTags } = require('../../lib/util')
|
36
|
+
|
37
|
+
const createSpan = (spanName, headers, params) => {
|
38
|
+
const span = Tracer.createSpan(spanName, { headers })
|
39
|
+
const spanTags = getSpanTags({ headers }, Event.Type.PARTY, Event.Action.PUT)
|
40
|
+
span.setTags(spanTags)
|
41
|
+
const queryTags = EventFrameworkUtil.Tags.getQueryTags(
|
42
|
+
QueryTags.serviceName.accountLookupService,
|
43
|
+
QueryTags.auditType.transactionFlow,
|
44
|
+
QueryTags.contentType.httpRequest,
|
45
|
+
QueryTags.operation.timeoutInterschemePartiesLookups,
|
46
|
+
{
|
47
|
+
partyIdType: params.Type,
|
48
|
+
partyIdentifier: params.ID
|
49
|
+
}
|
50
|
+
)
|
51
|
+
span.setTags(queryTags)
|
52
|
+
return span
|
53
|
+
}
|
54
|
+
|
55
|
+
module.exports = createSpan
|
@@ -31,73 +31,56 @@
|
|
31
31
|
******/
|
32
32
|
'use strict'
|
33
33
|
|
34
|
-
const {
|
35
|
-
|
36
|
-
Enums: { FSPIOPErrorCodes }
|
37
|
-
} = require('@mojaloop/central-services-error-handling')
|
38
|
-
const {
|
39
|
-
EventStateMetadata,
|
40
|
-
EventStatusType,
|
41
|
-
AuditEventAction
|
42
|
-
} = require('@mojaloop/event-sdk')
|
34
|
+
const { Factory: { reformatFSPIOPError } } = require('@mojaloop/central-services-error-handling')
|
35
|
+
const { EventStateMetadata, EventStatusType } = require('@mojaloop/event-sdk')
|
43
36
|
const Metrics = require('@mojaloop/central-services-metrics')
|
44
37
|
|
45
|
-
const Participant = require('../../models/participantEndpoint/facade')
|
46
|
-
const { ERROR_MESSAGES } = require('../../constants')
|
47
38
|
const { logger } = require('../../lib')
|
48
39
|
const { countFspiopError } = require('../../lib/util')
|
49
|
-
const {
|
40
|
+
const { createDeps } = require('../parties/deps')
|
41
|
+
const { TimeoutPartiesService } = require('../parties/services')
|
50
42
|
|
51
43
|
const timeoutInterschemePartiesLookups = async ({ proxyCache, batchSize }) => {
|
52
|
-
|
53
|
-
|
44
|
+
const operation = timeoutInterschemePartiesLookups.name
|
45
|
+
logger.info(`${operation} start...`, { batchSize })
|
46
|
+
return proxyCache.processExpiredAlsKeys(
|
47
|
+
(key) => sendTimeoutCallback(key, proxyCache, operation), batchSize
|
48
|
+
)
|
54
49
|
}
|
55
50
|
|
56
51
|
const timeoutProxyGetPartiesLookups = async ({ proxyCache, batchSize }) => {
|
57
|
-
|
58
|
-
|
52
|
+
const operation = timeoutProxyGetPartiesLookups.name
|
53
|
+
logger.info(`${operation} start...`, { batchSize })
|
54
|
+
return proxyCache.processExpiredProxyGetPartiesKeys(
|
55
|
+
(key) => sendTimeoutCallback(key, proxyCache, operation), batchSize
|
56
|
+
)
|
59
57
|
}
|
60
58
|
|
61
|
-
const sendTimeoutCallback = async (cacheKey) => {
|
59
|
+
const sendTimeoutCallback = async (cacheKey, proxyCache, operation) => {
|
62
60
|
const histTimerEnd = Metrics.getHistogram(
|
63
61
|
'eg_timeoutInterschemePartiesLookups',
|
64
62
|
'Egress - Interscheme parties lookup timeout callback',
|
65
63
|
['success']
|
66
64
|
).startTimer()
|
67
|
-
|
68
|
-
const
|
69
|
-
const
|
70
|
-
const
|
71
|
-
log.verbose('sendTimeoutCallback details:', { errorInformation, cacheKey, partyType })
|
65
|
+
const log = logger.child({ cacheKey, operation })
|
66
|
+
const deps = createDeps({ proxyCache, log })
|
67
|
+
const service = TimeoutPartiesService.createInstance(deps, cacheKey, operation)
|
68
|
+
const span = service.deps.childSpan
|
72
69
|
|
73
70
|
try {
|
74
|
-
|
75
|
-
await validateParticipant(destination, log)
|
76
|
-
await span.audit({ headers, errorInformation }, AuditEventAction.start)
|
77
|
-
step = 'sendErrorToParticipant-2'
|
78
|
-
await Participant.sendErrorToParticipant(destination, endpointType, errorInformation, headers, params, undefined, span)
|
71
|
+
await service.handleExpiredKey()
|
79
72
|
histTimerEnd({ success: true })
|
80
73
|
} catch (err) {
|
81
74
|
log.warn('error in sendTimeoutCallback: ', err)
|
82
75
|
histTimerEnd({ success: false })
|
83
76
|
const fspiopError = reformatFSPIOPError(err)
|
84
|
-
countFspiopError(fspiopError, { operation
|
77
|
+
countFspiopError(fspiopError, { operation, step: service?.currenStep })
|
85
78
|
|
86
79
|
await finishSpan(span, fspiopError)
|
87
80
|
throw fspiopError
|
88
81
|
}
|
89
82
|
}
|
90
83
|
|
91
|
-
const validateParticipant = async (fspId, log) => {
|
92
|
-
const participant = await Participant.validateParticipant(fspId)
|
93
|
-
if (!participant) {
|
94
|
-
const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
|
95
|
-
log.error(`error in validateParticipant: ${errMessage}`)
|
96
|
-
throw createFSPIOPError(FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
|
97
|
-
}
|
98
|
-
return participant
|
99
|
-
}
|
100
|
-
|
101
84
|
const finishSpan = async (span, err) => {
|
102
85
|
if (!span.isFinished) {
|
103
86
|
const state = new EventStateMetadata(
|
@@ -110,11 +93,6 @@ const finishSpan = async (span, err) => {
|
|
110
93
|
}
|
111
94
|
}
|
112
95
|
|
113
|
-
const parseCacheKey = (cacheKey) => {
|
114
|
-
const [destination, partyType, partyId] = cacheKey.split(':').slice(-3)
|
115
|
-
return [destination, partyType, partyId]
|
116
|
-
}
|
117
|
-
|
118
96
|
module.exports = {
|
119
97
|
timeoutInterschemePartiesLookups,
|
120
98
|
timeoutProxyGetPartiesLookups,
|
package/test/fixtures/index.js
CHANGED
@@ -163,6 +163,13 @@ const mockAlsRequestDto = (sourceId, type, partyId) => ({
|
|
163
163
|
partyId
|
164
164
|
})
|
165
165
|
|
166
|
+
const expiredCacheKeyDto = ({
|
167
|
+
sourceId = 'sourceId',
|
168
|
+
type = 'MSISDN',
|
169
|
+
partyId = 'partyId-123',
|
170
|
+
prefix = 'prefix'
|
171
|
+
} = {}) => `${prefix}:${sourceId}:${type}:${partyId}`
|
172
|
+
|
166
173
|
const mockHapiRequestDto = ({ // https://hapi.dev/api/?v=21.3.3#request-properties
|
167
174
|
method = 'GET',
|
168
175
|
traceid = randomUUID(),
|
@@ -185,6 +192,7 @@ module.exports = {
|
|
185
192
|
putPartiesSuccessResponseDto,
|
186
193
|
postParticipantsPayloadDto,
|
187
194
|
errorCallbackResponseDto,
|
195
|
+
expiredCacheKeyDto,
|
188
196
|
mockAlsRequestDto,
|
189
197
|
protocolVersionsDto,
|
190
198
|
mockHapiRequestDto,
|
@@ -1,18 +1,50 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
1
28
|
const { createProxyCache } = require('@mojaloop/inter-scheme-proxy-cache-lib')
|
2
|
-
const {
|
29
|
+
const { RedisProxyCache } = require('@mojaloop/inter-scheme-proxy-cache-lib/dist/lib/storages/RedisProxyCache')
|
30
|
+
const config = require('#src/lib/config')
|
3
31
|
const fixtures = require('../../../fixtures')
|
4
32
|
const { ProxyApiClient } = require('../../../util')
|
5
|
-
const
|
33
|
+
const { PAYER_DFSP, PARTY_ID_TYPE, PROXY_NAME } = require('../../constants')
|
6
34
|
|
7
35
|
const wait = (sec) => new Promise(resolve => setTimeout(resolve, sec * 1000))
|
8
36
|
|
9
37
|
const CRON_TIMEOUT_SEC = 15 // see TIMEXP
|
10
38
|
|
39
|
+
jest.setTimeout(60_000)
|
40
|
+
|
11
41
|
describe('Timeout Handler', () => {
|
12
42
|
const { type, proxyConfig } = config.PROXY_CACHE_CONFIG
|
13
43
|
const proxyCache = createProxyCache(type, proxyConfig)
|
14
44
|
const proxyClient = new ProxyApiClient()
|
15
45
|
|
46
|
+
const checkKeysExistence = async (keys) => Promise.all(keys.map(key => proxyCache.redisClient.exists(key)))
|
47
|
+
|
16
48
|
beforeAll(async () => {
|
17
49
|
await proxyCache.connect()
|
18
50
|
const redisClient = proxyCache.redisClient
|
@@ -22,6 +54,11 @@ describe('Timeout Handler', () => {
|
|
22
54
|
}))
|
23
55
|
})
|
24
56
|
|
57
|
+
beforeEach(async () => {
|
58
|
+
const history = await proxyClient.deleteHistory()
|
59
|
+
expect(history).toEqual([])
|
60
|
+
})
|
61
|
+
|
25
62
|
afterAll(async () => {
|
26
63
|
return Promise.all([
|
27
64
|
proxyClient.deleteHistory(),
|
@@ -29,47 +66,65 @@ describe('Timeout Handler', () => {
|
|
29
66
|
])
|
30
67
|
})
|
31
68
|
|
32
|
-
it('
|
33
|
-
|
34
|
-
expect(history).toEqual([])
|
35
|
-
|
36
|
-
// send a couple of keys to redis
|
37
|
-
const partyIds = ['1234567', '7654321']
|
38
|
-
const keys = [
|
39
|
-
`'als:${PAYER_DFSP}:${PARTY_ID_TYPE}:${partyIds[0]}:expiresAt'`,
|
40
|
-
`'als:${PAYER_DFSP}:${PARTY_ID_TYPE}:${partyIds[1]}:expiresAt'`
|
41
|
-
]
|
69
|
+
it('should pass timeoutInterschemePartiesLookups flow', async () => {
|
70
|
+
const partyIds = [`isp1-${Date.now()}`, `isp2-${Date.now()}`]
|
42
71
|
const proxies = [PROXY_NAME]
|
43
72
|
const alsReq1 = fixtures.mockAlsRequestDto(PAYER_DFSP, PARTY_ID_TYPE, partyIds[0])
|
44
73
|
const alsReq2 = fixtures.mockAlsRequestDto(PAYER_DFSP, PARTY_ID_TYPE, partyIds[1])
|
74
|
+
const keys = [
|
75
|
+
RedisProxyCache.formatAlsCacheExpiryKey(alsReq1),
|
76
|
+
RedisProxyCache.formatAlsCacheExpiryKey(alsReq2)
|
77
|
+
]
|
78
|
+
// send a couple of keys to redis
|
45
79
|
const results = await Promise.all([
|
46
80
|
proxyCache.setSendToProxiesList(alsReq1, proxies, CRON_TIMEOUT_SEC),
|
47
81
|
proxyCache.setSendToProxiesList(alsReq2, proxies, CRON_TIMEOUT_SEC)
|
48
82
|
])
|
49
|
-
expect(results
|
83
|
+
expect(results).toEqual([true, true])
|
84
|
+
expect(await checkKeysExistence(keys)).toEqual([1, 1])
|
50
85
|
|
51
86
|
// wait for the timeout handler to process the keys
|
52
87
|
await wait(CRON_TIMEOUT_SEC * 1.5)
|
88
|
+
const history = await proxyClient.waitForNHistoryCalls(2)
|
53
89
|
|
54
90
|
// check that the keys are no longer in redis
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
// check that the callbacks are sent and received at the FSP
|
59
|
-
// for test resilience, we will retry the history check a few times
|
60
|
-
const retryMaxCount = 20
|
61
|
-
const retryIntervalSec = 2
|
62
|
-
let retryCount = 0
|
63
|
-
|
64
|
-
while (history.length < 2 && retryCount < retryMaxCount) {
|
65
|
-
await wait(retryIntervalSec)
|
66
|
-
history = await proxyClient.getHistory()
|
67
|
-
retryCount++
|
68
|
-
}
|
91
|
+
expect(await checkKeysExistence(keys)).toEqual([0, 0])
|
92
|
+
|
69
93
|
expect(history.length).toBe(2)
|
70
94
|
const path0 = history.find(h => h.path.includes(partyIds[0])).path
|
71
95
|
const path1 = history.find(h => h.path.includes(partyIds[1])).path
|
72
96
|
expect(path0).toBe(`/parties/${PARTY_ID_TYPE}/${partyIds[0]}/error`)
|
73
97
|
expect(path1).toBe(`/parties/${PARTY_ID_TYPE}/${partyIds[1]}/error`)
|
74
|
-
}
|
98
|
+
})
|
99
|
+
|
100
|
+
it('should pass timeoutProxyGetPartiesLookups flow', async () => {
|
101
|
+
const partyId1 = `pgp1-${Date.now()}`
|
102
|
+
const partyId2 = `pgp2-${Date.now()}`
|
103
|
+
const alsReq1 = fixtures.mockAlsRequestDto(PAYER_DFSP, PARTY_ID_TYPE, partyId1)
|
104
|
+
const alsReq2 = fixtures.mockAlsRequestDto(PAYER_DFSP, PARTY_ID_TYPE, partyId2)
|
105
|
+
const keys = [
|
106
|
+
RedisProxyCache.formatProxyGetPartiesExpiryKey(alsReq1, PROXY_NAME),
|
107
|
+
RedisProxyCache.formatProxyGetPartiesExpiryKey(alsReq2, PROXY_NAME)
|
108
|
+
]
|
109
|
+
// send a couple of keys to redis
|
110
|
+
const results = await Promise.all([
|
111
|
+
proxyCache.setProxyGetPartiesTimeout(alsReq1, PROXY_NAME, CRON_TIMEOUT_SEC),
|
112
|
+
proxyCache.setProxyGetPartiesTimeout(alsReq2, PROXY_NAME, CRON_TIMEOUT_SEC)
|
113
|
+
])
|
114
|
+
expect(results).toEqual([true, true])
|
115
|
+
expect(await checkKeysExistence(keys)).toEqual([1, 1])
|
116
|
+
|
117
|
+
// wait for the timeout handler to process the keys
|
118
|
+
await wait(CRON_TIMEOUT_SEC * 1.5)
|
119
|
+
const history = await proxyClient.waitForNHistoryCalls(2)
|
120
|
+
|
121
|
+
// check that the keys are no longer in redis
|
122
|
+
expect(await checkKeysExistence(keys)).toEqual([0, 0])
|
123
|
+
|
124
|
+
expect(history.length).toBe(2)
|
125
|
+
const path1 = history.find(h => h.path.includes(partyId1)).path
|
126
|
+
const path2 = history.find(h => h.path.includes(partyId2)).path
|
127
|
+
expect(path1).toBe(`/parties/${PARTY_ID_TYPE}/${partyId1}/error`)
|
128
|
+
expect(path2).toBe(`/parties/${PARTY_ID_TYPE}/${partyId2}/error`)
|
129
|
+
})
|
75
130
|
})
|
@@ -26,7 +26,7 @@
|
|
26
26
|
******/
|
27
27
|
|
28
28
|
const { createMockDeps, participantMock } = require('./deps')
|
29
|
-
// should be first require to mock external deps
|
29
|
+
// ↑ should be first require to mock external deps ↑
|
30
30
|
const BasePartiesService = require('#src/domain/parties/services/BasePartiesService')
|
31
31
|
const config = require('#src/lib/config')
|
32
32
|
const { API_TYPES } = require('#src/constants')
|
@@ -26,7 +26,7 @@
|
|
26
26
|
******/
|
27
27
|
|
28
28
|
const { createMockDeps, createProxyCacheMock, oracleMock, participantMock } = require('./deps')
|
29
|
-
// should be first require to mock external deps
|
29
|
+
// ↑ should be first require to mock external deps ↑
|
30
30
|
const { GetPartiesService } = require('#src/domain/parties/services/index')
|
31
31
|
const fixtures = require('#test/fixtures/index')
|
32
32
|
|
@@ -26,6 +26,7 @@
|
|
26
26
|
******/
|
27
27
|
|
28
28
|
const { createMockDeps, oracleMock } = require('./deps')
|
29
|
+
// ↑ should be first require to mock external deps ↑
|
29
30
|
const { PutPartiesErrorService } = require('#src/domain/parties/services/index')
|
30
31
|
const fixtures = require('#test/fixtures/index')
|
31
32
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const { createMockDeps, createProxyCacheMock, participantMock } = require('./deps')
|
29
|
+
// ↑ should be first require to mock external deps ↑
|
30
|
+
const { TimeoutPartiesService } = require('#src/domain/parties/services/index')
|
31
|
+
const { API_TYPES } = require('#src/constants')
|
32
|
+
const fixtures = require('#test/fixtures/index')
|
33
|
+
|
34
|
+
describe('TimeoutPartiesService Tests -->', () => {
|
35
|
+
const { config } = createMockDeps()
|
36
|
+
|
37
|
+
beforeEach(() => {
|
38
|
+
jest.clearAllMocks()
|
39
|
+
})
|
40
|
+
|
41
|
+
test('should send error callback to external participant through proxy', async () => {
|
42
|
+
participantMock.validateParticipant = jest.fn().mockResolvedValue(null)
|
43
|
+
const proxy = 'proxyAB'
|
44
|
+
const proxyCache = createProxyCacheMock({
|
45
|
+
lookupProxyByDfspId: jest.fn().mockResolvedValue(proxy)
|
46
|
+
})
|
47
|
+
const deps = createMockDeps({ proxyCache })
|
48
|
+
const cacheKey = fixtures.expiredCacheKeyDto()
|
49
|
+
const service = TimeoutPartiesService.createInstance(deps, cacheKey, 'test')
|
50
|
+
|
51
|
+
await service.handleExpiredKey()
|
52
|
+
expect(participantMock.sendErrorToParticipant).toHaveBeenCalledTimes(1)
|
53
|
+
expect(participantMock.sendErrorToParticipant.mock.lastCall[0]).toBe(proxy)
|
54
|
+
})
|
55
|
+
|
56
|
+
test('should send error callback in ISO20022 format', async () => {
|
57
|
+
participantMock.validateParticipant = jest.fn().mockResolvedValue({})
|
58
|
+
const deps = {
|
59
|
+
...createMockDeps(),
|
60
|
+
config: { ...config, API_TYPE: API_TYPES.iso20022 }
|
61
|
+
}
|
62
|
+
const sourceId = 'sourceFsp'
|
63
|
+
const cacheKey = fixtures.expiredCacheKeyDto({ sourceId })
|
64
|
+
const service = TimeoutPartiesService.createInstance(deps, cacheKey, 'test')
|
65
|
+
|
66
|
+
await service.handleExpiredKey()
|
67
|
+
expect(participantMock.sendErrorToParticipant).toHaveBeenCalledTimes(1)
|
68
|
+
const { Assgnr, Assgne } = participantMock.sendErrorToParticipant.mock.lastCall[2].Assgnmt
|
69
|
+
expect(Assgnr.Agt.FinInstnId.Othr.Id).toBe(config.HUB_NAME)
|
70
|
+
expect(Assgne.Agt.FinInstnId.Othr.Id).toBe(sourceId)
|
71
|
+
})
|
72
|
+
})
|
@@ -31,11 +31,13 @@
|
|
31
31
|
|
32
32
|
'use strict'
|
33
33
|
|
34
|
-
const Participant = require('../../../../src/models/participantEndpoint/facade')
|
35
|
-
const TimeoutDomain = require('../../../../src/domain/timeout')
|
36
34
|
const Metrics = require('@mojaloop/central-services-metrics')
|
35
|
+
const Participant = require('#src/models/participantEndpoint/facade')
|
36
|
+
const TimeoutDomain = require('#src/domain/timeout/index')
|
37
|
+
const { mockDeps } = require('#test/util/index')
|
37
38
|
|
38
39
|
describe('Timeout Domain', () => {
|
40
|
+
const proxyCache = mockDeps.createProxyCacheMock()
|
39
41
|
// Initialize Metrics for testing
|
40
42
|
Metrics.getCounter(
|
41
43
|
'errorCount',
|
@@ -56,9 +58,10 @@ describe('Timeout Domain', () => {
|
|
56
58
|
describe('timeoutInterschemePartiesLookups', () => {
|
57
59
|
describe('timeoutInterschemePartiesLookups', () => {
|
58
60
|
it('should process expired ALS keys', async () => {
|
59
|
-
const
|
60
|
-
await TimeoutDomain.timeoutInterschemePartiesLookups({ proxyCache
|
61
|
-
expect(
|
61
|
+
const batchSize = 10
|
62
|
+
await TimeoutDomain.timeoutInterschemePartiesLookups({ proxyCache, batchSize })
|
63
|
+
expect(proxyCache.processExpiredAlsKeys).toHaveBeenCalledWith(expect.any(Function), batchSize)
|
64
|
+
expect(Participant.sendErrorToParticipant).toHaveBeenCalled()
|
62
65
|
})
|
63
66
|
})
|
64
67
|
|
@@ -69,7 +72,7 @@ describe('Timeout Domain', () => {
|
|
69
72
|
|
70
73
|
const cacheKey = `als:${SOURCE_ID}:2:3` // ':expiresAt' part is removed inside proxyCache.processExpiryKey()
|
71
74
|
|
72
|
-
await TimeoutDomain.sendTimeoutCallback(cacheKey)
|
75
|
+
await TimeoutDomain.sendTimeoutCallback(cacheKey, proxyCache)
|
73
76
|
|
74
77
|
expect(Participant.validateParticipant).toHaveBeenCalledWith(SOURCE_ID)
|
75
78
|
expect(Participant.sendErrorToParticipant).toHaveBeenCalledWith(
|
@@ -82,7 +85,9 @@ describe('Timeout Domain', () => {
|
|
82
85
|
|
83
86
|
it('should throw error if participant validation fails', async () => {
|
84
87
|
Participant.validateParticipant.mockResolvedValue(null)
|
85
|
-
await expect(
|
88
|
+
await expect(
|
89
|
+
TimeoutDomain.sendTimeoutCallback('als:sourceId:2:3:expiresAt', proxyCache)
|
90
|
+
).rejects.toThrow()
|
86
91
|
})
|
87
92
|
})
|
88
93
|
})
|
@@ -1,16 +1,43 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
1
28
|
const axiosLib = require('axios')
|
2
|
-
const
|
3
|
-
const fixtures = require('
|
29
|
+
const { logger } = require('#src/lib/index')
|
30
|
+
const fixtures = require('#test/fixtures/index')
|
4
31
|
|
5
32
|
class BasicApiClient {
|
6
33
|
constructor ({
|
7
34
|
baseURL,
|
8
35
|
axios = axiosLib.create({ baseURL }),
|
9
|
-
|
36
|
+
log = logger.child({ component: this.constructor.name })
|
10
37
|
} = {}) {
|
11
38
|
this.baseURL = baseURL
|
12
39
|
this.axios = axios
|
13
|
-
this.
|
40
|
+
this.log = log
|
14
41
|
this.fixtures = fixtures
|
15
42
|
}
|
16
43
|
|
@@ -22,10 +49,10 @@ class BasicApiClient {
|
|
22
49
|
headers,
|
23
50
|
data: body
|
24
51
|
})
|
25
|
-
this.
|
52
|
+
this.log.info(`sendRequest is done [${method} ${url}]:`, { method, url, body, headers, response: { status, data } })
|
26
53
|
return { data, status }
|
27
54
|
} catch (err) {
|
28
|
-
this.
|
55
|
+
this.log.error('error in sendRequest: ', err)
|
29
56
|
throw err
|
30
57
|
}
|
31
58
|
}
|
@@ -1,4 +1,32 @@
|
|
1
|
-
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const { setTimeout: sleep } = require('node:timers/promises')
|
29
|
+
const { PROXY_PORT } = require('#test/integration/constants')
|
2
30
|
const BasicApiClient = require('./BasicApiClient')
|
3
31
|
|
4
32
|
const baseURL = `http://localhost:${PROXY_PORT}`
|
@@ -10,6 +38,7 @@ class ProxyApiClient extends BasicApiClient {
|
|
10
38
|
|
11
39
|
async getHistory () {
|
12
40
|
const { data } = await this.sendRequest({ url: '/history' })
|
41
|
+
this.log.verbose('getHistory response data: ', { data })
|
13
42
|
return data.history
|
14
43
|
}
|
15
44
|
|
@@ -20,6 +49,22 @@ class ProxyApiClient extends BasicApiClient {
|
|
20
49
|
})
|
21
50
|
return data.history
|
22
51
|
}
|
52
|
+
|
53
|
+
async waitForNHistoryCalls (N, retryMaxCount = 20, retryIntervalSec = 2) {
|
54
|
+
// check that the callbacks are sent and received at the FSP
|
55
|
+
// for test resilience, we will retry the history check a few times
|
56
|
+
let retryCount = 0
|
57
|
+
let history = []
|
58
|
+
|
59
|
+
while (history.length < N && retryCount < retryMaxCount) {
|
60
|
+
await sleep(retryIntervalSec * 1000)
|
61
|
+
history = await this.getHistory()
|
62
|
+
retryCount++
|
63
|
+
}
|
64
|
+
this.log.info('waitForNHistoryCalls is done: ', { history })
|
65
|
+
|
66
|
+
return history
|
67
|
+
}
|
23
68
|
}
|
24
69
|
|
25
70
|
module.exports = ProxyApiClient
|
package/test/util/mockDeps.js
CHANGED
@@ -25,10 +25,17 @@
|
|
25
25
|
--------------
|
26
26
|
******/
|
27
27
|
|
28
|
+
const fixtures = require('../fixtures')
|
29
|
+
|
30
|
+
// eslint-disable-next-line n/no-callback-literal
|
31
|
+
const processExpierdKeysFn = async (cb) => cb(fixtures.expiredCacheKeyDto())
|
32
|
+
|
28
33
|
const createProxyCacheMock = ({
|
29
34
|
addDfspIdToProxyMapping = jest.fn(async () => true),
|
30
35
|
isPendingCallback = jest.fn(async () => false),
|
31
36
|
lookupProxyByDfspId = jest.fn(async () => null),
|
37
|
+
processExpiredAlsKeys = jest.fn(processExpierdKeysFn),
|
38
|
+
processExpiredProxyGetPartiesKeys = jest.fn(processExpierdKeysFn),
|
32
39
|
receivedErrorResponse = jest.fn(async () => false),
|
33
40
|
receivedSuccessResponse = jest.fn(async () => true),
|
34
41
|
removeDfspIdFromProxyMapping = jest.fn(async () => true),
|
@@ -39,6 +46,8 @@ const createProxyCacheMock = ({
|
|
39
46
|
addDfspIdToProxyMapping,
|
40
47
|
isPendingCallback,
|
41
48
|
lookupProxyByDfspId,
|
49
|
+
processExpiredAlsKeys,
|
50
|
+
processExpiredProxyGetPartiesKeys,
|
42
51
|
receivedErrorResponse,
|
43
52
|
receivedSuccessResponse,
|
44
53
|
removeDfspIdFromProxyMapping,
|
@@ -1,54 +0,0 @@
|
|
1
|
-
const {
|
2
|
-
Factory: { createFSPIOPError },
|
3
|
-
Enums: { FSPIOPErrorCodes }
|
4
|
-
} = require('@mojaloop/central-services-error-handling')
|
5
|
-
const {
|
6
|
-
Http: { Headers: { FSPIOP: FSPIOPHeaders } },
|
7
|
-
Events: { Event: { Type: EventType, Action: EventAction } },
|
8
|
-
EndPoints: { FspEndpointTypes },
|
9
|
-
Tags: { QueryTags: QueryTagsEnum }
|
10
|
-
} = require('@mojaloop/central-services-shared').Enum
|
11
|
-
const { Tracer } = require('@mojaloop/event-sdk')
|
12
|
-
const EventFrameworkUtil = require('@mojaloop/central-services-shared').Util.EventFramework
|
13
|
-
|
14
|
-
const LibUtil = require('../../lib/util')
|
15
|
-
const Config = require('../../lib/config')
|
16
|
-
const partiesUtils = require('../parties/partiesUtils')
|
17
|
-
|
18
|
-
const timeoutCallbackDto = async ({ destination, partyId, partyType }) => {
|
19
|
-
const headers = {
|
20
|
-
[FSPIOPHeaders.SOURCE]: Config.HUB_NAME,
|
21
|
-
[FSPIOPHeaders.DESTINATION]: destination
|
22
|
-
}
|
23
|
-
const params = {
|
24
|
-
ID: partyId,
|
25
|
-
Type: partyType
|
26
|
-
}
|
27
|
-
const error = createFSPIOPError(FSPIOPErrorCodes.EXPIRED_ERROR)
|
28
|
-
|
29
|
-
const dto = {
|
30
|
-
errorInformation: await partiesUtils.makePutPartiesErrorPayload(Config, error, headers, params),
|
31
|
-
headers,
|
32
|
-
params,
|
33
|
-
endpointType: FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR
|
34
|
-
}
|
35
|
-
const span = Tracer.createSpan('timeoutInterschemePartiesLookups', { headers: dto.headers })
|
36
|
-
const spanTags = LibUtil.getSpanTags({ headers: dto.headers }, EventType.PARTY, EventAction.PUT)
|
37
|
-
span.setTags(spanTags)
|
38
|
-
const queryTags = EventFrameworkUtil.Tags.getQueryTags(
|
39
|
-
QueryTagsEnum.serviceName.accountLookupService,
|
40
|
-
QueryTagsEnum.auditType.transactionFlow,
|
41
|
-
QueryTagsEnum.contentType.httpRequest,
|
42
|
-
QueryTagsEnum.operation.timeoutInterschemePartiesLookups,
|
43
|
-
{
|
44
|
-
partyIdType: params.Type,
|
45
|
-
partyIdentifier: params.ID
|
46
|
-
}
|
47
|
-
)
|
48
|
-
span.setTags(queryTags)
|
49
|
-
return { ...dto, span }
|
50
|
-
}
|
51
|
-
|
52
|
-
module.exports = {
|
53
|
-
timeoutCallbackDto
|
54
|
-
}
|
@@ -1,24 +0,0 @@
|
|
1
|
-
const { API_TYPES } = require('@mojaloop/central-services-shared').Util.Hapi
|
2
|
-
const { timeoutCallbackDto } = require('../../../../src/domain/timeout/dto')
|
3
|
-
const config = require('../../../../src/lib/config')
|
4
|
-
|
5
|
-
const realApiType = config.API_TYPE
|
6
|
-
|
7
|
-
describe('timeoutCallbackDto Tests -->', () => {
|
8
|
-
afterAll(() => {
|
9
|
-
config.API_TYPE = realApiType
|
10
|
-
})
|
11
|
-
|
12
|
-
test('should produce ISO payload', async () => {
|
13
|
-
config.API_TYPE = API_TYPES.iso20022
|
14
|
-
const destination = 'D1'
|
15
|
-
const partyId = 'P1'
|
16
|
-
const partyType = 'XXX'
|
17
|
-
const dto = await timeoutCallbackDto({ destination, partyId, partyType })
|
18
|
-
expect(dto.errorInformation).toBeTruthy()
|
19
|
-
|
20
|
-
const { Assgnr, Assgne } = dto.errorInformation.Assgnmt
|
21
|
-
expect(Assgnr.Agt.FinInstnId.Othr.Id).toBe(config.HUB_NAME)
|
22
|
-
expect(Assgne.Agt.FinInstnId.Othr.Id).toBe(destination)
|
23
|
-
})
|
24
|
-
})
|