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,324 @@
|
|
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
|
+
* Crosslake
|
22
|
+
- Lewis Daly <lewisd@crosslaketech.com>
|
23
|
+
- Kevin Leyow <kevin.leyow@modusbox.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const Db = require('../../../../src/lib/db')
|
29
|
+
const Config = require('../../../../src/lib/config')
|
30
|
+
const Oracle = require('../../../../src/domain/oracle')
|
31
|
+
const OracleModel = require('../../../../src/models/oracle')
|
32
|
+
const EventSdk = require('@mojaloop/event-sdk')
|
33
|
+
|
34
|
+
describe('Oracle', () => {
|
35
|
+
beforeAll(async () => {
|
36
|
+
await Db.connect(Config.DATABASE)
|
37
|
+
})
|
38
|
+
|
39
|
+
afterAll(async () => {
|
40
|
+
await Db.disconnect()
|
41
|
+
})
|
42
|
+
|
43
|
+
const createHeaders = {
|
44
|
+
accept: 'application/vnd.interoperability.participants+json;version=1',
|
45
|
+
'cache-control': 'no-cache',
|
46
|
+
date: '',
|
47
|
+
'content-type': 'application/vnd.interoperability.participants+json;version=1.1',
|
48
|
+
host: '127.0.0.1:4003',
|
49
|
+
'accept-encoding': 'gzip, deflate',
|
50
|
+
'content-length': 164,
|
51
|
+
connection: 'keep-alive'
|
52
|
+
}
|
53
|
+
const testSpan = EventSdk.Tracer.createSpan('createOracle service')
|
54
|
+
|
55
|
+
const oracleAuhMsisdnUrlPayload = {
|
56
|
+
isDefault: true,
|
57
|
+
currency: 'AUD',
|
58
|
+
oracleIdType: 'MSISDN',
|
59
|
+
endpoint: {
|
60
|
+
value: 'http://localhost:8444',
|
61
|
+
endpointType: 'URL'
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
const oracleUsdMsisdnUrlPayload = {
|
66
|
+
isDefault: true,
|
67
|
+
currency: 'USD',
|
68
|
+
oracleIdType: 'MSISDN',
|
69
|
+
endpoint: {
|
70
|
+
value: 'http://localhost:8444',
|
71
|
+
endpointType: 'URL'
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
const oracleAudEmailUrlPayload = {
|
76
|
+
isDefault: true,
|
77
|
+
currency: 'AUD',
|
78
|
+
oracleIdType: 'EMAIL',
|
79
|
+
endpoint: {
|
80
|
+
value: 'http://localhost:8444',
|
81
|
+
endpointType: 'URL'
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
describe('Create', () => {
|
86
|
+
it('creates an oracle', async () => {
|
87
|
+
const result = await Oracle.createOracle(oracleAuhMsisdnUrlPayload, createHeaders, testSpan)
|
88
|
+
expect(result).toBe(true)
|
89
|
+
|
90
|
+
const oracleEndpointResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
91
|
+
const createdId = oracleEndpointResult[0].oracleEndpointId
|
92
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: createdId })
|
93
|
+
})
|
94
|
+
|
95
|
+
it('creates a similar oracle if the first is inactive', async () => {
|
96
|
+
const result = await Oracle.createOracle(oracleAuhMsisdnUrlPayload, createHeaders, testSpan)
|
97
|
+
expect(result).toBe(true)
|
98
|
+
|
99
|
+
// Delete/mark first oracle inactive
|
100
|
+
const previousOracleResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
101
|
+
const firstOracleCreatedId = previousOracleResult[0].oracleEndpointId
|
102
|
+
await Oracle.deleteOracle({ ID: firstOracleCreatedId })
|
103
|
+
|
104
|
+
const secondResult = await Oracle.createOracle(oracleAuhMsisdnUrlPayload, createHeaders, testSpan)
|
105
|
+
expect(secondResult).toBe(true)
|
106
|
+
|
107
|
+
const oracleEndpointResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
108
|
+
const activeCreatedId = oracleEndpointResult[0].oracleEndpointId
|
109
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: activeCreatedId })
|
110
|
+
|
111
|
+
// Cleanup inactive endpoint for good measure
|
112
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: firstOracleCreatedId })
|
113
|
+
})
|
114
|
+
|
115
|
+
it('rejects creating a similar oracle when one is still active', async () => {
|
116
|
+
const result = await Oracle.createOracle(oracleAuhMsisdnUrlPayload, createHeaders, testSpan)
|
117
|
+
expect(result).toBe(true)
|
118
|
+
|
119
|
+
try {
|
120
|
+
await Oracle.createOracle(oracleAuhMsisdnUrlPayload, createHeaders, testSpan)
|
121
|
+
} catch (error) {
|
122
|
+
expect(error.message).toBe('Active oracle with matching partyIdTypeId, endpointTypeId, currencyId already exists')
|
123
|
+
}
|
124
|
+
|
125
|
+
const oracleEndpointResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
126
|
+
const createdId = oracleEndpointResult[0].oracleEndpointId
|
127
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: createdId })
|
128
|
+
})
|
129
|
+
})
|
130
|
+
|
131
|
+
describe('Update', () => {
|
132
|
+
it('updates an oracle', async () => {
|
133
|
+
const createResult = await Oracle.createOracle(oracleAuhMsisdnUrlPayload, createHeaders, testSpan)
|
134
|
+
expect(createResult).toBe(true)
|
135
|
+
|
136
|
+
// Get newly created oracle
|
137
|
+
const oracleEndpointResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
138
|
+
const createdId = oracleEndpointResult[0].oracleEndpointId
|
139
|
+
|
140
|
+
// Update the oracle's currency
|
141
|
+
const updateResult = await Oracle.updateOracle(
|
142
|
+
{
|
143
|
+
ID: createdId
|
144
|
+
},
|
145
|
+
{
|
146
|
+
isDefault: true,
|
147
|
+
currency: 'USD',
|
148
|
+
oracleIdType: 'MSISDN',
|
149
|
+
endpoint: {
|
150
|
+
value: 'http://localhost:8444',
|
151
|
+
endpointType: 'URL'
|
152
|
+
}
|
153
|
+
}
|
154
|
+
)
|
155
|
+
expect(updateResult).toBe(true)
|
156
|
+
|
157
|
+
const updatedOracleEndpointResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
158
|
+
expect(updatedOracleEndpointResult[0].currency).toEqual('USD')
|
159
|
+
|
160
|
+
// Cleanup
|
161
|
+
const updatedId = updatedOracleEndpointResult[0].oracleEndpointId
|
162
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: updatedId })
|
163
|
+
})
|
164
|
+
|
165
|
+
it('updates an oracle even if there is a similar oracle that is inactive', async () => {
|
166
|
+
const createResultAUD = await Oracle.createOracle(
|
167
|
+
oracleAuhMsisdnUrlPayload,
|
168
|
+
createHeaders,
|
169
|
+
testSpan
|
170
|
+
)
|
171
|
+
expect(createResultAUD).toBe(true)
|
172
|
+
|
173
|
+
// Get newly created AUD currency oracle
|
174
|
+
const oracleEndpointResultAUD = await OracleModel.getOracleEndpointByType('MSISDN')
|
175
|
+
const createdIdAUD = oracleEndpointResultAUD[0].oracleEndpointId
|
176
|
+
|
177
|
+
// Delete/mark first AUD currency oracle inactive
|
178
|
+
await Oracle.deleteOracle({ ID: createdIdAUD })
|
179
|
+
|
180
|
+
const payloadUSD = {
|
181
|
+
isDefault: true,
|
182
|
+
currency: 'USD',
|
183
|
+
oracleIdType: 'MSISDN',
|
184
|
+
endpoint: {
|
185
|
+
value: 'http://localhost:8444',
|
186
|
+
endpointType: 'URL'
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
// Create USD currency oracle
|
191
|
+
const createResultUSD = await Oracle.createOracle(payloadUSD, createHeaders, testSpan)
|
192
|
+
expect(createResultUSD).toBe(true)
|
193
|
+
|
194
|
+
// Get newly created USD currency oracle
|
195
|
+
const oracleEndpointResultUSD = await OracleModel.getOracleEndpointByType('MSISDN')
|
196
|
+
const createdIdUSD = oracleEndpointResultUSD[0].oracleEndpointId
|
197
|
+
|
198
|
+
// Update the USD currency oracle to be AUD currency
|
199
|
+
const updateResult = await Oracle.updateOracle(
|
200
|
+
{
|
201
|
+
ID: createdIdUSD
|
202
|
+
},
|
203
|
+
{
|
204
|
+
isDefault: true,
|
205
|
+
currency: 'AUD',
|
206
|
+
oracleIdType: 'MSISDN',
|
207
|
+
endpoint: {
|
208
|
+
value: 'http://localhost:8444',
|
209
|
+
endpointType: 'URL'
|
210
|
+
}
|
211
|
+
}
|
212
|
+
)
|
213
|
+
|
214
|
+
// Assert true since previous AUD currency oracle was deleted
|
215
|
+
expect(updateResult).toBe(true)
|
216
|
+
|
217
|
+
// Cleanup
|
218
|
+
const updatedOracleEndpointResult = await OracleModel.getOracleEndpointByType('MSISDN')
|
219
|
+
expect(updatedOracleEndpointResult[0].currency).toEqual('AUD')
|
220
|
+
|
221
|
+
const updatedId = updatedOracleEndpointResult[0].oracleEndpointId
|
222
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: updatedId })
|
223
|
+
|
224
|
+
// Cleanup inactive model for good measure
|
225
|
+
await Db.from('oracleEndpoint').destroy({ oracleEndpointId: createdIdAUD })
|
226
|
+
})
|
227
|
+
|
228
|
+
it('rejects updating an oracles currency if updating it would match an existing active oracle', async () => {
|
229
|
+
const testSpan = EventSdk.Tracer.createSpan('createOracle service')
|
230
|
+
const createResultAUD = await Oracle.createOracle(
|
231
|
+
oracleAuhMsisdnUrlPayload,
|
232
|
+
createHeaders,
|
233
|
+
testSpan
|
234
|
+
)
|
235
|
+
expect(createResultAUD).toBe(true)
|
236
|
+
|
237
|
+
// Create USD currency oracle
|
238
|
+
const createResultUSD = await Oracle.createOracle(
|
239
|
+
oracleUsdMsisdnUrlPayload,
|
240
|
+
createHeaders,
|
241
|
+
testSpan
|
242
|
+
)
|
243
|
+
expect(createResultUSD).toBe(true)
|
244
|
+
|
245
|
+
// Get newly created USD currency oracle
|
246
|
+
const oracleEndpointResultUSD = await OracleModel.getOracleEndpointByTypeAndCurrency('MSISDN', 'USD')
|
247
|
+
const createdIdUSD = oracleEndpointResultUSD[0].oracleEndpointId
|
248
|
+
|
249
|
+
// Update the USD currency oracle to be AUD currency
|
250
|
+
try {
|
251
|
+
await Oracle.updateOracle(
|
252
|
+
{
|
253
|
+
ID: createdIdUSD
|
254
|
+
},
|
255
|
+
oracleAuhMsisdnUrlPayload
|
256
|
+
)
|
257
|
+
} catch (error) {
|
258
|
+
// Should throw error since there is an existing active oracle
|
259
|
+
// with similar currency
|
260
|
+
expect(error.message).toBe('Active oracle with matching partyIdTypeId, endpointTypeId, currencyId already exists')
|
261
|
+
}
|
262
|
+
|
263
|
+
// Cleanup
|
264
|
+
const oracleEndpointResultMSISDNAUD = await OracleModel.getOracleEndpointByTypeAndCurrency('MSISDN', 'AUD')
|
265
|
+
const oracleEndpointResultMSISDNUSD = await OracleModel.getOracleEndpointByTypeAndCurrency('MSISDN', 'USD')
|
266
|
+
await Db.from('oracleEndpoint').destroy({
|
267
|
+
oracleEndpointId: oracleEndpointResultMSISDNUSD[0].oracleEndpointId
|
268
|
+
})
|
269
|
+
await Db.from('oracleEndpoint').destroy({
|
270
|
+
oracleEndpointId: oracleEndpointResultMSISDNAUD[0].oracleEndpointId
|
271
|
+
})
|
272
|
+
})
|
273
|
+
|
274
|
+
it('rejects updating an oracles id type if updating it would match an existing active oracle', async () => {
|
275
|
+
const testSpan = EventSdk.Tracer.createSpan('createOracle service')
|
276
|
+
const createResultMSISDN = await Oracle.createOracle(
|
277
|
+
oracleAuhMsisdnUrlPayload,
|
278
|
+
createHeaders,
|
279
|
+
testSpan
|
280
|
+
)
|
281
|
+
expect(createResultMSISDN).toBe(true)
|
282
|
+
|
283
|
+
// Create email id type oracle
|
284
|
+
const createResultEMAIL = await Oracle.createOracle(
|
285
|
+
oracleAudEmailUrlPayload,
|
286
|
+
createHeaders,
|
287
|
+
testSpan
|
288
|
+
)
|
289
|
+
expect(createResultEMAIL).toBe(true)
|
290
|
+
|
291
|
+
// Get newly created email id type oracle
|
292
|
+
const oracleEndpointResultEmail = await OracleModel.getOracleEndpointByTypeAndCurrency('EMAIL', 'AUD')
|
293
|
+
const createdIdEmail = oracleEndpointResultEmail[0].oracleEndpointId
|
294
|
+
|
295
|
+
// Update the email id type oracle to be MSISDN id type oracle
|
296
|
+
try {
|
297
|
+
await Oracle.updateOracle(
|
298
|
+
{
|
299
|
+
ID: createdIdEmail
|
300
|
+
},
|
301
|
+
oracleAuhMsisdnUrlPayload
|
302
|
+
)
|
303
|
+
} catch (error) {
|
304
|
+
// Should throw error since there is an existing active oracle
|
305
|
+
// with similar id type
|
306
|
+
expect(error.message).toBe('Active oracle with matching partyIdTypeId, endpointTypeId, currencyId already exists')
|
307
|
+
}
|
308
|
+
|
309
|
+
// Cleanup
|
310
|
+
const oracleEndpointResultMSISDNAUD = await OracleModel.getOracleEndpointByTypeAndCurrency('MSISDN', 'AUD')
|
311
|
+
const oracleEndpointResultEMAILAUD = await OracleModel.getOracleEndpointByTypeAndCurrency('EMAIL', 'AUD')
|
312
|
+
await Db.from('oracleEndpoint').destroy({
|
313
|
+
oracleEndpointId: oracleEndpointResultMSISDNAUD[0].oracleEndpointId
|
314
|
+
})
|
315
|
+
await Db.from('oracleEndpoint').destroy({
|
316
|
+
oracleEndpointId: oracleEndpointResultEMAILAUD[0].oracleEndpointId
|
317
|
+
})
|
318
|
+
})
|
319
|
+
|
320
|
+
// Currently there is only one endpoint type, that being 'URL'.
|
321
|
+
// Would need to add tests when more endpoints are added.
|
322
|
+
it.todo('rejects updating an oracles endpoint type if updating it would match an existing active oracle')
|
323
|
+
})
|
324
|
+
})
|
@@ -0,0 +1,75 @@
|
|
1
|
+
const { createProxyCache } = require('@mojaloop/inter-scheme-proxy-cache-lib')
|
2
|
+
const { PAYER_DFSP, PARTY_ID_TYPE, PROXY_NAME } = require('../../constants')
|
3
|
+
const fixtures = require('../../../fixtures')
|
4
|
+
const { ProxyApiClient } = require('../../../util')
|
5
|
+
const config = require('../../../../src/lib/config')
|
6
|
+
|
7
|
+
const wait = (sec) => new Promise(resolve => setTimeout(resolve, sec * 1000))
|
8
|
+
|
9
|
+
const CRON_TIMEOUT_SEC = 10 // see TIMEXP
|
10
|
+
|
11
|
+
describe('Timeout Handler', () => {
|
12
|
+
const { type, proxyConfig } = config.PROXY_CACHE_CONFIG
|
13
|
+
const proxyCache = createProxyCache(type, proxyConfig)
|
14
|
+
const proxyClient = new ProxyApiClient()
|
15
|
+
|
16
|
+
beforeAll(async () => {
|
17
|
+
await proxyCache.connect()
|
18
|
+
const redisClient = proxyCache.redisClient
|
19
|
+
const redisNodes = redisClient.nodes ? redisClient.nodes('master') : [redisClient]
|
20
|
+
await Promise.all(redisNodes.map(async node => {
|
21
|
+
await node.flushall()
|
22
|
+
}))
|
23
|
+
})
|
24
|
+
|
25
|
+
afterAll(async () => {
|
26
|
+
return Promise.all([
|
27
|
+
proxyClient.deleteHistory(),
|
28
|
+
proxyCache.disconnect()
|
29
|
+
])
|
30
|
+
})
|
31
|
+
|
32
|
+
it('test', async () => {
|
33
|
+
let history = await proxyClient.deleteHistory()
|
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
|
+
]
|
42
|
+
const proxies = [PROXY_NAME]
|
43
|
+
const alsReq1 = fixtures.mockAlsRequestDto(PAYER_DFSP, PARTY_ID_TYPE, partyIds[0])
|
44
|
+
const alsReq2 = fixtures.mockAlsRequestDto(PAYER_DFSP, PARTY_ID_TYPE, partyIds[1])
|
45
|
+
const results = await Promise.all([
|
46
|
+
proxyCache.setSendToProxiesList(alsReq1, proxies, CRON_TIMEOUT_SEC),
|
47
|
+
proxyCache.setSendToProxiesList(alsReq2, proxies, CRON_TIMEOUT_SEC)
|
48
|
+
])
|
49
|
+
expect(results.includes(false)).toBe(false)
|
50
|
+
|
51
|
+
// wait for the timeout handler to process the keys
|
52
|
+
await wait(CRON_TIMEOUT_SEC * 1.5)
|
53
|
+
|
54
|
+
// check that the keys are no longer in redis
|
55
|
+
const exists = await Promise.all(keys.map(key => proxyCache.redisClient.exists(key)))
|
56
|
+
expect(exists.includes(1)).toBe(false)
|
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
|
+
}
|
69
|
+
expect(history.length).toBe(2)
|
70
|
+
const path0 = history.find(h => h.path.includes(partyIds[0])).path
|
71
|
+
const path1 = history.find(h => h.path.includes(partyIds[1])).path
|
72
|
+
expect(path0).toBe(`/parties/${PARTY_ID_TYPE}/${partyIds[0]}/error`)
|
73
|
+
expect(path1).toBe(`/parties/${PARTY_ID_TYPE}/${partyIds[1]}/error`)
|
74
|
+
}, 60_000)
|
75
|
+
})
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# Retrieve the external IP address of the host machine (on macOS)
|
4
|
+
# or the IP address of the docker0 interface (on Linux)
|
5
|
+
get_external_ip() {
|
6
|
+
if [ "$(uname)" = "Linux" ]; then
|
7
|
+
echo "$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)"
|
8
|
+
else
|
9
|
+
# Need to find a way to support Windows here
|
10
|
+
echo "$(route get ifconfig.me | grep interface | sed -e 's/.*: //' | xargs ipconfig getifaddr)"
|
11
|
+
fi
|
12
|
+
}
|
13
|
+
|
14
|
+
# set/override dynamic variables
|
15
|
+
export REDIS_CLUSTER_ANNOUNCE_IP=$(get_external_ip)
|
@@ -0,0 +1,68 @@
|
|
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
|
+
* Crosslake
|
22
|
+
- Lewis Daly <lewisd@crosslaketech.com>
|
23
|
+
|
24
|
+
--------------
|
25
|
+
******/
|
26
|
+
|
27
|
+
'use strict'
|
28
|
+
|
29
|
+
const Db = require('../../../../src/lib/db')
|
30
|
+
const Config = require('../../../../src/lib/config')
|
31
|
+
const { getCurrencyById } = require('../../../../src/models/currency')
|
32
|
+
|
33
|
+
describe('currency model', () => {
|
34
|
+
beforeAll(async () => {
|
35
|
+
await Db.connect(Config.DATABASE)
|
36
|
+
})
|
37
|
+
|
38
|
+
afterAll(async () => {
|
39
|
+
await Db.disconnect()
|
40
|
+
})
|
41
|
+
|
42
|
+
describe('getCurrencyById', () => {
|
43
|
+
it('gets a currency by id', async () => {
|
44
|
+
// Arrange
|
45
|
+
const expected = {
|
46
|
+
currencyId: 'AUD',
|
47
|
+
name: 'Australian dollar',
|
48
|
+
isActive: 1
|
49
|
+
}
|
50
|
+
|
51
|
+
// Act
|
52
|
+
const result = await getCurrencyById('AUD')
|
53
|
+
delete result.createdDate
|
54
|
+
|
55
|
+
// Assert
|
56
|
+
expect(result).toMatchObject(expected)
|
57
|
+
})
|
58
|
+
|
59
|
+
it('returns null when it cannot find a currency', async () => {
|
60
|
+
// Arrange
|
61
|
+
// Act
|
62
|
+
const currency = await getCurrencyById('UUU')
|
63
|
+
|
64
|
+
// Assert
|
65
|
+
expect(currency).toBe(null)
|
66
|
+
})
|
67
|
+
})
|
68
|
+
})
|
@@ -0,0 +1,62 @@
|
|
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
|
+
* Crosslake
|
22
|
+
- Lewis Daly <lewisd@crosslaketech.com>
|
23
|
+
- Miguel de Barros <miguel.debarros@modusbox.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
'use strict'
|
29
|
+
|
30
|
+
const axios = require('axios').default
|
31
|
+
|
32
|
+
const {
|
33
|
+
TEST_ALS_HOST,
|
34
|
+
ADMIN_PORT,
|
35
|
+
API_PORT
|
36
|
+
} = require('../util/testConfig')
|
37
|
+
|
38
|
+
describe('plugins', () => {
|
39
|
+
describe('API documentation - /swagger.json', () => {
|
40
|
+
it('loads the swagger file for the admin api', async () => {
|
41
|
+
// Arrange
|
42
|
+
// nothing to do
|
43
|
+
|
44
|
+
// Act
|
45
|
+
const response = await axios.get(`http://${TEST_ALS_HOST}:${ADMIN_PORT}/swagger.json`)
|
46
|
+
|
47
|
+
// Assert
|
48
|
+
expect(response.data.info.title).toBe('Open API for ALS Admin API')
|
49
|
+
})
|
50
|
+
|
51
|
+
it('loads the swagger file for the default api', async () => {
|
52
|
+
// Arrange
|
53
|
+
// nothing to do
|
54
|
+
|
55
|
+
// Act
|
56
|
+
const response = await axios.get(`http://${TEST_ALS_HOST}:${API_PORT}/swagger.json`)
|
57
|
+
|
58
|
+
// Assert
|
59
|
+
expect(response.data.info.title).toBe('Open API for FSP Interoperability (FSPIOP) (Implementation Friendly Version)')
|
60
|
+
})
|
61
|
+
})
|
62
|
+
})
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require('./setup')
|
2
|
+
|
3
|
+
const Logger = require('@mojaloop/central-services-logger')
|
4
|
+
const { onboarding } = require('../util')
|
5
|
+
const { PROXY_NAME, PAYER_DFSP } = require('../integration/constants')
|
6
|
+
|
7
|
+
const pause = async (ms = 1000) => new Promise(resolve => {
|
8
|
+
Logger.info(`pause for ${ms / 1000} sec....`)
|
9
|
+
setTimeout(resolve, ms)
|
10
|
+
})
|
11
|
+
|
12
|
+
const prepareTestParticipants = async () => {
|
13
|
+
await pause(15_000) // sometimes on CircleCI env we have error: socket hang up
|
14
|
+
await onboarding.createHubAccounts()
|
15
|
+
await pause()
|
16
|
+
|
17
|
+
await onboarding.createTestParticipant({ name: PAYER_DFSP })
|
18
|
+
await onboarding.createTestParticipant({
|
19
|
+
name: PROXY_NAME,
|
20
|
+
isProxy: true
|
21
|
+
})
|
22
|
+
|
23
|
+
await onboarding.createOracle()
|
24
|
+
Logger.info('prepareTestParticipants is finished')
|
25
|
+
}
|
26
|
+
|
27
|
+
prepareTestParticipants().catch(err => {
|
28
|
+
Logger.error(err)
|
29
|
+
throw err
|
30
|
+
})
|
@@ -0,0 +1,81 @@
|
|
1
|
+
{
|
2
|
+
"HUB_PARTICIPANT": {
|
3
|
+
"ID": 1,
|
4
|
+
"NAME": "Hub"
|
5
|
+
},
|
6
|
+
"TEST_ALS_HOST":"account-lookup-service",
|
7
|
+
"ADMIN_PORT": 4001,
|
8
|
+
"API_PORT": 4002,
|
9
|
+
"DATABASE": {
|
10
|
+
"DIALECT": "mysql",
|
11
|
+
"HOST": "mysql-als",
|
12
|
+
"PORT": 3306,
|
13
|
+
"USER": "account_lookup",
|
14
|
+
"PASSWORD": "password",
|
15
|
+
"DATABASE": "account_lookup",
|
16
|
+
"POOL_MIN_SIZE": 10,
|
17
|
+
"POOL_MAX_SIZE": 10,
|
18
|
+
"ACQUIRE_TIMEOUT_MILLIS": 30000,
|
19
|
+
"CREATE_TIMEOUT_MILLIS": 30000,
|
20
|
+
"DESTROY_TIMEOUT_MILLIS": 5000,
|
21
|
+
"IDLE_TIMEOUT_MILLIS": 30000,
|
22
|
+
"REAP_INTERVAL_MILLIS": 1000,
|
23
|
+
"CREATE_RETRY_INTERVAL_MILLIS": 200,
|
24
|
+
"DEBUG": false
|
25
|
+
},
|
26
|
+
"PROTOCOL_VERSIONS": {
|
27
|
+
"CONTENT": {
|
28
|
+
"DEFAULT": "1.1",
|
29
|
+
"VALIDATELIST": [
|
30
|
+
"1.1",
|
31
|
+
"1.0"
|
32
|
+
]
|
33
|
+
},
|
34
|
+
"ACCEPT": {
|
35
|
+
"DEFAULT": "1",
|
36
|
+
"VALIDATELIST": [
|
37
|
+
"1",
|
38
|
+
"1.0",
|
39
|
+
"1.1"
|
40
|
+
]
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"DISPLAY_ROUTES": true,
|
44
|
+
"RUN_MIGRATIONS": true,
|
45
|
+
"CENTRAL_SHARED_ENDPOINT_CACHE_CONFIG": {
|
46
|
+
"expiresIn": 180000,
|
47
|
+
"generateTimeout": 30000
|
48
|
+
},
|
49
|
+
"PROXY_CACHE": {
|
50
|
+
"enabled": true,
|
51
|
+
"type": "redis-cluster",
|
52
|
+
"proxyConfig": {
|
53
|
+
"cluster": [
|
54
|
+
{ "host": "redis-node-0", "port": 6379 }
|
55
|
+
]
|
56
|
+
}
|
57
|
+
},
|
58
|
+
"SWITCH_ENDPOINT": "http://localhost:3001",
|
59
|
+
"INSTRUMENTATION": {
|
60
|
+
"METRICS": {
|
61
|
+
"DISABLED": false,
|
62
|
+
"labels": {
|
63
|
+
"fspId": "*"
|
64
|
+
},
|
65
|
+
"config": {
|
66
|
+
"timeout": 5000,
|
67
|
+
"prefix": "moja_",
|
68
|
+
"defaultLabels": {
|
69
|
+
"serviceName": "account-lookup-service"
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
},
|
74
|
+
"ENDPOINT_SECURITY":{
|
75
|
+
"JWS": {
|
76
|
+
"JWS_SIGN": false,
|
77
|
+
"JWS_SIGNING_KEY_PATH": "secrets/jwsSigningKey.key"
|
78
|
+
}
|
79
|
+
},
|
80
|
+
"API_DOC_ENDPOINTS_ENABLED": true
|
81
|
+
}
|