account-lookup-service 15.5.0-iso.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.circleci/config.yml +11 -0
- package/.ncurc.yaml +6 -0
- package/.nvmrc +1 -0
- package/.nycrc.yml +20 -0
- package/.versionrc +15 -0
- package/CHANGELOG.md +330 -0
- package/CODEOWNERS +38 -0
- package/Dockerfile +45 -0
- package/LICENSE.md +10 -0
- package/README.md +252 -0
- package/audit-ci.jsonc +32 -0
- package/audit-resolve.json +161 -0
- package/config/default.json +109 -0
- package/config/knexfile.js +21 -0
- package/docker/account-lookup-service/default.json +106 -0
- package/docker/account-lookup-service/make-default-json.sh +5 -0
- package/docker/account-lookup-service/override.json +15 -0
- package/docker/central-ledger/default.json +458 -0
- package/docker/config-modifier/account-lookup-service.js +31 -0
- package/docker/kafka/consumer.properties +26 -0
- package/docker/kafka/producer.properties +45 -0
- package/docker/kafka/server.properties +143 -0
- package/docker/kafka/tools-log4j.properties +21 -0
- package/docker/mock-proxy/Dockerfile +15 -0
- package/docker/mock-proxy/package-lock.json +4986 -0
- package/docker/mock-proxy/package.json +24 -0
- package/docker/mock-proxy/src/config.ts +14 -0
- package/docker/mock-proxy/src/server.ts +94 -0
- package/docker/mock-proxy/src/utils.ts +29 -0
- package/docker/mock-proxy/tsconfig.json +24 -0
- package/docker/sql-init/01_permissions.sql +2 -0
- package/docker/sql-init-central-ledger/01_permissions.sql +2 -0
- package/docker/wait-for/wait-for-account-lookup-service.sh +10 -0
- package/docker/wait-for/wait-for-central-ledger.sh +11 -0
- package/docker/wait-for/wait-for-kafka.sh +7 -0
- package/docker/wait-for/wait-for-ml-api-adapter.sh +9 -0
- package/docker/wait-for/wait-for-mockserver.sh +20 -0
- package/docker/wait-for/wait-for-mysql-als.sh +14 -0
- package/docker/wait-for/wait-for-mysql-central-ledger.sh +11 -0
- package/docker/wait-for/wait-for-mysql.sh +11 -0
- package/docker/wait-for/wait-for-objstore.sh +12 -0
- package/docker/wait-for/wait-for.env +18 -0
- package/docker/wait-for/wait-for.sh +81 -0
- package/docker-compose.integration.yml +29 -0
- package/docker-compose.yml +243 -0
- package/jest-int.config.js +8 -0
- package/jest.config.js +16 -0
- package/jsdoc.json +38 -0
- package/migrations/01_currency.js +42 -0
- package/migrations/02_endpointType.js +43 -0
- package/migrations/03_endpointType-indexes.js +37 -0
- package/migrations/04_partyIdType.js +43 -0
- package/migrations/05_partyIdType-indexes.js +38 -0
- package/migrations/08_oracleEndpoint.js +51 -0
- package/migrations/09_oracleEndpoint-indexes.js +41 -0
- package/migrations/10_oracleEndpoint-remove-constraints.js +38 -0
- package/package.json +180 -0
- package/scripts/_wait4_all.js +143 -0
- package/scripts/test-functional.sh +76 -0
- package/secrets/jwsSigningKey.key +27 -0
- package/seeds/currency.js +765 -0
- package/seeds/endpointType.js +65 -0
- package/seeds/partyIdType.js +79 -0
- package/src/api/endpointcache.js +67 -0
- package/src/api/health.js +66 -0
- package/src/api/index.js +85 -0
- package/src/api/oracles/{ID}.js +100 -0
- package/src/api/oracles.js +96 -0
- package/src/api/participants/{ID}/error.js +44 -0
- package/src/api/participants/{ID}.js +44 -0
- package/src/api/participants/{Type}/{ID}/error.js +74 -0
- package/src/api/participants/{Type}/{ID}/{SubId}/error.js +68 -0
- package/src/api/participants/{Type}/{ID}/{SubId}.js +113 -0
- package/src/api/participants/{Type}/{ID}.js +133 -0
- package/src/api/participants.js +63 -0
- package/src/api/parties/{Type}/{ID}/error.js +66 -0
- package/src/api/parties/{Type}/{ID}/{SubId}/error.js +56 -0
- package/src/api/parties/{Type}/{ID}/{SubId}.js +77 -0
- package/src/api/parties/{Type}/{ID}.js +98 -0
- package/src/api/routes.js +294 -0
- package/src/constants.js +16 -0
- package/src/domain/oracle/index.js +33 -0
- package/src/domain/oracle/oracle.js +234 -0
- package/src/domain/participants/index.js +35 -0
- package/src/domain/participants/participants.js +560 -0
- package/src/domain/parties/getPartiesByTypeAndID.js +239 -0
- package/src/domain/parties/index.js +32 -0
- package/src/domain/parties/parties.js +215 -0
- package/src/domain/parties/utils.js +84 -0
- package/src/domain/timeout/dto.js +48 -0
- package/src/domain/timeout/index.js +104 -0
- package/src/handlers/TimeoutHandler.js +94 -0
- package/src/handlers/index.js +70 -0
- package/src/handlers/monitoring/index.js +51 -0
- package/src/handlers/monitoring/plugins/health.js +61 -0
- package/src/handlers/monitoring/plugins/metrics.js +48 -0
- package/src/handlers/register.js +102 -0
- package/src/index.js +66 -0
- package/src/interface/admin-swagger.yaml +804 -0
- package/src/interface/admin_swagger.json +959 -0
- package/src/interface/api-swagger-iso20022-parties.yaml +1734 -0
- package/src/interface/api-swagger.yaml +1733 -0
- package/src/interface/api_swagger.json +3046 -0
- package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2256 -0
- package/src/interface/thirdparty/admin-swagger.yaml +808 -0
- package/src/interface/thirdparty/admin_swagger.json +961 -0
- package/src/interface/thirdparty/api-swagger.yaml +1739 -0
- package/src/interface/thirdparty/api_swagger.json +3142 -0
- package/src/lib/argv.js +39 -0
- package/src/lib/cache.js +126 -0
- package/src/lib/config.js +183 -0
- package/src/lib/db.js +26 -0
- package/src/lib/headers.js +53 -0
- package/src/lib/healthCheck/subServiceHealth.js +84 -0
- package/src/lib/index.js +11 -0
- package/src/lib/migrator.js +17 -0
- package/src/lib/requestLogger.js +54 -0
- package/src/lib/util.js +66 -0
- package/src/metrics/handler.js +33 -0
- package/src/metrics/plugin.js +52 -0
- package/src/metrics/routes.js +43 -0
- package/src/models/currency/currency.js +48 -0
- package/src/models/currency/index.js +32 -0
- package/src/models/endpointType/endpointType.js +48 -0
- package/src/models/endpointType/index.js +32 -0
- package/src/models/misc/migrationLock.js +49 -0
- package/src/models/oracle/facade.js +341 -0
- package/src/models/oracle/index.js +41 -0
- package/src/models/oracle/oracleEndpoint.js +192 -0
- package/src/models/oracle/oracleEndpointCached.js +108 -0
- package/src/models/participantEndpoint/facade.js +238 -0
- package/src/models/partyIdType/index.js +32 -0
- package/src/models/partyIdType/partyIdType.js +41 -0
- package/src/plugins.js +139 -0
- package/src/server.js +199 -0
- package/test/fixtures/index.js +131 -0
- package/test/fixtures/iso.js +110 -0
- package/test/integration/.env +8 -0
- package/test/integration/api/parties.test.js +137 -0
- package/test/integration/constants.js +20 -0
- package/test/integration/domain/oracle/index.test.js +324 -0
- package/test/integration/domain/timeout/index.test.js +75 -0
- package/test/integration/env.sh +15 -0
- package/test/integration/example.test.js +12 -0
- package/test/integration/models/currency/currency.test.js +68 -0
- package/test/integration/plugins.test.js +62 -0
- package/test/integration/prepareTestParticipants.js +30 -0
- package/test/integration/setup.js +5 -0
- package/test/integration-config.json +81 -0
- package/test/integration-runner.sh +108 -0
- package/test/unit/api/health.test.js +142 -0
- package/test/unit/api/oracles/{ID}.test.js +264 -0
- package/test/unit/api/oracles.test.js +173 -0
- package/test/unit/api/participants/participants.test.js +117 -0
- package/test/unit/api/participants/{Type}/{ID}/error.test.js +155 -0
- package/test/unit/api/participants/{Type}/{ID}/{SubId}/error.test.js +131 -0
- package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +377 -0
- package/test/unit/api/participants/{Type}/{ID}.test.js +383 -0
- package/test/unit/api/participants.test.js +108 -0
- package/test/unit/api/parties/endpointcache.test.js +83 -0
- package/test/unit/api/parties/parties.test.js +102 -0
- package/test/unit/api/parties/{Type}/{ID}/error.test.js +145 -0
- package/test/unit/api/parties/{Type}/{ID}/{SubId}/error.test.js +141 -0
- package/test/unit/api/parties/{Type}/{ID}/{SubId}.test.js +241 -0
- package/test/unit/api/parties/{Type}/{ID}.test.js +240 -0
- package/test/unit/domain/oracle/oracle.test.js +505 -0
- package/test/unit/domain/participants/participants.test.js +1724 -0
- package/test/unit/domain/parties/parties.test.js +940 -0
- package/test/unit/domain/timeout/dto.test.js +28 -0
- package/test/unit/domain/timeout/index.test.js +81 -0
- package/test/unit/handlers/TimeoutHandler.test.js +125 -0
- package/test/unit/handlers/index.test.js +56 -0
- package/test/unit/handlers/register.test.js +90 -0
- package/test/unit/index.test.js +139 -0
- package/test/unit/iso20022/partiesValidation.test.js +129 -0
- package/test/unit/lib/TransformFacades.test.js +18 -0
- package/test/unit/lib/argv.test.js +40 -0
- package/test/unit/lib/cache.test.js +172 -0
- package/test/unit/lib/config.test.js +108 -0
- package/test/unit/lib/healthCheck/subServiceHealth.test.js +89 -0
- package/test/unit/lib/migrator.test.js +52 -0
- package/test/unit/lib/requestLogger.test.js +115 -0
- package/test/unit/lib/util.test.js +68 -0
- package/test/unit/mocks.js +66 -0
- package/test/unit/models/currency/currency.test.js +91 -0
- package/test/unit/models/endpointType/endpointType.test.js +69 -0
- package/test/unit/models/misc/migrationLock.test.js +96 -0
- package/test/unit/models/oracle/facade.test.js +546 -0
- package/test/unit/models/oracle/oracleEndpoint.test.js +409 -0
- package/test/unit/models/oracle/oracleEndpointCached.test.js +153 -0
- package/test/unit/models/participantEndpoint/facade.test.js +295 -0
- package/test/unit/models/partyIdType/partyIdType.test.js +88 -0
- package/test/unit/plugins.test.js +89 -0
- package/test/unit/setup.js +7 -0
- package/test/util/apiClients/AlsApiClient.js +44 -0
- package/test/util/apiClients/BasicApiClient.js +34 -0
- package/test/util/apiClients/ProxyApiClient.js +25 -0
- package/test/util/apiClients/index.js +7 -0
- package/test/util/helper.js +332 -0
- package/test/util/index.js +11 -0
- package/test/util/mockgen.js +43 -0
- package/test/util/onboarding.js +132 -0
- package/test/util/scripts/addAlsDb.sh +33 -0
- package/test/util/scripts/configureMockServer.sh +35 -0
- package/test/util/scripts/env.sh +19 -0
- package/test/util/scripts/populateTestData.sh +62 -0
- package/test/util/scripts/startMockCentralServer.sh +45 -0
- package/test/util/scripts/startMockOracleServer.sh +45 -0
- package/test/util/testConfig.js +44 -0
@@ -0,0 +1,940 @@
|
|
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
|
+
* ModusBox
|
22
|
+
- Rajiv Mothilal <rajiv.mothilal@modusbox.com>
|
23
|
+
- Steven Oderayi <steven.oderayi@modusbox.com>
|
24
|
+
|
25
|
+
* Crosslake
|
26
|
+
- Lewis Daly <lewisd@crosslaketech.com>
|
27
|
+
|
28
|
+
--------------
|
29
|
+
******/
|
30
|
+
|
31
|
+
'use strict'
|
32
|
+
|
33
|
+
const { randomUUID } = require('node:crypto')
|
34
|
+
const { setTimeout: sleep } = require('node:timers/promises')
|
35
|
+
const Sinon = require('sinon')
|
36
|
+
const { createProxyCache } = require('@mojaloop/inter-scheme-proxy-cache-lib')
|
37
|
+
const { Enum, Util } = require('@mojaloop/central-services-shared')
|
38
|
+
const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
|
39
|
+
const Logger = require('@mojaloop/central-services-logger')
|
40
|
+
|
41
|
+
const Config = require('../../../../src/lib/config')
|
42
|
+
const Db = require('../../../../src/lib/db')
|
43
|
+
const partiesDomain = require('../../../../src/domain/parties/parties')
|
44
|
+
const partiesUtils = require('../../../../src/domain/parties/utils')
|
45
|
+
const participant = require('../../../../src/models/participantEndpoint/facade')
|
46
|
+
const oracle = require('../../../../src/models/oracle/facade')
|
47
|
+
const oracleEndpointCached = require('../../../../src/models/oracle/oracleEndpointCached')
|
48
|
+
const libUtil = require('../../../../src/lib/util')
|
49
|
+
const { logger } = require('../../../../src/lib')
|
50
|
+
const { ERROR_MESSAGES } = require('../../../../src/constants')
|
51
|
+
|
52
|
+
const Helper = require('../../../util/helper')
|
53
|
+
const fixtures = require('../../../fixtures')
|
54
|
+
|
55
|
+
const { type: proxyCacheType, proxyConfig: proxyCacheConfig } = Config.PROXY_CACHE_CONFIG
|
56
|
+
|
57
|
+
const { encodePayload } = Util.StreamingProtocol
|
58
|
+
const { RestMethods } = Enum.Http
|
59
|
+
|
60
|
+
Logger.isDebugEnabled = jest.fn(() => true)
|
61
|
+
Logger.isErrorEnabled = jest.fn(() => true)
|
62
|
+
Logger.isInfoEnabled = jest.fn(() => true)
|
63
|
+
let sandbox
|
64
|
+
|
65
|
+
describe('Parties Tests', () => {
|
66
|
+
let proxyCache
|
67
|
+
|
68
|
+
beforeEach(async () => {
|
69
|
+
await Util.Endpoints.initializeCache(Config.CENTRAL_SHARED_ENDPOINT_CACHE_CONFIG, libUtil.hubNameConfig)
|
70
|
+
sandbox = Sinon.createSandbox()
|
71
|
+
sandbox.stub(Util.Request)
|
72
|
+
sandbox.stub(Util.Http, 'SwitchDefaultHeaders').returns(Helper.defaultSwitchHeaders)
|
73
|
+
sandbox.stub(Util.proxies)
|
74
|
+
|
75
|
+
Db.oracleEndpoint = {
|
76
|
+
query: sandbox.stub()
|
77
|
+
}
|
78
|
+
Db.from = (table) => {
|
79
|
+
return Db[table]
|
80
|
+
}
|
81
|
+
proxyCache = createProxyCache(proxyCacheType, proxyCacheConfig)
|
82
|
+
await proxyCache.connect()
|
83
|
+
})
|
84
|
+
|
85
|
+
afterEach(async () => {
|
86
|
+
await proxyCache.disconnect()
|
87
|
+
sandbox.restore()
|
88
|
+
})
|
89
|
+
|
90
|
+
describe('getPartiesByTypeAndID', () => {
|
91
|
+
beforeEach(() => {
|
92
|
+
sandbox.stub(participant)
|
93
|
+
Config.PROXY_CACHE_CONFIG.enabled = false
|
94
|
+
})
|
95
|
+
|
96
|
+
afterEach(() => {
|
97
|
+
sandbox.restore()
|
98
|
+
})
|
99
|
+
|
100
|
+
it('handles error case where destination header is missing', async () => {
|
101
|
+
expect.hasAssertions()
|
102
|
+
// Arrange
|
103
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
104
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
105
|
+
data: {
|
106
|
+
partyList: [
|
107
|
+
{ fspId: 'fsp1' }
|
108
|
+
]
|
109
|
+
}
|
110
|
+
})
|
111
|
+
participant.sendRequest = sandbox.stub().resolves()
|
112
|
+
const headers = {
|
113
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
114
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
115
|
+
date: '2019-05-24 08:52:19',
|
116
|
+
'fspiop-source': 'payerfsp'
|
117
|
+
}
|
118
|
+
const expectedHeaders = {
|
119
|
+
...headers,
|
120
|
+
'fspiop-source': 'payerfsp',
|
121
|
+
'fspiop-destination': 'fsp1'
|
122
|
+
}
|
123
|
+
|
124
|
+
// Act
|
125
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan())
|
126
|
+
|
127
|
+
// Assert
|
128
|
+
const lastCallHeaderArgs = participant.sendRequest.getCall(0).args
|
129
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
130
|
+
expect(lastCallHeaderArgs[0]).toStrictEqual(expectedHeaders)
|
131
|
+
expect(lastCallHeaderArgs[1]).toBe('fsp1')
|
132
|
+
})
|
133
|
+
|
134
|
+
it('forwards request to destination if specified in headers without consulting any oracles', async () => {
|
135
|
+
expect.hasAssertions()
|
136
|
+
// Arrange
|
137
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
138
|
+
sandbox.stub(oracle, 'oracleRequest')
|
139
|
+
participant.sendRequest = sandbox.stub().resolves()
|
140
|
+
|
141
|
+
const headers = {
|
142
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
143
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
144
|
+
date: '2019-05-24 08:52:19',
|
145
|
+
'fspiop-source': 'payerfsp',
|
146
|
+
'fspiop-destination': 'destfsp'
|
147
|
+
}
|
148
|
+
|
149
|
+
const expectedHeaders = {
|
150
|
+
...headers,
|
151
|
+
'fspiop-source': 'payerfsp',
|
152
|
+
'fspiop-destination': 'destfsp'
|
153
|
+
}
|
154
|
+
|
155
|
+
// Act
|
156
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan())
|
157
|
+
|
158
|
+
// Assert
|
159
|
+
const lastCallHeaderArgs = participant.sendRequest.getCall(0).args
|
160
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
161
|
+
expect(oracle.oracleRequest.callCount).toBe(0)
|
162
|
+
expect(lastCallHeaderArgs[0]).toStrictEqual(expectedHeaders)
|
163
|
+
expect(lastCallHeaderArgs[1]).toBe('destfsp')
|
164
|
+
})
|
165
|
+
|
166
|
+
it('should set source proxyMapping if source is not in scheme, and there is proxy-header', async () => {
|
167
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
168
|
+
participant.validateParticipant = sandbox.stub()
|
169
|
+
.onFirstCall().resolves(null) // source
|
170
|
+
.onSecondCall().resolves({}) // proxy
|
171
|
+
const source = `source-${Date.now()}`
|
172
|
+
const proxy = `proxy-${Date.now()}`
|
173
|
+
|
174
|
+
let cached = await proxyCache.lookupProxyByDfspId(source)
|
175
|
+
expect(cached).toBe(null)
|
176
|
+
|
177
|
+
const headers = fixtures.partiesCallHeadersDto({ source, proxy })
|
178
|
+
const { params, method, query } = Helper.getByTypeIdRequest
|
179
|
+
|
180
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, method, query, Helper.mockSpan(), null, proxyCache)
|
181
|
+
await sleep(1000)
|
182
|
+
|
183
|
+
cached = await proxyCache.lookupProxyByDfspId(source)
|
184
|
+
expect(cached).toBe(proxy)
|
185
|
+
})
|
186
|
+
|
187
|
+
it('should send error callback if destination is not in the scheme, and not in proxyCache', async () => {
|
188
|
+
participant.validateParticipant = sandbox.stub()
|
189
|
+
.onFirstCall().resolves({}) // source
|
190
|
+
.onSecondCall().resolves(null) // destination
|
191
|
+
participant.sendRequest = sandbox.stub().resolves()
|
192
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
193
|
+
sandbox.stub(oracle, 'oracleRequest')
|
194
|
+
const headers = fixtures.partiesCallHeadersDto()
|
195
|
+
|
196
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan(), null, proxyCache)
|
197
|
+
|
198
|
+
expect(participant.sendRequest.callCount).toBe(0)
|
199
|
+
expect(oracle.oracleRequest.callCount).toBe(0)
|
200
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
201
|
+
|
202
|
+
const { errorInformation } = participant.sendErrorToParticipant.getCall(0).args[2]
|
203
|
+
expect(errorInformation.errorCode).toBe('3200')
|
204
|
+
expect(errorInformation.errorDescription).toContain(ERROR_MESSAGES.partyDestinationFspNotFound)
|
205
|
+
})
|
206
|
+
|
207
|
+
it('should send request to proxy, if destination is not in the scheme, but has proxyMapping', async () => {
|
208
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
209
|
+
participant.validateParticipant = sandbox.stub()
|
210
|
+
.onFirstCall().resolves({}) // source
|
211
|
+
.onSecondCall().resolves(null) // destination
|
212
|
+
participant.sendRequest = sandbox.stub().resolves()
|
213
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
214
|
+
|
215
|
+
const destination = `destination-${Date.now()}`
|
216
|
+
const proxyId = `proxy-${Date.now()}`
|
217
|
+
await proxyCache.addDfspIdToProxyMapping(destination, proxyId)
|
218
|
+
const headers = fixtures.partiesCallHeadersDto({ destination })
|
219
|
+
|
220
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan(), null, proxyCache)
|
221
|
+
|
222
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(0)
|
223
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
224
|
+
|
225
|
+
const [proxyHeaders, proxyDestination] = participant.sendRequest.getCall(0).args
|
226
|
+
expect(proxyHeaders).toEqual(headers)
|
227
|
+
expect(proxyDestination).toEqual(proxyId)
|
228
|
+
})
|
229
|
+
|
230
|
+
it('handles error when sourceDfsp cannot be found (no fspiop-proxy in headers)', async () => {
|
231
|
+
expect.hasAssertions()
|
232
|
+
// Arrange
|
233
|
+
participant.validateParticipant = sandbox.stub().resolves(null)
|
234
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves(null)
|
235
|
+
const loggerStub = sandbox.stub(logger.mlLogger, 'error')
|
236
|
+
|
237
|
+
// Act
|
238
|
+
await partiesDomain.getPartiesByTypeAndID(Helper.getByTypeIdRequest.headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query)
|
239
|
+
|
240
|
+
// Assert
|
241
|
+
expect(loggerStub.callCount).toBe(1)
|
242
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
243
|
+
|
244
|
+
const { errorInformation } = participant.sendErrorToParticipant.getCall(0).args[2]
|
245
|
+
expect(errorInformation.errorCode).toBe('3200')
|
246
|
+
expect(errorInformation.errorDescription).toContain(ERROR_MESSAGES.partySourceFspNotFound)
|
247
|
+
})
|
248
|
+
|
249
|
+
it('should send error callback, if proxy-header is present, but no proxy in the scheme', async () => {
|
250
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
251
|
+
participant.validateParticipant = sandbox.stub().resolves(null)
|
252
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
253
|
+
participant.sendRequest = sandbox.stub().resolves()
|
254
|
+
const proxy = `proxy-${Date.now()}`
|
255
|
+
const headers = fixtures.partiesCallHeadersDto({ proxy })
|
256
|
+
|
257
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, null, null, proxyCache)
|
258
|
+
|
259
|
+
expect(participant.sendRequest.callCount).toBe(0)
|
260
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
261
|
+
|
262
|
+
const { errorInformation } = participant.sendErrorToParticipant.getCall(0).args[2]
|
263
|
+
expect(errorInformation.errorCode).toBe('3200')
|
264
|
+
expect(errorInformation.errorDescription).toContain(ERROR_MESSAGES.partyProxyNotFound)
|
265
|
+
})
|
266
|
+
|
267
|
+
it('handles error when `participant.validateParticipant()`cannot be found and `sendErrorToParticipant()` fails', async () => {
|
268
|
+
expect.hasAssertions()
|
269
|
+
// Arrange
|
270
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
271
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
272
|
+
data: {
|
273
|
+
partyList: [
|
274
|
+
{ fspId: 'fsp1' }
|
275
|
+
]
|
276
|
+
}
|
277
|
+
})
|
278
|
+
participant.sendRequest = sandbox.stub().throws(new Error('Error sending request'))
|
279
|
+
participant.sendErrorToParticipant = sandbox.stub().throws(new Error('Error sending Error'))
|
280
|
+
const loggerStub = sandbox.stub(logger.mlLogger, 'error')
|
281
|
+
|
282
|
+
const headers = {
|
283
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
284
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
285
|
+
date: '2019-05-24 08:52:19',
|
286
|
+
'fspiop-source': 'payerfsp',
|
287
|
+
// Also test the empty DESTINATION header case
|
288
|
+
'fspiop-destination': null
|
289
|
+
}
|
290
|
+
|
291
|
+
// Act
|
292
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query)
|
293
|
+
|
294
|
+
// Assert
|
295
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
296
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
297
|
+
expect(loggerStub.callCount).toBe(2)
|
298
|
+
})
|
299
|
+
|
300
|
+
it('handles error when SubId is supplied but `participant.validateParticipant()` cannot be found and `sendErrorToParticipant()` fails', async () => {
|
301
|
+
expect.hasAssertions()
|
302
|
+
// Arrange
|
303
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
304
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
305
|
+
data: {
|
306
|
+
partyList: [
|
307
|
+
{ fspId: 'fsp1' }
|
308
|
+
]
|
309
|
+
}
|
310
|
+
})
|
311
|
+
participant.sendRequest = sandbox.stub().throws(new Error('Error sending request'))
|
312
|
+
participant.sendErrorToParticipant = sandbox.stub().throws(new Error('Error sending Error'))
|
313
|
+
sandbox.stub(Logger)
|
314
|
+
|
315
|
+
const headers = {
|
316
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
317
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
318
|
+
date: '2019-05-24 08:52:19',
|
319
|
+
'fspiop-source': 'payerfsp'
|
320
|
+
}
|
321
|
+
const params = { ...Helper.getByTypeIdRequest.params, SubId: 'subId' }
|
322
|
+
const expectedErrorCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR
|
323
|
+
|
324
|
+
// Act
|
325
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan())
|
326
|
+
|
327
|
+
// Assert
|
328
|
+
const firstCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
329
|
+
expect(firstCallArgs[1]).toBe(expectedErrorCallbackEnpointType)
|
330
|
+
})
|
331
|
+
|
332
|
+
it('ensures sendRequest is called with the right endpoint type when no SubId is supplied', async () => {
|
333
|
+
expect.hasAssertions()
|
334
|
+
// Arrange
|
335
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
336
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
337
|
+
data: {
|
338
|
+
partyList: [
|
339
|
+
{ fspId: 'fsp1' }
|
340
|
+
]
|
341
|
+
}
|
342
|
+
})
|
343
|
+
participant.sendRequest = sandbox.stub().resolves()
|
344
|
+
const headers = {
|
345
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
346
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
347
|
+
date: '2019-05-24 08:52:19',
|
348
|
+
'fspiop-source': 'payerfsp'
|
349
|
+
}
|
350
|
+
const params = { ...Helper.getByTypeIdRequest.params }
|
351
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET
|
352
|
+
|
353
|
+
// Act
|
354
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query)
|
355
|
+
|
356
|
+
// Assert
|
357
|
+
const firstCallArgs = participant.sendRequest.getCall(0).args
|
358
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
359
|
+
expect(firstCallArgs[2]).toBe(expectedCallbackEnpointType)
|
360
|
+
})
|
361
|
+
|
362
|
+
it('ensures sendRequest is called with the right endpoint type when SubId is supplied', async () => {
|
363
|
+
expect.hasAssertions()
|
364
|
+
// Arrange
|
365
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
366
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
367
|
+
data: {
|
368
|
+
partyList: [
|
369
|
+
{
|
370
|
+
fspId: 'fsp1',
|
371
|
+
partySubIdOrType: 'subId'
|
372
|
+
}
|
373
|
+
]
|
374
|
+
}
|
375
|
+
})
|
376
|
+
participant.sendRequest = sandbox.stub().resolves()
|
377
|
+
const headers = {
|
378
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
379
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
380
|
+
date: '2019-05-24 08:52:19',
|
381
|
+
'fspiop-source': 'payerfsp'
|
382
|
+
}
|
383
|
+
const params = { ...Helper.getByTypeIdRequest.params, SubId: 'subId' }
|
384
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET
|
385
|
+
|
386
|
+
// Act
|
387
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query)
|
388
|
+
|
389
|
+
// Assert
|
390
|
+
const firstCallArgs = participant.sendRequest.getCall(0).args
|
391
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
392
|
+
expect(firstCallArgs[2]).toBe(expectedCallbackEnpointType)
|
393
|
+
})
|
394
|
+
|
395
|
+
it('ensures sendErrorToParticipant is called with the right endpoint type when SubId is supplied is not matched', async () => {
|
396
|
+
expect.hasAssertions()
|
397
|
+
// Arrange
|
398
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
399
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
400
|
+
data: {
|
401
|
+
partyList: [
|
402
|
+
{
|
403
|
+
fspId: 'fsp1',
|
404
|
+
partySubIdOrType: 'subId'
|
405
|
+
}
|
406
|
+
]
|
407
|
+
}
|
408
|
+
})
|
409
|
+
participant.sendRequest = sandbox.stub().resolves()
|
410
|
+
participant.sendErrorToParticipant = sandbox.stub().throws(new Error('Error sending Error'))
|
411
|
+
|
412
|
+
const headers = {
|
413
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
414
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
415
|
+
date: '2019-05-24 08:52:19',
|
416
|
+
'fspiop-source': 'payerfsp'
|
417
|
+
}
|
418
|
+
const params = { ...Helper.getByTypeIdRequest.params, SubId: 'subIdNOTFOUND' }
|
419
|
+
const expectedErrorCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR
|
420
|
+
|
421
|
+
// Act
|
422
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query)
|
423
|
+
|
424
|
+
// Assert
|
425
|
+
const firstCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
426
|
+
expect(firstCallArgs[1]).toBe(expectedErrorCallbackEnpointType)
|
427
|
+
})
|
428
|
+
|
429
|
+
it('ensures sendRequest is called only once in FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET mode when oracle returns two records without SubId and with SubId', async () => {
|
430
|
+
expect.hasAssertions()
|
431
|
+
// Arrange
|
432
|
+
participant.validateParticipant = sandbox.stub().returns({})
|
433
|
+
sandbox.stub(oracle, 'oracleRequest').returns({
|
434
|
+
data: {
|
435
|
+
partyList: [
|
436
|
+
{
|
437
|
+
fspId: 'fsp1'
|
438
|
+
},
|
439
|
+
{
|
440
|
+
fspId: 'fsp1',
|
441
|
+
partySubIdOrType: 'subId'
|
442
|
+
}
|
443
|
+
]
|
444
|
+
}
|
445
|
+
})
|
446
|
+
participant.sendRequest = sandbox.stub().resolves()
|
447
|
+
const headers = {
|
448
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
449
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
450
|
+
date: '2019-05-24 08:52:19',
|
451
|
+
'fspiop-source': 'payerfsp'
|
452
|
+
}
|
453
|
+
const params = { ...Helper.getByTypeIdRequest.params, SubId: 'subId' }
|
454
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET
|
455
|
+
|
456
|
+
// Act
|
457
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query)
|
458
|
+
|
459
|
+
// Assert
|
460
|
+
const firstCallArgs = participant.sendRequest.getCall(0).args
|
461
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
462
|
+
expect(firstCallArgs[2]).toBe(expectedCallbackEnpointType)
|
463
|
+
})
|
464
|
+
|
465
|
+
it('should send request to proxy if oracle returns dfsp NOT from the scheme', async () => {
|
466
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
467
|
+
const proxyName = `proxy-${Date.now()}`
|
468
|
+
const fspId = `dfspNotFromScheme-${Date.now()}`
|
469
|
+
const oracleResponse = fixtures.oracleRequestResponseDto({
|
470
|
+
partyList: [{ fspId }]
|
471
|
+
})
|
472
|
+
sandbox.stub(oracle, 'oracleRequest').resolves(oracleResponse)
|
473
|
+
participant.validateParticipant = sandbox.stub()
|
474
|
+
.onFirstCall().resolves({}) // source
|
475
|
+
.onSecondCall().resolves(null) // oracle dfsp
|
476
|
+
participant.sendRequest = sandbox.stub().resolves()
|
477
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
478
|
+
|
479
|
+
const isAdded = await proxyCache.addDfspIdToProxyMapping(fspId, proxyName)
|
480
|
+
expect(isAdded).toBe(true)
|
481
|
+
|
482
|
+
const headers = fixtures.partiesCallHeadersDto({ destination: '' })
|
483
|
+
const { params, method, query } = Helper.getByTypeIdRequest
|
484
|
+
|
485
|
+
await partiesDomain.getPartiesByTypeAndID(headers, params, method, query, null, null, proxyCache)
|
486
|
+
|
487
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(0)
|
488
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
489
|
+
const calledProxy = participant.sendRequest.getCall(0).args[1]
|
490
|
+
expect(calledProxy).toBe(proxyName)
|
491
|
+
})
|
492
|
+
|
493
|
+
it('handles error when `oracleRequest` returns no result', async () => {
|
494
|
+
expect.hasAssertions()
|
495
|
+
// Arrange
|
496
|
+
participant.validateParticipant = sandbox.stub().resolves({})
|
497
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves(null)
|
498
|
+
oracle.oracleRequest = sandbox.stub().resolves(null)
|
499
|
+
sandbox.stub(Logger)
|
500
|
+
const expectedErrorCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR
|
501
|
+
|
502
|
+
// Act
|
503
|
+
const headers = { ...Helper.getByTypeIdRequest.headers }
|
504
|
+
delete headers['fspiop-destination']
|
505
|
+
|
506
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan())
|
507
|
+
|
508
|
+
// Assert
|
509
|
+
const firstCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
510
|
+
expect(firstCallArgs[1]).toBe(expectedErrorCallbackEnpointType)
|
511
|
+
})
|
512
|
+
|
513
|
+
it('should perform sendToProxies alsRequest, if no destination-header and no data in oracle response', async () => {
|
514
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
515
|
+
const proxyNames = ['proxyA', 'proxyB']
|
516
|
+
Util.proxies.getAllProxiesNames = sandbox.stub().resolves(proxyNames)
|
517
|
+
oracle.oracleRequest = sandbox.stub().resolves(null)
|
518
|
+
participant.validateParticipant = sandbox.stub().resolves({})
|
519
|
+
participant.sendRequest = sandbox.stub().resolves()
|
520
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
521
|
+
|
522
|
+
const source = `fromDfsp-${Date.now()}`
|
523
|
+
const destination = ''
|
524
|
+
const headers = fixtures.partiesCallHeadersDto({ source, destination })
|
525
|
+
const alsReq = partiesUtils.alsRequestDto(source, Helper.getByTypeIdRequest.params)
|
526
|
+
|
527
|
+
let isExists = await proxyCache.receivedSuccessResponse(alsReq) // no in cache
|
528
|
+
expect(isExists).toBe(false)
|
529
|
+
|
530
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan(), null, proxyCache)
|
531
|
+
|
532
|
+
isExists = await proxyCache.receivedSuccessResponse(alsReq)
|
533
|
+
expect(isExists).toBe(true)
|
534
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(0)
|
535
|
+
expect(participant.sendRequest.callCount).toBe(proxyNames.length)
|
536
|
+
const calledProxies = participant.sendRequest.args.map(args => args[1])
|
537
|
+
expect(calledProxies).toEqual(proxyNames)
|
538
|
+
})
|
539
|
+
|
540
|
+
it('should send error callback, if no successful sendToProxiesList requests', async () => {
|
541
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
542
|
+
const proxyNames = ['proxyA', 'proxyB']
|
543
|
+
Util.proxies.getAllProxiesNames = sandbox.stub().resolves(proxyNames)
|
544
|
+
oracle.oracleRequest = sandbox.stub().resolves(null)
|
545
|
+
participant.validateParticipant = sandbox.stub().resolves({})
|
546
|
+
participant.sendRequest = sandbox.stub().rejects(new Error('Some network issue'))
|
547
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
548
|
+
const headers = fixtures.partiesCallHeadersDto({ destination: '' })
|
549
|
+
|
550
|
+
await partiesDomain.getPartiesByTypeAndID(headers, Helper.getByTypeIdRequest.params, Helper.getByTypeIdRequest.method, Helper.getByTypeIdRequest.query, Helper.mockSpan(), null, proxyCache)
|
551
|
+
|
552
|
+
expect(participant.sendRequest.callCount).toBe(proxyNames.length)
|
553
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
554
|
+
|
555
|
+
const { errorInformation } = participant.sendErrorToParticipant.getCall(0).args[2]
|
556
|
+
expect(errorInformation.errorCode).toBe('3200')
|
557
|
+
expect(errorInformation.errorDescription).toContain(ERROR_MESSAGES.proxyConnectionError)
|
558
|
+
})
|
559
|
+
})
|
560
|
+
|
561
|
+
describe('putPartiesByTypeAndID', () => {
|
562
|
+
beforeEach(() => {
|
563
|
+
sandbox.stub(participant)
|
564
|
+
Config.PROXY_CACHE_CONFIG.enabled = false
|
565
|
+
})
|
566
|
+
|
567
|
+
afterEach(() => {
|
568
|
+
sandbox.restore()
|
569
|
+
})
|
570
|
+
|
571
|
+
it('successfully sends the callback to the participant', async () => {
|
572
|
+
expect.hasAssertions()
|
573
|
+
// Arrange
|
574
|
+
participant.validateParticipant = sandbox.stub().resolves({
|
575
|
+
name: 'fsp1'
|
576
|
+
})
|
577
|
+
participant.sendRequest = sandbox.stub().resolves()
|
578
|
+
const payload = JSON.stringify({ testPayload: true })
|
579
|
+
const dataUri = encodePayload(payload, 'application/json')
|
580
|
+
|
581
|
+
// Act
|
582
|
+
await partiesDomain.putPartiesByTypeAndID(Helper.putByTypeIdRequest.headers, Helper.putByTypeIdRequest.params, 'put', payload, dataUri, null, proxyCache)
|
583
|
+
|
584
|
+
// Assert
|
585
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
586
|
+
const sendRequestCallArgs = participant.sendRequest.getCall(0).args
|
587
|
+
expect(sendRequestCallArgs[1]).toStrictEqual('fsp1')
|
588
|
+
participant.sendRequest.reset()
|
589
|
+
})
|
590
|
+
|
591
|
+
it('successfully sends the callback to the participant when SubId is supplied', async () => {
|
592
|
+
expect.hasAssertions()
|
593
|
+
// Arrange
|
594
|
+
participant.validateParticipant = sandbox.stub().resolves({
|
595
|
+
data: {
|
596
|
+
name: 'fsp1'
|
597
|
+
}
|
598
|
+
})
|
599
|
+
participant.sendRequest = sandbox.stub().resolves()
|
600
|
+
const payload = {}
|
601
|
+
const params = { ...Helper.putByTypeIdRequest.params, SubId: 'subId' }
|
602
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT
|
603
|
+
|
604
|
+
// Act
|
605
|
+
await partiesDomain.putPartiesByTypeAndID(Helper.putByTypeIdRequest.headers, params, 'put', payload, null, null, proxyCache)
|
606
|
+
|
607
|
+
// Assert
|
608
|
+
expect(participant.sendRequest.callCount).toBe(1)
|
609
|
+
const sendRequestCallArgs = participant.sendRequest.getCall(0).args
|
610
|
+
expect(sendRequestCallArgs[2]).toBe(expectedCallbackEnpointType)
|
611
|
+
})
|
612
|
+
|
613
|
+
it('handles error when `participant.validateParticipant()` returns no participant', async () => {
|
614
|
+
expect.hasAssertions()
|
615
|
+
// Arrange
|
616
|
+
const loggerStub = sandbox.stub(logger, 'error')
|
617
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
618
|
+
|
619
|
+
const payload = JSON.stringify({ testPayload: true })
|
620
|
+
const dataUri = encodePayload(payload, 'application/json')
|
621
|
+
const { headers, params, method } = Helper.putByTypeIdRequest
|
622
|
+
|
623
|
+
// Act
|
624
|
+
await partiesDomain.putPartiesByTypeAndID(headers, params, method, payload, dataUri, proxyCache)
|
625
|
+
|
626
|
+
// Assert
|
627
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
628
|
+
const firstLoggerCallArgs = loggerStub.getCall(0).args
|
629
|
+
expect(firstLoggerCallArgs[1].message).toBe(ERROR_MESSAGES.partySourceFspNotFound)
|
630
|
+
loggerStub.reset()
|
631
|
+
participant.sendErrorToParticipant.reset()
|
632
|
+
})
|
633
|
+
|
634
|
+
it('should add proxyMapping, if source is not in scheme, and there is fspiop-proxy header', async () => {
|
635
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
636
|
+
participant.validateParticipant = sandbox.stub().resolves(null)
|
637
|
+
participant.sendRequest = sandbox.stub().resolves()
|
638
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
639
|
+
|
640
|
+
const source = `source-${Date.now()}`
|
641
|
+
let cachedProxy = await proxyCache.lookupProxyByDfspId(source)
|
642
|
+
expect(cachedProxy).toBeNull()
|
643
|
+
|
644
|
+
const proxy = `proxy-${Date.now()}`
|
645
|
+
const headers = fixtures.partiesCallHeadersDto({ source, proxy })
|
646
|
+
const payload = { test: true }
|
647
|
+
const dataUri = encodePayload(JSON.stringify(payload), 'application/json')
|
648
|
+
const { params, method } = Helper.putByTypeIdRequest
|
649
|
+
|
650
|
+
await partiesDomain.putPartiesByTypeAndID(headers, params, method, payload, dataUri, null, proxyCache)
|
651
|
+
|
652
|
+
cachedProxy = await proxyCache.lookupProxyByDfspId(source)
|
653
|
+
expect(cachedProxy).toBe(proxy)
|
654
|
+
})
|
655
|
+
|
656
|
+
it('should update oracle with partyDetails received from proxy, if previous alsReq is cached', async () => {
|
657
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
658
|
+
const source = `source-${Date.now()}`
|
659
|
+
const destination = `payer-fsp-${Date.now()}`
|
660
|
+
const proxy = `proxy-${Date.now()}`
|
661
|
+
|
662
|
+
participant.validateParticipant = sandbox.stub()
|
663
|
+
.onFirstCall().resolves(null) // payee
|
664
|
+
.onSecondCall().resolves({ name: destination }) // payer
|
665
|
+
oracleEndpointCached.getOracleEndpointByType = sandbox.stub().resolves([
|
666
|
+
{ value: 'http://oracle.endpoint' }
|
667
|
+
])
|
668
|
+
oracle.oracleRequest = sandbox.stub().resolves()
|
669
|
+
|
670
|
+
const headers = fixtures.partiesCallHeadersDto({ source, destination, proxy })
|
671
|
+
const partyId = `testParty-${randomUUID()}`
|
672
|
+
const partyIdType = 'MSISDN'
|
673
|
+
const partyDetails = fixtures.putPartiesSuccessResponseDto({
|
674
|
+
partyId,
|
675
|
+
partyIdType,
|
676
|
+
fspId: source
|
677
|
+
})
|
678
|
+
const dataUri = encodePayload(JSON.stringify(partyDetails), 'application/json')
|
679
|
+
const params = { ID: partyId, Type: partyIdType }
|
680
|
+
|
681
|
+
const alsReq = fixtures.mockAlsRequestDto(destination, partyIdType, partyId)
|
682
|
+
const isSet = await proxyCache.setSendToProxiesList(alsReq, [proxy])
|
683
|
+
expect(isSet).toBe(true)
|
684
|
+
|
685
|
+
await partiesDomain.putPartiesByTypeAndID(headers, params, 'PUT', partyDetails, dataUri, null, proxyCache)
|
686
|
+
await sleep(1000)
|
687
|
+
|
688
|
+
expect(oracle.oracleRequest.callCount).toBe(1)
|
689
|
+
const [, method, , , payload] = oracle.oracleRequest.getCall(0).args
|
690
|
+
expect(payload.fspId).toBe(source)
|
691
|
+
expect(method).toBe(RestMethods.POST)
|
692
|
+
})
|
693
|
+
|
694
|
+
it('handles error when SubId is supplied but `participant.validateParticipant()` returns no participant', async () => {
|
695
|
+
expect.hasAssertions()
|
696
|
+
// Arrange
|
697
|
+
sandbox.stub(Logger)
|
698
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
699
|
+
participant.validateParticipant = sandbox.stub()
|
700
|
+
participant.validateParticipant.withArgs('payerfsp')
|
701
|
+
.resolves({
|
702
|
+
data: {
|
703
|
+
name: 'fsp1'
|
704
|
+
}
|
705
|
+
})
|
706
|
+
participant.validateParticipant.withArgs('payeefsp').resolves(null)
|
707
|
+
|
708
|
+
const payload = JSON.stringify({ testPayload: true })
|
709
|
+
const dataUri = encodePayload(payload, 'application/json')
|
710
|
+
const params = { ...Helper.putByTypeIdRequest.params, SubId: 'subId' }
|
711
|
+
const expectedErrorCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR
|
712
|
+
|
713
|
+
// Act
|
714
|
+
await partiesDomain.putPartiesByTypeAndID(Helper.putByTypeIdRequest.headers, params, 'put', payload, dataUri)
|
715
|
+
|
716
|
+
// Assert
|
717
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
718
|
+
const firstCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
719
|
+
expect(firstCallArgs[1]).toBe(expectedErrorCallbackEnpointType)
|
720
|
+
})
|
721
|
+
|
722
|
+
it('handles error when `participant.validateParticipant()` is found and `sendErrorToParticipant()` fails', async () => {
|
723
|
+
expect.hasAssertions()
|
724
|
+
// Arrange
|
725
|
+
participant.validateParticipant = sandbox.stub()
|
726
|
+
participant.validateParticipant.withArgs('payerfsp')
|
727
|
+
.resolves({
|
728
|
+
data: {
|
729
|
+
name: 'fsp1'
|
730
|
+
}
|
731
|
+
})
|
732
|
+
participant.validateParticipant.withArgs('payeefsp').resolves(null)
|
733
|
+
participant.sendErrorToParticipant = sandbox.stub().throws('Error in sendErrorToParticipant')
|
734
|
+
|
735
|
+
const payload = JSON.stringify({ testPayload: true })
|
736
|
+
const dataUri = encodePayload(payload, 'application/json')
|
737
|
+
|
738
|
+
// Act
|
739
|
+
await partiesDomain.putPartiesByTypeAndID(Helper.putByTypeIdRequest.headers, Helper.putByTypeIdRequest.params, 'put', payload, dataUri, null, proxyCache)
|
740
|
+
|
741
|
+
// Assert
|
742
|
+
expect(participant.validateParticipant.callCount).toBe(2)
|
743
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
744
|
+
participant.validateParticipant.reset()
|
745
|
+
participant.sendErrorToParticipant.reset()
|
746
|
+
})
|
747
|
+
|
748
|
+
it('handles error when SubId is supplied, `participant.validateParticipant()` is found but `sendErrorToParticipant()` fails', async () => {
|
749
|
+
expect.hasAssertions()
|
750
|
+
// Arrange
|
751
|
+
sandbox.stub(Logger)
|
752
|
+
participant.validateParticipant = sandbox.stub()
|
753
|
+
participant.validateParticipant.withArgs('payerfsp')
|
754
|
+
.resolves({
|
755
|
+
data: {
|
756
|
+
name: 'fsp1'
|
757
|
+
}
|
758
|
+
})
|
759
|
+
participant.validateParticipant.withArgs('payeefsp').resolves(null)
|
760
|
+
participant.sendErrorToParticipant = sandbox.stub().throws('Error in sendErrorToParticipant')
|
761
|
+
|
762
|
+
const payload = JSON.stringify({ testPayload: true })
|
763
|
+
const dataUri = encodePayload(payload, 'application/json')
|
764
|
+
const params = { ...Helper.putByTypeIdRequest.params, SubId: 'subId' }
|
765
|
+
const expectedErrorCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR
|
766
|
+
|
767
|
+
// Act
|
768
|
+
await partiesDomain.putPartiesByTypeAndID(Helper.putByTypeIdRequest.headers, params, 'put', payload, dataUri, null, proxyCache)
|
769
|
+
|
770
|
+
// Assert
|
771
|
+
expect(participant.validateParticipant.callCount).toBe(2)
|
772
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
773
|
+
const firstCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
774
|
+
expect(firstCallArgs[1]).toBe(expectedErrorCallbackEnpointType)
|
775
|
+
})
|
776
|
+
})
|
777
|
+
|
778
|
+
describe('putPartiesErrorByTypeAndID', () => {
|
779
|
+
beforeEach(() => {
|
780
|
+
sandbox.stub(participant)
|
781
|
+
sandbox.stub(partiesDomain, 'getPartiesByTypeAndID')
|
782
|
+
Config.PROXY_CACHE_CONFIG.enabled = false
|
783
|
+
})
|
784
|
+
|
785
|
+
afterEach(() => {
|
786
|
+
sandbox.restore()
|
787
|
+
})
|
788
|
+
|
789
|
+
it('successfully sends error to the participant', async () => {
|
790
|
+
expect.hasAssertions()
|
791
|
+
// Arrange
|
792
|
+
participant.validateParticipant = sandbox.stub().resolves({
|
793
|
+
data: {
|
794
|
+
name: 'fsp1'
|
795
|
+
}
|
796
|
+
})
|
797
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
798
|
+
const payload = JSON.stringify({ errorPayload: true })
|
799
|
+
const dataUri = encodePayload(payload, 'application/json')
|
800
|
+
|
801
|
+
// Act
|
802
|
+
await partiesDomain.putPartiesErrorByTypeAndID(Helper.putByTypeIdRequest.headers, Helper.putByTypeIdRequest.params, payload, dataUri, Helper.mockSpan())
|
803
|
+
|
804
|
+
// Assert
|
805
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
806
|
+
const sendErrorCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
807
|
+
expect(sendErrorCallArgs[0]).toStrictEqual('payeefsp')
|
808
|
+
})
|
809
|
+
|
810
|
+
it('succesfully sends error to the participant when SubId is supplied', async () => {
|
811
|
+
expect.hasAssertions()
|
812
|
+
// Arrange
|
813
|
+
participant.validateParticipant = sandbox.stub().resolves({
|
814
|
+
data: {
|
815
|
+
name: 'fsp1'
|
816
|
+
}
|
817
|
+
})
|
818
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
819
|
+
const payload = JSON.stringify({ errorPayload: true })
|
820
|
+
const dataUri = encodePayload(payload, 'application/json')
|
821
|
+
const params = { ...Helper.putByTypeIdRequest.params, SubId: 'subId' }
|
822
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR
|
823
|
+
|
824
|
+
// Act
|
825
|
+
await partiesDomain.putPartiesErrorByTypeAndID(Helper.putByTypeIdRequest.headers, params, payload, dataUri)
|
826
|
+
|
827
|
+
// Assert
|
828
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
829
|
+
const sendErrorCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
830
|
+
expect(sendErrorCallArgs[0]).toStrictEqual('payeefsp')
|
831
|
+
expect(sendErrorCallArgs[1]).toBe(expectedCallbackEnpointType)
|
832
|
+
})
|
833
|
+
|
834
|
+
it('sends error to the participant when there is no destination participant', async () => {
|
835
|
+
expect.hasAssertions()
|
836
|
+
// Arrange
|
837
|
+
participant.validateParticipant = sandbox.stub().resolves(null)
|
838
|
+
participant.sendErrorToParticipant = sandbox.stub().throws(new Error('Unknown error'))
|
839
|
+
const payload = JSON.stringify({ errorPayload: true })
|
840
|
+
const dataUri = encodePayload(payload, 'application/json')
|
841
|
+
|
842
|
+
// Act
|
843
|
+
await partiesDomain.putPartiesErrorByTypeAndID(Helper.putByTypeIdRequest.headers, Helper.putByTypeIdRequest.params, payload, dataUri, null, proxyCache)
|
844
|
+
|
845
|
+
// Assert
|
846
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
847
|
+
const sendErrorCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
848
|
+
expect(sendErrorCallArgs[0]).toStrictEqual('payerfsp')
|
849
|
+
})
|
850
|
+
|
851
|
+
it('handles error when `decodePayload()` fails', async () => {
|
852
|
+
expect.hasAssertions()
|
853
|
+
// Arrange)
|
854
|
+
participant.validateParticipant = sandbox.stub().resolves({
|
855
|
+
data: {
|
856
|
+
name: 'fsp1'
|
857
|
+
}
|
858
|
+
})
|
859
|
+
participant.sendErrorToParticipant = sandbox.stub().throws(new Error('Unknown error'))
|
860
|
+
const payload = JSON.stringify({ errorPayload: true })
|
861
|
+
// Send a data uri that will cause `decodePayload` to throw
|
862
|
+
const invalidDataUri = () => 'invalid uri'
|
863
|
+
const { headers, params } = Helper.putByTypeIdRequest
|
864
|
+
|
865
|
+
// Act
|
866
|
+
await partiesDomain.putPartiesErrorByTypeAndID(headers, params, payload, invalidDataUri, Helper.mockSpan(), null)
|
867
|
+
|
868
|
+
// Assert
|
869
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
870
|
+
const sendErrorCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
871
|
+
expect(sendErrorCallArgs[0]).toStrictEqual(headers['fspiop-destination'])
|
872
|
+
})
|
873
|
+
|
874
|
+
it('handles error when `validateParticipant()` fails', async () => {
|
875
|
+
expect.hasAssertions()
|
876
|
+
// Arrange)
|
877
|
+
const loggerStub = sandbox.stub(logger.mlLogger, 'error')
|
878
|
+
participant.validateParticipant = sandbox.stub().throws(new Error('Validation fails'))
|
879
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves({})
|
880
|
+
const payload = JSON.stringify({ errorPayload: true })
|
881
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR
|
882
|
+
|
883
|
+
// Act
|
884
|
+
await partiesDomain.putPartiesErrorByTypeAndID(Helper.putByTypeIdRequest.headers, Helper.putByTypeIdRequest.params, payload)
|
885
|
+
|
886
|
+
// Assert
|
887
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
888
|
+
expect(loggerStub.callCount).toBe(1)
|
889
|
+
const sendErrorCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
890
|
+
expect(sendErrorCallArgs[1]).toBe(expectedCallbackEnpointType)
|
891
|
+
})
|
892
|
+
|
893
|
+
it('handles error when SubID is supplied but `validateParticipant()` fails', async () => {
|
894
|
+
expect.hasAssertions()
|
895
|
+
// Arrange
|
896
|
+
|
897
|
+
const loggerStub = sandbox.stub(logger.mlLogger, 'error')
|
898
|
+
participant.validateParticipant = sandbox.stub().throws(new Error('Validation fails'))
|
899
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves({})
|
900
|
+
const payload = JSON.stringify({ errorPayload: true })
|
901
|
+
const params = { ...Helper.putByTypeIdRequest.params, SubId: 'SubId' }
|
902
|
+
const expectedCallbackEnpointType = Enum.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR
|
903
|
+
|
904
|
+
// Act
|
905
|
+
await partiesDomain.putPartiesErrorByTypeAndID(Helper.putByTypeIdRequest.headers, params, payload)
|
906
|
+
|
907
|
+
// Assert
|
908
|
+
expect(participant.sendErrorToParticipant.callCount).toBe(1)
|
909
|
+
expect(loggerStub.callCount).toBe(1)
|
910
|
+
const sendErrorCallArgs = participant.sendErrorToParticipant.getCall(0).args
|
911
|
+
expect(sendErrorCallArgs[1]).toBe(expectedCallbackEnpointType)
|
912
|
+
})
|
913
|
+
|
914
|
+
it('should handle notValidPayeeIdentifier case, and delete partyId from oracle', async () => {
|
915
|
+
Config.PROXY_CACHE_CONFIG.enabled = true
|
916
|
+
const errorCode = MojaloopApiErrorCodes.PAYEE_IDENTIFIER_NOT_VALID.code
|
917
|
+
const payload = fixtures.errorCallbackResponseDto({ errorCode })
|
918
|
+
const source = `source-${Date.now()}`
|
919
|
+
const proxy = `proxy-${Date.now()}`
|
920
|
+
const headers = fixtures.partiesCallHeadersDto({ source, proxy })
|
921
|
+
const { params } = Helper.putByTypeIdRequest
|
922
|
+
participant.sendRequest = sandbox.stub().resolves()
|
923
|
+
participant.sendErrorToParticipant = sandbox.stub().resolves()
|
924
|
+
oracleEndpointCached.getOracleEndpointByType = sandbox.stub().resolves([
|
925
|
+
{ value: 'http://oracle.endpoint' }
|
926
|
+
])
|
927
|
+
oracle.oracleRequest = sandbox.stub().resolves()
|
928
|
+
|
929
|
+
await partiesDomain.putPartiesErrorByTypeAndID(headers, params, payload, '', null, null, proxyCache)
|
930
|
+
|
931
|
+
expect(participant.sendRequest.callCount).toBe(0)
|
932
|
+
expect(oracle.oracleRequest.callCount).toBe(1)
|
933
|
+
const [, method] = oracle.oracleRequest.getCall(0).args
|
934
|
+
expect(method).toBe(RestMethods.DELETE)
|
935
|
+
// todo: think, how to stub getPartiesByTypeAndID call
|
936
|
+
// expect(partiesDomain.getPartiesByTypeAndID.callCount).toBe(1)
|
937
|
+
// expect(participant.sendErrorToParticipant.callCount).toBe(0)
|
938
|
+
})
|
939
|
+
})
|
940
|
+
})
|