@mojaloop/central-ledger 9.2.2 → 15.1.3-snapshot.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +625 -204
- package/.env +3 -2
- package/.ncurc.yaml +9 -0
- package/.nvmrc +1 -1
- package/.versionrc +15 -0
- package/CHANGELOG.md +353 -0
- package/CODEOWNERS +31 -0
- package/Dockerfile +20 -14
- package/LICENSE.md +4 -4
- package/Onboarding.md +0 -7
- package/README.md +99 -22
- package/audit-resolve.json +136 -1
- package/config/default.json +82 -27
- package/docker/central-ledger/default.json +68 -21
- package/docker/ml-api-adapter/default.json +10 -1
- package/docker/wait-for/wait-for-objstore.sh +1 -6
- package/docker/wait-for/wait-for.env +1 -1
- package/docker-compose.integration.yml +8 -5
- package/docker-compose.yml +73 -16
- package/migrations/310203_transferParticipant-indexes.js +38 -0
- package/migrations/310503_participantLimit-indexes-composite.js +38 -0
- package/migrations/{400401_settlementWindowStateChange-indexes.js → 400401_settlmentWindowStateChange-indexes.js} +0 -0
- package/migrations/401301_settlementModel-indexes.js +2 -0
- package/migrations/500401_quote-hotfix-2719.js +58 -0
- package/migrations/500501_feature-fixSubIdRef.js +53 -0
- package/migrations/500601_party-2480.js +63 -0
- package/migrations/501001_quoteExtension-quote-service-174.js +46 -0
- package/migrations/501002_quoteExtension-2522.js +61 -0
- package/migrations/800101_feature-fixSubIdRef.js +90 -0
- package/migrations/910102_hotfix954.js +4 -1
- package/migrations/940100_quotePartyIdInfoExtension.js +52 -0
- package/migrations/940101_quotePartyIdInfoExtension-2522.js +64 -0
- package/migrations/950100_settlementContentAggregation-decimal184.js +40 -0
- package/migrations/950101_transferParticipantStateChange.js +46 -0
- package/migrations/950102_settlementModel-adjustPosition.js +42 -0
- package/migrations/950103_dropTransferParticipantStateChange.js +47 -0
- package/migrations/950104_settlementModel-settlementAccountTypeId.js +79 -0
- package/migrations/950106_unique_settlement_model_ledger_account_currency.js +38 -0
- package/migrations/950107_settlementWindowContent_foreign_settlementModel.js +60 -0
- package/package.json +99 -81
- package/scripts/_wait4_all.js +146 -0
- package/seeds/amountType.js +4 -6
- package/seeds/balanceOfPayments.js +4 -6
- package/seeds/bulkProcessingState.js +4 -6
- package/seeds/bulkTransferState.js +4 -6
- package/seeds/currency.js +4 -6
- package/seeds/endpointType.js +128 -7
- package/seeds/ledgerAccountType.js +11 -10
- package/seeds/ledgerEntryType.js +5 -7
- package/seeds/participant.js +4 -6
- package/seeds/participantLimitType.js +4 -6
- package/seeds/partyIdentifierType.js +4 -6
- package/seeds/partyType.js +4 -6
- package/seeds/settlementDelay.js +4 -6
- package/seeds/settlementGranularity.js +4 -6
- package/seeds/settlementInterchange.js +4 -6
- package/seeds/settlementState.js +4 -6
- package/seeds/settlementWindow1State.js +4 -6
- package/seeds/transactionInitiator.js +4 -6
- package/seeds/transactionInitiatorType.js +4 -6
- package/seeds/transactionScenario.js +4 -6
- package/seeds/transferParticipantRoleType.js +4 -6
- package/seeds/transferState.js +9 -6
- package/src/api/interface/swagger.json +728 -948
- package/src/api/ledgerAccountTypes/handler.js +55 -0
- package/src/api/ledgerAccountTypes/routes.js +63 -0
- package/src/api/metrics/handler.js +2 -2
- package/src/api/metrics/routes.js +1 -1
- package/src/api/participants/handler.js +43 -35
- package/src/api/participants/routes.js +13 -13
- package/src/api/root/routes.js +2 -2
- package/src/api/settlementModels/handler.js +9 -26
- package/src/api/settlementModels/routes.js +4 -4
- package/src/api/transactions/handler.js +46 -0
- package/src/api/transactions/routes.js +45 -0
- package/src/domain/bulkTransfer/index.js +6 -5
- package/src/domain/ledgerAccountTypes/index.js +58 -0
- package/src/domain/participant/index.js +55 -4
- package/src/domain/position/index.js +18 -2
- package/src/domain/settlement/index.js +39 -6
- package/src/domain/transactions/index.js +61 -0
- package/src/domain/transfer/index.js +22 -2
- package/src/domain/transfer/transform.js +3 -3
- package/src/handlers/admin/handler.js +24 -32
- package/src/handlers/bulk/fulfil/handler.js +89 -56
- package/src/handlers/bulk/get/handler.js +203 -0
- package/src/handlers/bulk/index.js +4 -1
- package/src/handlers/bulk/prepare/handler.js +30 -29
- package/src/handlers/bulk/processing/handler.js +61 -32
- package/src/handlers/bulk/shared/validator.js +13 -1
- package/src/handlers/index.js +18 -9
- package/src/handlers/positions/handler.js +67 -46
- package/src/handlers/register.js +7 -7
- package/src/handlers/timeouts/handler.js +9 -4
- package/src/handlers/transfers/handler.js +408 -182
- package/src/handlers/transfers/validator.js +41 -11
- package/src/lib/cache.js +8 -34
- package/src/lib/config.js +5 -7
- package/src/lib/enum.js +22 -22
- package/src/lib/enumCached.js +76 -0
- package/src/lib/healthCheck/subServiceHealth.js +2 -2
- package/src/lib/requestLogger.js +9 -9
- package/src/lib/urlParser.js +1 -1
- package/src/models/bulkTransfer/bulkTransfer.js +6 -6
- package/src/models/bulkTransfer/bulkTransferAssociation.js +3 -3
- package/src/models/bulkTransfer/bulkTransferDuplicateCheck.js +4 -4
- package/src/models/bulkTransfer/bulkTransferExtension.js +2 -2
- package/src/models/bulkTransfer/bulkTransferFulfilmentDuplicateCheck.js +4 -4
- package/src/models/bulkTransfer/bulkTransferStateChange.js +7 -7
- package/src/models/bulkTransfer/facade.js +54 -3
- package/src/models/bulkTransfer/individualTransfer.js +2 -2
- package/src/models/ilpPackets/ilpPacket.js +36 -0
- package/src/models/ledgerAccountType/ledgerAccountType.js +139 -3
- package/src/models/misc/migrationLock.js +1 -1
- package/src/models/misc/segment.js +1 -1
- package/src/models/participant/facade.js +226 -76
- package/src/models/participant/participant.js +6 -5
- package/src/models/participant/participantCached.js +8 -0
- package/src/models/participant/participantCurrency.js +7 -7
- package/src/models/participant/participantCurrencyCached.js +11 -1
- package/src/models/participant/participantLimit.js +13 -13
- package/src/models/participant/participantLimitCached.js +124 -0
- package/src/models/participant/participantPosition.js +34 -5
- package/src/models/participant/participantPositionChange.js +10 -2
- package/src/models/position/facade.js +112 -18
- package/src/models/position/participantPosition.js +6 -6
- package/src/models/settlement/settlementModel.js +92 -17
- package/src/models/settlement/settlementModelCached.js +139 -0
- package/src/models/transfer/facade.js +97 -32
- package/src/models/transfer/ilpPacket.js +4 -4
- package/src/models/transfer/transfer.js +7 -7
- package/src/models/transfer/transferDuplicateCheck.js +21 -5
- package/src/models/transfer/transferError.js +5 -5
- package/src/models/transfer/transferErrorDuplicateCheck.js +4 -4
- package/src/models/transfer/transferExtension.js +4 -4
- package/src/models/transfer/transferFulfilment.js +5 -5
- package/src/models/transfer/transferFulfilmentDuplicateCheck.js +4 -4
- package/src/models/transfer/transferParticipant.js +3 -3
- package/src/models/transfer/transferStateChange.js +11 -11
- package/src/models/transfer/transferTimeout.js +5 -5
- package/src/schema/bulkTransfer.js +4 -4
- package/src/shared/plugins.js +10 -9
- package/src/shared/setup.js +69 -46
- package/test/integration/domain/participant/index.test.js +2 -0
- package/test/integration/handlers/handlers.test.js +605 -166
- package/test/integration/handlers/root.test.js +1 -1
- package/test/integration/helpers/hubAccounts.js +62 -0
- package/test/integration/helpers/ilpPacket.js +1 -1
- package/test/integration/helpers/participantFundsInOut.js +80 -0
- package/test/integration/helpers/participantLimit.js +6 -1
- package/test/integration/helpers/settlementModels.js +88 -0
- package/test/integration/helpers/testConsumer.js +163 -0
- package/test/integration/helpers/testProducer.js +0 -1
- package/test/integration/helpers/transferDuplicateCheck.js +1 -1
- package/test/integration/helpers/transferStateChange.js +1 -1
- package/test/integration/helpers/transferTestHelper.js +3 -5
- package/test/integration/models/transfer/transferStateChange.test.js +6 -0
- package/test/unit/api/ledgerAccountTypes/handler.test.js +126 -0
- package/test/unit/api/ledgerAccountTypes/routes.test.js +52 -0
- package/test/unit/api/participants/handler.test.js +75 -33
- package/test/unit/api/root/handler.test.js +1 -1
- package/test/unit/api/root/routes.test.js +2 -2
- package/test/unit/api/settlementModels/handler.test.js +21 -57
- package/test/unit/api/transactions/handler.test.js +108 -0
- package/test/unit/api/transactions/routes.test.js +38 -0
- package/test/unit/domain/ledgerAccountTypes/index.test.js +197 -0
- package/test/unit/domain/participant/index.test.js +115 -2
- package/test/unit/domain/settlement/index.test.js +199 -29
- package/test/unit/domain/transactions/index.test.js +128 -0
- package/test/unit/domain/transfer/index.test.js +1 -0
- package/test/unit/domain/transfer/transform.test.js +2 -0
- package/test/unit/handlers/admin/handler.test.js +5 -5
- package/test/unit/handlers/bulk/get/handler.test.js +401 -0
- package/test/unit/handlers/index.test.js +6 -0
- package/test/unit/handlers/positions/handler.test.js +26 -0
- package/test/unit/handlers/register.test.js +2 -0
- package/test/unit/handlers/transfers/handler.test.js +491 -36
- package/test/unit/handlers/transfers/validator.test.js +31 -31
- package/test/unit/lib/cache.test.js +0 -64
- package/test/unit/lib/cachingOfEnums.test.js +121 -0
- package/test/unit/lib/config.test.js +34 -0
- package/test/unit/lib/enum.test.js +6 -1
- package/test/unit/lib/enumCached.test.js +82 -0
- package/test/unit/lib/healthCheck/subServiceHealth.test.js +2 -0
- package/test/unit/lib/requestLogger.test.js +14 -12
- package/test/unit/models/ilpPackets/ilpPacket.test.js +89 -0
- package/test/unit/models/ledgerAccountType/ledgerAccountType.test.js +255 -6
- package/test/unit/models/misc/migrationLock.test.js +4 -0
- package/test/unit/models/misc/segment.test.js +5 -0
- package/test/unit/models/participant/facade.test.js +493 -54
- package/test/unit/models/participant/participant.test.js +4 -0
- package/test/unit/models/participant/participantCurrency.test.js +22 -9
- package/test/unit/models/participant/participantCurrencyCached.test.js +1 -1
- package/test/unit/models/participant/participantLimit.test.js +97 -0
- package/test/unit/models/participant/participantLimitCached.test.js +232 -0
- package/test/unit/models/participant/participantPosition.test.js +217 -0
- package/test/unit/models/participant/participantPositionChange.test.js +3 -0
- package/test/unit/models/position/facade.test.js +318 -29
- package/test/unit/models/position/participantPosition.test.js +22 -7
- package/test/unit/models/settlement/settlementModel.test.js +18 -37
- package/test/unit/models/settlement/settlementModelCached.test.js +171 -0
- package/test/unit/models/transfer/facade.test.js +115 -0
- package/test/unit/models/transfer/ilpPacket.test.js +28 -11
- package/test/unit/models/transfer/transfer.test.js +13 -4
- package/test/unit/models/transfer/transferDuplicateCheck.test.js +4 -0
- package/test/unit/models/transfer/transferError.test.js +5 -1
- package/test/unit/models/transfer/transferErrorDuplicateCheck.test.js +4 -0
- package/test/unit/models/transfer/transferExtension.test.js +26 -9
- package/test/unit/models/transfer/transferFulfilment.test.js +14 -5
- package/test/unit/models/transfer/transferFulfilmentDuplicateCheck.test.js +4 -0
- package/test/unit/models/transfer/transferParticipant.test.js +14 -5
- package/test/unit/models/transfer/transferStateChange.test.js +3 -0
- package/test/unit/models/transfer/transferTimeout.test.js +6 -0
- package/test/unit/seeds/amountType.test.js +6 -22
- package/test/unit/seeds/balanceOfPayments.test.js +6 -22
- package/test/unit/seeds/bulkProcessingState.test.js +84 -0
- package/test/unit/{lib/sidecar/nullClient.test.js → seeds/bulkTransferState.test.js} +36 -39
- package/test/unit/seeds/currency.test.js +6 -22
- package/test/unit/seeds/endpointType.test.js +6 -22
- package/test/unit/seeds/ledgerAccountType.test.js +5 -22
- package/test/unit/seeds/ledgerEntryType.test.js +6 -22
- package/test/unit/seeds/participant.test.js +5 -22
- package/test/unit/seeds/participantLimitType.test.js +6 -22
- package/test/unit/seeds/partyIdentifierType.test.js +6 -22
- package/test/unit/seeds/partyType.test.js +6 -22
- package/test/unit/seeds/settlementState.test.js +5 -22
- package/test/unit/seeds/settlementWindow1State.test.js +5 -22
- package/test/unit/seeds/transactionInitiator.test.js +6 -22
- package/test/unit/seeds/transactionInitiatorType.test.js +6 -22
- package/test/unit/seeds/transactionScenario.test.js +6 -22
- package/test/unit/seeds/transferParticipantRoleType.test.js +6 -22
- package/test/unit/seeds/transferState.test.js +6 -22
- package/test/unit/shared/plugins.test.js +31 -1
- package/test/unit/shared/setup.test.js +25 -36
- package/test/util/helpers.js +37 -2
- package/test/util/randomTransfers.js +1 -1
- package/test/util/scripts/env.sh +6 -5
- package/test/util/scripts/populateTestData.sh +204 -181
- package/test/util/scripts/populateTestDataForLegacySimulator.sh +261 -0
- package/test/util/scripts/restartObjStore.sh +1 -1
- package/test-integration.Dockerfile +15 -15
- package/test.Dockerfile +12 -12
- package/.circleci/_set_up_deploy_envs.sh +0 -47
- package/.dockerignore +0 -17
- package/.ncurc.json +0 -3
- package/server.sh +0 -4
- package/sonar-project.properties +0 -17
- package/src/lib/sidecar/index.js +0 -47
- package/src/lib/sidecar/nullClient.js +0 -18
- package/test/.env +0 -8
- package/test/integration-config.json +0 -367
- package/test/integration-runner.env +0 -31
- package/test/integration-runner.sh +0 -264
- package/test/spec-runner.sh +0 -132
- package/test/unit/lib/sidecar/index.test.js +0 -148
- package/test/unit/models/position/participantLimit.test.js +0 -135
|
@@ -30,7 +30,8 @@ const Uuid = require('uuid4')
|
|
|
30
30
|
const retry = require('async-retry')
|
|
31
31
|
const Logger = require('@mojaloop/central-services-logger')
|
|
32
32
|
const Config = require('../../../src/lib/config')
|
|
33
|
-
const
|
|
33
|
+
const Time = require('@mojaloop/central-services-shared').Util.Time
|
|
34
|
+
const sleep = Time.sleep
|
|
34
35
|
const Db = require('@mojaloop/central-services-database').Db
|
|
35
36
|
const Cache = require('../../../src/lib/cache')
|
|
36
37
|
const Consumer = require('@mojaloop/central-services-stream').Util.Consumer
|
|
@@ -39,13 +40,26 @@ const Utility = require('@mojaloop/central-services-shared').Util.Kafka
|
|
|
39
40
|
const Enum = require('@mojaloop/central-services-shared').Enum
|
|
40
41
|
const ParticipantHelper = require('../helpers/participant')
|
|
41
42
|
const ParticipantLimitHelper = require('../helpers/participantLimit')
|
|
43
|
+
const ParticipantFundsInOutHelper = require('../helpers/participantFundsInOut')
|
|
42
44
|
const ParticipantEndpointHelper = require('../helpers/participantEndpoint')
|
|
45
|
+
const SettlementHelper = require('../helpers/settlementModels')
|
|
46
|
+
const HubAccountsHelper = require('../helpers/hubAccounts')
|
|
43
47
|
const TransferService = require('../../../src/domain/transfer')
|
|
44
48
|
const ParticipantService = require('../../../src/domain/participant')
|
|
45
49
|
const TransferExtensionModel = require('../../../src/models/transfer/transferExtension')
|
|
46
50
|
const Util = require('@mojaloop/central-services-shared').Util
|
|
47
51
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
48
|
-
const {
|
|
52
|
+
const {
|
|
53
|
+
wrapWithRetries,
|
|
54
|
+
getMessagePayloadOrThrow,
|
|
55
|
+
sleepPromise
|
|
56
|
+
} = require('../../util/helpers')
|
|
57
|
+
const TestConsumer = require('../helpers/testConsumer')
|
|
58
|
+
|
|
59
|
+
const ParticipantCached = require('../../../src/models/participant/participantCached')
|
|
60
|
+
const ParticipantCurrencyCached = require('../../../src/models/participant/participantCurrencyCached')
|
|
61
|
+
const ParticipantLimitCached = require('../../../src/models/participant/participantLimitCached')
|
|
62
|
+
const SettlementModelCached = require('../../../src/models/settlement/settlementModelCached')
|
|
49
63
|
|
|
50
64
|
const Handlers = {
|
|
51
65
|
index: require('../../../src/handlers/register'),
|
|
@@ -90,167 +104,238 @@ const testData = {
|
|
|
90
104
|
expiration: new Date((new Date()).getTime() + (24 * 60 * 60 * 1000)) // tomorrow
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
const testDataZAR = {
|
|
108
|
+
amount: {
|
|
109
|
+
currency: 'ZAR',
|
|
110
|
+
amount: 110
|
|
111
|
+
},
|
|
112
|
+
payer: {
|
|
113
|
+
name: 'payerFsp',
|
|
114
|
+
limit: 500
|
|
115
|
+
},
|
|
116
|
+
payee: {
|
|
117
|
+
name: 'payeeFsp',
|
|
118
|
+
limit: 300
|
|
119
|
+
},
|
|
120
|
+
endpoint: {
|
|
121
|
+
base: 'http://localhost:1080',
|
|
122
|
+
email: 'test@example.com'
|
|
123
|
+
},
|
|
124
|
+
now: new Date(),
|
|
125
|
+
expiration: new Date((new Date()).getTime() + (24 * 60 * 60 * 1000)) // tomorrow
|
|
126
|
+
}
|
|
99
127
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const payeeLimitAndInitialPosition = await ParticipantLimitHelper.prepareLimitAndInitialPosition(payee.participant.name, {
|
|
105
|
-
currency: dataObj.amount.currency,
|
|
106
|
-
limit: { value: dataObj.payee.limit }
|
|
107
|
-
})
|
|
128
|
+
const prepareTestData = async (dataObj) => {
|
|
129
|
+
try {
|
|
130
|
+
const payer = await ParticipantHelper.prepareData(dataObj.payer.name, dataObj.amount.currency)
|
|
131
|
+
const payee = await ParticipantHelper.prepareData(dataObj.payee.name, dataObj.amount.currency)
|
|
108
132
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_TRANSFER_PUT', `${dataObj.endpoint.base}/transfers/{{transferId}}`)
|
|
112
|
-
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_TRANSFER_ERROR', `${dataObj.endpoint.base}/transfers/{{transferId}}/error`)
|
|
113
|
-
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_BULK_TRANSFER_POST', `${dataObj.endpoint.base}/bulkTransfers`)
|
|
114
|
-
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_BULK_TRANSFER_PUT', `${dataObj.endpoint.base}/bulkTransfers/{{id}}`)
|
|
115
|
-
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_BULK_TRANSFER_ERROR', `${dataObj.endpoint.base}/bulkTransfers/{{id}}/error`)
|
|
116
|
-
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_QUOTES', `${dataObj.endpoint.base}`)
|
|
117
|
-
}
|
|
133
|
+
const kafkacat = 'GROUP=abc; T=topic; TR=transfer; kafkacat -b localhost -G $GROUP $T-$TR-prepare $T-$TR-position $T-$TR-fulfil $T-$TR-get $T-admin-$TR $T-notification-event $T-bulk-prepare'
|
|
134
|
+
if (debug) console.error(kafkacat)
|
|
118
135
|
|
|
119
|
-
|
|
120
|
-
transferId: Uuid(),
|
|
121
|
-
payerFsp: payer.participant.name,
|
|
122
|
-
payeeFsp: payee.participant.name,
|
|
123
|
-
amount: {
|
|
136
|
+
const payerLimitAndInitialPosition = await ParticipantLimitHelper.prepareLimitAndInitialPosition(payer.participant.name, {
|
|
124
137
|
currency: dataObj.amount.currency,
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
key: 'key2',
|
|
138
|
-
value: 'value2'
|
|
139
|
-
}
|
|
140
|
-
]
|
|
141
|
-
}
|
|
142
|
-
}
|
|
138
|
+
limit: { value: dataObj.payer.limit }
|
|
139
|
+
})
|
|
140
|
+
const payeeLimitAndInitialPosition = await ParticipantLimitHelper.prepareLimitAndInitialPosition(payee.participant.name, {
|
|
141
|
+
currency: dataObj.amount.currency,
|
|
142
|
+
limit: { value: dataObj.payee.limit }
|
|
143
|
+
})
|
|
144
|
+
await ParticipantFundsInOutHelper.recordFundsIn(payer.participant.name, payer.participantCurrencyId2, {
|
|
145
|
+
currency: dataObj.amount.currency,
|
|
146
|
+
amount: 10000
|
|
147
|
+
})
|
|
143
148
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
for (const name of [payer.participant.name, payee.participant.name]) {
|
|
150
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_TRANSFER_POST', `${dataObj.endpoint.base}/transfers`)
|
|
151
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_TRANSFER_PUT', `${dataObj.endpoint.base}/transfers/{{transferId}}`)
|
|
152
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_TRANSFER_ERROR', `${dataObj.endpoint.base}/transfers/{{transferId}}/error`)
|
|
153
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_BULK_TRANSFER_POST', `${dataObj.endpoint.base}/bulkTransfers`)
|
|
154
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_BULK_TRANSFER_PUT', `${dataObj.endpoint.base}/bulkTransfers/{{id}}`)
|
|
155
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_BULK_TRANSFER_ERROR', `${dataObj.endpoint.base}/bulkTransfers/{{id}}/error`)
|
|
156
|
+
await ParticipantEndpointHelper.prepareData(name, 'FSPIOP_CALLBACK_URL_QUOTES', `${dataObj.endpoint.base}`)
|
|
157
|
+
}
|
|
152
158
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
const transferPayload = {
|
|
160
|
+
transferId: Uuid(),
|
|
161
|
+
payerFsp: payer.participant.name,
|
|
162
|
+
payeeFsp: payee.participant.name,
|
|
163
|
+
amount: {
|
|
164
|
+
currency: dataObj.amount.currency,
|
|
165
|
+
amount: dataObj.amount.amount
|
|
166
|
+
},
|
|
167
|
+
ilpPacket: 'AYIBgQAAAAAAAASwNGxldmVsb25lLmRmc3AxLm1lci45T2RTOF81MDdqUUZERmZlakgyOVc4bXFmNEpLMHlGTFGCAUBQU0svMS4wCk5vbmNlOiB1SXlweUYzY3pYSXBFdzVVc05TYWh3CkVuY3J5cHRpb246IG5vbmUKUGF5bWVudC1JZDogMTMyMzZhM2ItOGZhOC00MTYzLTg0NDctNGMzZWQzZGE5OGE3CgpDb250ZW50LUxlbmd0aDogMTM1CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbgpTZW5kZXItSWRlbnRpZmllcjogOTI4MDYzOTEKCiJ7XCJmZWVcIjowLFwidHJhbnNmZXJDb2RlXCI6XCJpbnZvaWNlXCIsXCJkZWJpdE5hbWVcIjpcImFsaWNlIGNvb3BlclwiLFwiY3JlZGl0TmFtZVwiOlwibWVyIGNoYW50XCIsXCJkZWJpdElkZW50aWZpZXJcIjpcIjkyODA2MzkxXCJ9IgA',
|
|
168
|
+
condition: 'GRzLaTP7DJ9t4P-a_BA0WA9wzzlsugf00-Tn6kESAfM',
|
|
169
|
+
expiration: dataObj.expiration,
|
|
170
|
+
extensionList: {
|
|
171
|
+
extension: [
|
|
172
|
+
{
|
|
173
|
+
key: 'key1',
|
|
174
|
+
value: 'value1'
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
key: 'key2',
|
|
178
|
+
value: 'value2'
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
168
182
|
}
|
|
169
|
-
}
|
|
170
183
|
|
|
171
|
-
|
|
184
|
+
const prepareHeaders = {
|
|
185
|
+
'fspiop-source': payer.participant.name,
|
|
186
|
+
'fspiop-destination': payee.participant.name,
|
|
187
|
+
'content-type': 'application/vnd.interoperability.transfers+json;version=1.1'
|
|
188
|
+
}
|
|
189
|
+
const fulfilAbortRejectHeaders = {
|
|
190
|
+
'fspiop-source': payee.participant.name,
|
|
191
|
+
'fspiop-destination': payer.participant.name,
|
|
192
|
+
'content-type': 'application/vnd.interoperability.transfers+json;version=1.1'
|
|
193
|
+
}
|
|
172
194
|
|
|
173
|
-
|
|
174
|
-
|
|
195
|
+
const fulfilPayload = {
|
|
196
|
+
fulfilment: 'UNlJ98hZTY_dsw0cAqw4i_UN3v4utt7CZFB4yfLbVFA',
|
|
197
|
+
completedTimestamp: dataObj.now,
|
|
198
|
+
transferState: 'COMMITTED',
|
|
199
|
+
extensionList: {
|
|
200
|
+
extension: [
|
|
201
|
+
{
|
|
202
|
+
key: 'key1',
|
|
203
|
+
value: 'value1'
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
key: 'key2',
|
|
207
|
+
value: 'value2'
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
175
212
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
213
|
+
const rejectPayload = Object.assign({}, fulfilPayload, { transferState: TransferInternalState.ABORTED_REJECTED })
|
|
214
|
+
|
|
215
|
+
const errorPayload = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PAYEE_FSP_REJECTED_TXN).toApiErrorObject()
|
|
216
|
+
errorPayload.errorInformation.extensionList = { extension: [{ key: 'errorDetail', value: 'This is an abort extension' }] }
|
|
217
|
+
|
|
218
|
+
const messageProtocolPrepare = {
|
|
219
|
+
id: Uuid(),
|
|
220
|
+
from: transferPayload.payerFsp,
|
|
221
|
+
to: transferPayload.payeeFsp,
|
|
222
|
+
type: 'application/json',
|
|
223
|
+
content: {
|
|
224
|
+
headers: prepareHeaders,
|
|
225
|
+
payload: transferPayload
|
|
226
|
+
},
|
|
227
|
+
metadata: {
|
|
228
|
+
event: {
|
|
229
|
+
id: Uuid(),
|
|
230
|
+
type: TransferEventAction.PREPARE,
|
|
231
|
+
action: TransferEventType.PREPARE,
|
|
232
|
+
createdAt: dataObj.now,
|
|
233
|
+
state: {
|
|
234
|
+
status: 'success',
|
|
235
|
+
code: 0
|
|
236
|
+
}
|
|
194
237
|
}
|
|
195
238
|
}
|
|
196
239
|
}
|
|
197
|
-
}
|
|
198
240
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
const messageProtocolFulfil = Util.clone(messageProtocolPrepare)
|
|
242
|
+
messageProtocolFulfil.id = Uuid()
|
|
243
|
+
messageProtocolFulfil.from = transferPayload.payeeFsp
|
|
244
|
+
messageProtocolFulfil.to = transferPayload.payerFsp
|
|
245
|
+
messageProtocolFulfil.content.headers = fulfilAbortRejectHeaders
|
|
246
|
+
messageProtocolFulfil.content.uriParams = { id: transferPayload.transferId }
|
|
247
|
+
messageProtocolFulfil.content.payload = fulfilPayload
|
|
248
|
+
messageProtocolFulfil.metadata.event.id = Uuid()
|
|
249
|
+
messageProtocolFulfil.metadata.event.type = TransferEventType.FULFIL
|
|
250
|
+
messageProtocolFulfil.metadata.event.action = TransferEventAction.COMMIT
|
|
251
|
+
|
|
252
|
+
const messageProtocolReject = Util.clone(messageProtocolFulfil)
|
|
253
|
+
messageProtocolReject.id = Uuid()
|
|
254
|
+
messageProtocolFulfil.content.uriParams = { id: transferPayload.transferId }
|
|
255
|
+
messageProtocolReject.content.payload = rejectPayload
|
|
256
|
+
messageProtocolReject.metadata.event.action = TransferEventAction.REJECT
|
|
257
|
+
|
|
258
|
+
const messageProtocolError = Util.clone(messageProtocolFulfil)
|
|
259
|
+
messageProtocolError.id = Uuid()
|
|
260
|
+
messageProtocolFulfil.content.uriParams = { id: transferPayload.transferId }
|
|
261
|
+
messageProtocolError.content.payload = errorPayload
|
|
262
|
+
messageProtocolError.metadata.event.action = TransferEventAction.ABORT
|
|
263
|
+
|
|
264
|
+
const topicConfTransferPrepare = Utility.createGeneralTopicConf(Config.KAFKA_CONFIG.TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE, TransferEventType.TRANSFER, TransferEventType.PREPARE)
|
|
265
|
+
const topicConfTransferFulfil = Utility.createGeneralTopicConf(Config.KAFKA_CONFIG.TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE, TransferEventType.TRANSFER, TransferEventType.FULFIL)
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
transferPayload,
|
|
269
|
+
fulfilPayload,
|
|
270
|
+
rejectPayload,
|
|
271
|
+
errorPayload,
|
|
272
|
+
messageProtocolPrepare,
|
|
273
|
+
messageProtocolFulfil,
|
|
274
|
+
messageProtocolReject,
|
|
275
|
+
messageProtocolError,
|
|
276
|
+
topicConfTransferPrepare,
|
|
277
|
+
topicConfTransferFulfil,
|
|
278
|
+
payer,
|
|
279
|
+
payerLimitAndInitialPosition,
|
|
280
|
+
payee,
|
|
281
|
+
payeeLimitAndInitialPosition
|
|
282
|
+
}
|
|
283
|
+
} catch (err) {
|
|
284
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
240
285
|
}
|
|
241
286
|
}
|
|
242
287
|
|
|
243
288
|
Test('Handlers test', async handlersTest => {
|
|
244
289
|
const startTime = new Date()
|
|
290
|
+
await Db.connect(Config.DATABASE)
|
|
291
|
+
await ParticipantCached.initialize()
|
|
292
|
+
await ParticipantCurrencyCached.initialize()
|
|
293
|
+
await ParticipantLimitCached.initialize()
|
|
294
|
+
await SettlementModelCached.initialize()
|
|
295
|
+
await Cache.initCache()
|
|
296
|
+
await SettlementHelper.prepareData()
|
|
297
|
+
await HubAccountsHelper.prepareData()
|
|
298
|
+
|
|
299
|
+
// Start a testConsumer to monitor events that our handlers emit
|
|
300
|
+
const testConsumer = new TestConsumer([
|
|
301
|
+
{
|
|
302
|
+
topicName: Utility.transformGeneralTopicName(
|
|
303
|
+
Config.KAFKA_CONFIG.TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE,
|
|
304
|
+
Enum.Events.Event.Type.TRANSFER,
|
|
305
|
+
Enum.Events.Event.Action.FULFIL
|
|
306
|
+
),
|
|
307
|
+
config: Utility.getKafkaConfig(
|
|
308
|
+
Config.KAFKA_CONFIG,
|
|
309
|
+
Enum.Kafka.Config.CONSUMER,
|
|
310
|
+
Enum.Events.Event.Type.TRANSFER.toUpperCase(),
|
|
311
|
+
Enum.Events.Event.Action.FULFIL.toUpperCase()
|
|
312
|
+
)
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
topicName: Utility.transformGeneralTopicName(
|
|
316
|
+
Config.KAFKA_CONFIG.TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE,
|
|
317
|
+
Enum.Events.Event.Type.NOTIFICATION,
|
|
318
|
+
Enum.Events.Event.Action.EVENT
|
|
319
|
+
),
|
|
320
|
+
config: Utility.getKafkaConfig(
|
|
321
|
+
Config.KAFKA_CONFIG,
|
|
322
|
+
Enum.Kafka.Config.CONSUMER,
|
|
323
|
+
Enum.Events.Event.Type.NOTIFICATION.toUpperCase(),
|
|
324
|
+
Enum.Events.Event.Action.EVENT.toUpperCase()
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
])
|
|
328
|
+
|
|
245
329
|
await handlersTest.test('registerAllHandlers should', async registerAllHandlers => {
|
|
246
330
|
await registerAllHandlers.test('setup handlers', async (test) => {
|
|
247
|
-
await Db.connect(Config.DATABASE)
|
|
248
|
-
await Cache.initCache()
|
|
249
331
|
await Handlers.transfers.registerPrepareHandler()
|
|
250
332
|
await Handlers.positions.registerPositionHandler()
|
|
251
333
|
await Handlers.transfers.registerFulfilHandler()
|
|
252
334
|
await Handlers.timeouts.registerTimeoutHandler()
|
|
253
335
|
|
|
336
|
+
// Set up the testConsumer here
|
|
337
|
+
await testConsumer.startListening()
|
|
338
|
+
|
|
254
339
|
sleep(rebalanceDelay, debug, 'registerAllHandlers', 'awaiting registration of common handlers')
|
|
255
340
|
|
|
256
341
|
test.pass('done')
|
|
@@ -260,6 +345,312 @@ Test('Handlers test', async handlersTest => {
|
|
|
260
345
|
await registerAllHandlers.end()
|
|
261
346
|
})
|
|
262
347
|
|
|
348
|
+
await handlersTest.test('transferFulfilReserve should', async transferFulfilReserve => {
|
|
349
|
+
await transferFulfilReserve.test('Does not send a RESERVED_ABORTED notification when the Payee aborts the transfer', async (test) => {
|
|
350
|
+
// Arrange
|
|
351
|
+
const td = await prepareTestData(testData)
|
|
352
|
+
|
|
353
|
+
// 1. send a PREPARE request (from Payer)
|
|
354
|
+
const prepareConfig = Utility.getKafkaConfig(
|
|
355
|
+
Config.KAFKA_CONFIG,
|
|
356
|
+
Enum.Kafka.Config.PRODUCER,
|
|
357
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
358
|
+
TransferEventType.PREPARE.toUpperCase())
|
|
359
|
+
prepareConfig.logger = Logger
|
|
360
|
+
await Producer.produceMessage(td.messageProtocolPrepare, td.topicConfTransferPrepare, prepareConfig)
|
|
361
|
+
const transfer = await wrapWithRetries(async () => {
|
|
362
|
+
// lets fetch the transfer
|
|
363
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
364
|
+
// lets check its status, and if its what we expect return the result
|
|
365
|
+
if (transfer.transferState === 'RESERVED') return transfer
|
|
366
|
+
// otherwise lets return nothing
|
|
367
|
+
return null
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
test.equal(transfer.transferState, 'RESERVED', 'Transfer is in reserved state')
|
|
371
|
+
|
|
372
|
+
// 2. send an ABORTED request from Payee
|
|
373
|
+
td.messageProtocolFulfil.metadata.event.action = TransferEventAction.RESERVE
|
|
374
|
+
const completedTimestamp = Time.getUTCString(new Date())
|
|
375
|
+
td.messageProtocolFulfil.content.payload = {
|
|
376
|
+
...td.messageProtocolFulfil.content.payload,
|
|
377
|
+
completedTimestamp,
|
|
378
|
+
transferState: 'ABORTED'
|
|
379
|
+
}
|
|
380
|
+
const fulfilConfig = Utility.getKafkaConfig(
|
|
381
|
+
Config.KAFKA_CONFIG,
|
|
382
|
+
Enum.Kafka.Config.PRODUCER,
|
|
383
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
384
|
+
TransferEventType.FULFIL.toUpperCase())
|
|
385
|
+
fulfilConfig.logger = Logger
|
|
386
|
+
await Producer.produceMessage(td.messageProtocolFulfil, td.topicConfTransferFulfil, fulfilConfig)
|
|
387
|
+
|
|
388
|
+
// Assert
|
|
389
|
+
// 3. Check that we didn't sent a notification for the Payee
|
|
390
|
+
try {
|
|
391
|
+
await wrapWithRetries(() => testConsumer.getEventsForFilter({
|
|
392
|
+
topicFilter: 'topic-notification-event',
|
|
393
|
+
action: 'reserved-aborted'
|
|
394
|
+
}))
|
|
395
|
+
test.notOk('Should not be executed')
|
|
396
|
+
} catch (err) {
|
|
397
|
+
console.log(err)
|
|
398
|
+
test.ok('No payee abort notification sent')
|
|
399
|
+
}
|
|
400
|
+
console.log(JSON.stringify(testConsumer.getAllEvents()))
|
|
401
|
+
|
|
402
|
+
// TODO: I can't seem to find the payer abort notification in the log
|
|
403
|
+
// is there something I'm missing here? Does it go to a different handler?
|
|
404
|
+
|
|
405
|
+
// 4. Check that we sent 1 notification for the payer
|
|
406
|
+
// const payerAbortNotification = (await wrapWithRetries(() => testConsumer.getEventsForFilter({
|
|
407
|
+
// topicFilter: 'topic-notification-event',
|
|
408
|
+
// action: 'abort'
|
|
409
|
+
// })))[0]
|
|
410
|
+
// test.ok(payerAbortNotification, 'Payer Abort notification sent')
|
|
411
|
+
|
|
412
|
+
// Cleanup
|
|
413
|
+
testConsumer.clearEvents()
|
|
414
|
+
test.end()
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
await transferFulfilReserve.test('send a RESERVED_ABORTED notification if the transfer is expired', async (test) => {
|
|
418
|
+
// Arrange
|
|
419
|
+
const customTestData = {
|
|
420
|
+
...testData,
|
|
421
|
+
expiration: new Date((new Date()).getTime() + (2 * 1000)) // 2 seconds
|
|
422
|
+
}
|
|
423
|
+
const td = await prepareTestData(customTestData)
|
|
424
|
+
|
|
425
|
+
// 1. send a PREPARE request (from Payer)
|
|
426
|
+
const prepareConfig = Utility.getKafkaConfig(
|
|
427
|
+
Config.KAFKA_CONFIG,
|
|
428
|
+
Enum.Kafka.Config.PRODUCER,
|
|
429
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
430
|
+
TransferEventType.PREPARE.toUpperCase())
|
|
431
|
+
prepareConfig.logger = Logger
|
|
432
|
+
await Producer.produceMessage(td.messageProtocolPrepare, td.topicConfTransferPrepare, prepareConfig)
|
|
433
|
+
const transfer = await wrapWithRetries(async () => {
|
|
434
|
+
// lets fetch the transfer
|
|
435
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
436
|
+
// lets check its status, and if its what we expect return the result
|
|
437
|
+
if (transfer.transferState === 'RESERVED') return transfer
|
|
438
|
+
// otherwise lets return nothing
|
|
439
|
+
return null
|
|
440
|
+
})
|
|
441
|
+
test.equal(transfer.transferState, 'RESERVED', 'Transfer is in reserved state')
|
|
442
|
+
|
|
443
|
+
// 2. sleep so that the RESERVED transfer expires
|
|
444
|
+
await sleepPromise(2)
|
|
445
|
+
|
|
446
|
+
// 3. send a RESERVED request from Payee
|
|
447
|
+
td.messageProtocolFulfil.metadata.event.action = TransferEventAction.RESERVE
|
|
448
|
+
const completedTimestamp = Time.getUTCString(new Date())
|
|
449
|
+
td.messageProtocolFulfil.content.payload = {
|
|
450
|
+
...td.messageProtocolFulfil.content.payload,
|
|
451
|
+
completedTimestamp,
|
|
452
|
+
transferState: 'RESERVED'
|
|
453
|
+
}
|
|
454
|
+
const fulfilConfig = Utility.getKafkaConfig(
|
|
455
|
+
Config.KAFKA_CONFIG,
|
|
456
|
+
Enum.Kafka.Config.PRODUCER,
|
|
457
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
458
|
+
TransferEventType.FULFIL.toUpperCase())
|
|
459
|
+
fulfilConfig.logger = Logger
|
|
460
|
+
await Producer.produceMessage(td.messageProtocolFulfil, td.topicConfTransferFulfil, fulfilConfig)
|
|
461
|
+
|
|
462
|
+
// 4. Get the updated transfer since the completedTimestamp may have changed
|
|
463
|
+
const updatedTransfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
464
|
+
const expectedAbortNotificationPayload = {
|
|
465
|
+
completedTimestamp: Time.getUTCString(new Date(updatedTransfer.completedTimestamp)),
|
|
466
|
+
transferState: 'ABORTED'
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Assert
|
|
470
|
+
// 5. Check that we sent 2 notifications to kafka - one for the Payee, one for the Payer
|
|
471
|
+
const payerAbortNotification = (await wrapWithRetries(
|
|
472
|
+
() => testConsumer.getEventsForFilter({ topicFilter: 'topic-notification-event', action: 'commit' }))
|
|
473
|
+
)[0]
|
|
474
|
+
const payeeAbortNotification = (await wrapWithRetries(
|
|
475
|
+
() => testConsumer.getEventsForFilter({ topicFilter: 'topic-notification-event', action: 'reserved-aborted' }))
|
|
476
|
+
)[0]
|
|
477
|
+
test.ok(payerAbortNotification, 'Payer Abort notification sent')
|
|
478
|
+
test.ok(payeeAbortNotification, 'Payee Abort notification sent')
|
|
479
|
+
|
|
480
|
+
test.deepEqual(
|
|
481
|
+
getMessagePayloadOrThrow(payeeAbortNotification),
|
|
482
|
+
expectedAbortNotificationPayload,
|
|
483
|
+
'Abort notification should be sent with the correct values'
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
// Cleanup
|
|
487
|
+
testConsumer.clearEvents()
|
|
488
|
+
test.end()
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
await transferFulfilReserve.test('send a RESERVED_ABORTED notification when the transfer is not in a RESERVED state', async (test) => {
|
|
492
|
+
// Arrange
|
|
493
|
+
const td = await prepareTestData(testData)
|
|
494
|
+
|
|
495
|
+
// 1. send a PREPARE request (from Payer)
|
|
496
|
+
const prepareConfig = Utility.getKafkaConfig(
|
|
497
|
+
Config.KAFKA_CONFIG,
|
|
498
|
+
Enum.Kafka.Config.PRODUCER,
|
|
499
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
500
|
+
TransferEventType.PREPARE.toUpperCase())
|
|
501
|
+
prepareConfig.logger = Logger
|
|
502
|
+
await Producer.produceMessage(td.messageProtocolPrepare, td.topicConfTransferPrepare, prepareConfig)
|
|
503
|
+
const transfer = await wrapWithRetries(async () => {
|
|
504
|
+
// lets fetch the transfer
|
|
505
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
506
|
+
// lets check its status, and if its what we expect return the result
|
|
507
|
+
if (transfer.transferState === 'RESERVED') return transfer
|
|
508
|
+
// otherwise lets return nothing
|
|
509
|
+
return null
|
|
510
|
+
})
|
|
511
|
+
test.equal(transfer.transferState, 'RESERVED', 'Transfer is in reserved state')
|
|
512
|
+
|
|
513
|
+
// 2. Modify the transfer in the DB
|
|
514
|
+
await TransferService.saveTransferStateChange({
|
|
515
|
+
transferId: transfer.transferId,
|
|
516
|
+
transferStateId: 'INVALID'
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
// 3. send a RESERVED request from Payee
|
|
520
|
+
td.messageProtocolFulfil.metadata.event.action = TransferEventAction.RESERVE
|
|
521
|
+
const completedTimestamp = Time.getUTCString(new Date())
|
|
522
|
+
td.messageProtocolFulfil.content.payload = {
|
|
523
|
+
...td.messageProtocolFulfil.content.payload,
|
|
524
|
+
completedTimestamp,
|
|
525
|
+
transferState: 'RESERVED'
|
|
526
|
+
}
|
|
527
|
+
const fulfilConfig = Utility.getKafkaConfig(
|
|
528
|
+
Config.KAFKA_CONFIG,
|
|
529
|
+
Enum.Kafka.Config.PRODUCER,
|
|
530
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
531
|
+
TransferEventType.FULFIL.toUpperCase())
|
|
532
|
+
fulfilConfig.logger = Logger
|
|
533
|
+
await Producer.produceMessage(td.messageProtocolFulfil, td.topicConfTransferFulfil, fulfilConfig)
|
|
534
|
+
|
|
535
|
+
// 4. Get the updated transfer since the completedTimestamp may have changed
|
|
536
|
+
const updatedTransfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
537
|
+
const expectedAbortNotificationPayload = {
|
|
538
|
+
completedTimestamp: Time.getUTCString(new Date(updatedTransfer.completedTimestamp)),
|
|
539
|
+
transferState: 'ABORTED'
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Assert
|
|
543
|
+
// 5. Check that we sent 2 notifications to kafka - one for the Payee, one for the Payer
|
|
544
|
+
try {
|
|
545
|
+
const payerAbortNotification = (await wrapWithRetries(
|
|
546
|
+
() => testConsumer.getEventsForFilter({ topicFilter: 'topic-notification-event', action: 'commit' }))
|
|
547
|
+
)[0]
|
|
548
|
+
test.ok(payerAbortNotification, 'Payer Abort notification sent')
|
|
549
|
+
} catch (err) {
|
|
550
|
+
test.notOk('No payerAbortNotification was sent')
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
const payeeAbortNotification = (await wrapWithRetries(
|
|
554
|
+
() => testConsumer.getEventsForFilter({ topicFilter: 'topic-notification-event', action: 'reserved-aborted' }))
|
|
555
|
+
)[0]
|
|
556
|
+
test.ok(payeeAbortNotification, 'Payee Abort notification sent')
|
|
557
|
+
test.deepEqual(
|
|
558
|
+
getMessagePayloadOrThrow(payeeAbortNotification),
|
|
559
|
+
expectedAbortNotificationPayload,
|
|
560
|
+
'Abort notification should be sent with the correct values'
|
|
561
|
+
)
|
|
562
|
+
} catch (err) {
|
|
563
|
+
test.notOk('No payeeAbortNotification was sent')
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Cleanup
|
|
567
|
+
testConsumer.clearEvents()
|
|
568
|
+
test.end()
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
await transferFulfilReserve.test('send a RESERVED_ABORTED notification when the validation fails', async (test) => {
|
|
572
|
+
// Arrange
|
|
573
|
+
const td = await prepareTestData(testData)
|
|
574
|
+
|
|
575
|
+
// 1. send a PREPARE request (from Payer)
|
|
576
|
+
const prepareConfig = Utility.getKafkaConfig(
|
|
577
|
+
Config.KAFKA_CONFIG,
|
|
578
|
+
Enum.Kafka.Config.PRODUCER,
|
|
579
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
580
|
+
TransferEventType.PREPARE.toUpperCase())
|
|
581
|
+
prepareConfig.logger = Logger
|
|
582
|
+
await Producer.produceMessage(td.messageProtocolPrepare, td.topicConfTransferPrepare, prepareConfig)
|
|
583
|
+
const transfer = await wrapWithRetries(async () => {
|
|
584
|
+
// lets fetch the transfer
|
|
585
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
586
|
+
// lets check its status, and if its what we expect return the result
|
|
587
|
+
if (transfer.transferState === 'RESERVED') return transfer
|
|
588
|
+
// otherwise lets return nothing
|
|
589
|
+
return null
|
|
590
|
+
})
|
|
591
|
+
test.equal(transfer.transferState, 'RESERVED', 'Transfer is in reserved state')
|
|
592
|
+
|
|
593
|
+
// 2. send a RESERVED request with an invalid validation(from Payee)
|
|
594
|
+
td.messageProtocolFulfil.metadata.event.action = TransferEventAction.RESERVE
|
|
595
|
+
const completedTimestamp = Time.getUTCString(new Date())
|
|
596
|
+
td.messageProtocolFulfil.content.payload = {
|
|
597
|
+
fulfilment: 'INVALIDZTY_dsw0cAqw4i_UN3v4utt7CZFB4yfLbVFA',
|
|
598
|
+
completedTimestamp,
|
|
599
|
+
transferState: 'RESERVED'
|
|
600
|
+
}
|
|
601
|
+
const fulfilConfig = Utility.getKafkaConfig(
|
|
602
|
+
Config.KAFKA_CONFIG,
|
|
603
|
+
Enum.Kafka.Config.PRODUCER,
|
|
604
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
605
|
+
TransferEventType.FULFIL.toUpperCase())
|
|
606
|
+
fulfilConfig.logger = Logger
|
|
607
|
+
await Producer.produceMessage(td.messageProtocolFulfil, td.topicConfTransferFulfil, fulfilConfig)
|
|
608
|
+
|
|
609
|
+
await wrapWithRetries(async () => {
|
|
610
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
611
|
+
return transfer.transferState === 'ABORTED_ERROR'
|
|
612
|
+
})
|
|
613
|
+
const updatedTransfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId)
|
|
614
|
+
test.equal(updatedTransfer.transferState, 'ABORTED_ERROR', 'Transfer is in ABORTED_ERROR state')
|
|
615
|
+
const expectedAbortNotificationPayload = {
|
|
616
|
+
completedTimestamp: (new Date(Date.parse(updatedTransfer.completedTimestamp))).toISOString(),
|
|
617
|
+
transferState: 'ABORTED'
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Assert
|
|
621
|
+
// 3. Check that we sent 2 notifications to kafka - one for the Payee, one for the Payer
|
|
622
|
+
const payerAbortNotificationEvent = (await wrapWithRetries(
|
|
623
|
+
() => testConsumer.getEventsForFilter({ topicFilter: 'topic-notification-event', action: 'abort-validation' }))
|
|
624
|
+
)[0]
|
|
625
|
+
const payeeAbortNotificationEvent = (await wrapWithRetries(
|
|
626
|
+
() => testConsumer.getEventsForFilter({ topicFilter: 'topic-notification-event', action: 'reserved-aborted' }))
|
|
627
|
+
)[0]
|
|
628
|
+
test.ok(payerAbortNotificationEvent, 'Payer Abort notification sent')
|
|
629
|
+
test.ok(payeeAbortNotificationEvent, 'Payee Abort notification sent')
|
|
630
|
+
|
|
631
|
+
// grab kafka message
|
|
632
|
+
const payerAbortNotificationPayload = getMessagePayloadOrThrow(payeeAbortNotificationEvent)
|
|
633
|
+
|
|
634
|
+
test.equal(
|
|
635
|
+
payerAbortNotificationPayload.transferState,
|
|
636
|
+
expectedAbortNotificationPayload.transferState,
|
|
637
|
+
'Abort notification should be sent with the correct transferState'
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
test.equal(
|
|
641
|
+
payerAbortNotificationPayload.completedTimestamp,
|
|
642
|
+
expectedAbortNotificationPayload.completedTimestamp,
|
|
643
|
+
'Abort notification should be sent with the correct completedTimestamp'
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
// Cleanup
|
|
647
|
+
testConsumer.clearEvents()
|
|
648
|
+
test.end()
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
transferFulfilReserve.end()
|
|
652
|
+
})
|
|
653
|
+
|
|
263
654
|
await handlersTest.test('transferFulfilCommit should', async transferFulfilCommit => {
|
|
264
655
|
const td = await prepareTestData(testData)
|
|
265
656
|
|
|
@@ -291,7 +682,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
291
682
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
292
683
|
if (transfer.transferState !== TransferState.RESERVED) {
|
|
293
684
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
294
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
685
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#1 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
295
686
|
}
|
|
296
687
|
return tests()
|
|
297
688
|
}, retryOpts)
|
|
@@ -331,7 +722,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
331
722
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
332
723
|
if (transfer.transferState !== TransferState.COMMITTED) {
|
|
333
724
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
334
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
725
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#2 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
335
726
|
}
|
|
336
727
|
return tests()
|
|
337
728
|
}, retryOpts)
|
|
@@ -345,11 +736,9 @@ Test('Handlers test', async handlersTest => {
|
|
|
345
736
|
transferFulfilCommit.end()
|
|
346
737
|
})
|
|
347
738
|
|
|
348
|
-
await handlersTest.test('
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
await transferFulfilReject.test('update transfer state to RESERVED by PREPARE request', async (test) => {
|
|
739
|
+
await handlersTest.test('tranferFulfilCommit with default settlement model should', async transferFulfilCommit => {
|
|
740
|
+
const td = await prepareTestData(testDataZAR)
|
|
741
|
+
await transferFulfilCommit.test('update transfer state to RESERVED by PREPARE request', async (test) => {
|
|
353
742
|
const config = Utility.getKafkaConfig(
|
|
354
743
|
Config.KAFKA_CONFIG,
|
|
355
744
|
Enum.Kafka.Config.PRODUCER,
|
|
@@ -361,8 +750,15 @@ Test('Handlers test', async handlersTest => {
|
|
|
361
750
|
|
|
362
751
|
const tests = async () => {
|
|
363
752
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
753
|
+
const payerCurrentPosition = await ParticipantService.getPositionByParticipantCurrencyId(td.payer.participantCurrencyId) || {}
|
|
754
|
+
const payerInitialPosition = td.payerLimitAndInitialPosition.participantPosition.value
|
|
755
|
+
const payerExpectedPosition = payerInitialPosition + td.transferPayload.amount.amount
|
|
756
|
+
const payerPositionChange = await ParticipantService.getPositionChangeByParticipantPositionId(payerCurrentPosition.participantPositionId) || {}
|
|
364
757
|
test.equal(producerResponse, true, 'Producer for prepare published message')
|
|
365
758
|
test.equal(transfer.transferState, TransferState.RESERVED, `Transfer state changed to ${TransferState.RESERVED}`)
|
|
759
|
+
test.equal(payerCurrentPosition.value, payerExpectedPosition, 'Payer position incremented by transfer amount and updated in participantPosition')
|
|
760
|
+
test.equal(payerPositionChange.value, payerCurrentPosition.value, 'Payer position change value inserted and matches the updated participantPosition value')
|
|
761
|
+
test.equal(payerPositionChange.transferStateChangeId, transfer.transferStateChangeId, 'Payer position change record is bound to the corresponding transfer state change')
|
|
366
762
|
}
|
|
367
763
|
|
|
368
764
|
try {
|
|
@@ -370,7 +766,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
370
766
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
371
767
|
if (transfer.transferState !== TransferState.RESERVED) {
|
|
372
768
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
373
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
769
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#1 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
374
770
|
}
|
|
375
771
|
return tests()
|
|
376
772
|
}, retryOpts)
|
|
@@ -380,8 +776,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
380
776
|
}
|
|
381
777
|
test.end()
|
|
382
778
|
})
|
|
383
|
-
|
|
384
|
-
await transferFulfilReject.test('update transfer state to ABORTED_REJECTED by ABORT request', async (test) => {
|
|
779
|
+
await transferFulfilCommit.test('update transfer state to COMMITTED by FULFIL request', async (test) => {
|
|
385
780
|
const config = Utility.getKafkaConfig(
|
|
386
781
|
Config.KAFKA_CONFIG,
|
|
387
782
|
Enum.Kafka.Config.PRODUCER,
|
|
@@ -389,27 +784,27 @@ Test('Handlers test', async handlersTest => {
|
|
|
389
784
|
TransferEventType.FULFIL.toUpperCase())
|
|
390
785
|
config.logger = Logger
|
|
391
786
|
|
|
392
|
-
const producerResponse = await Producer.produceMessage(td.
|
|
393
|
-
|
|
787
|
+
const producerResponse = await Producer.produceMessage(td.messageProtocolFulfil, td.topicConfTransferFulfil, config)
|
|
394
788
|
const tests = async () => {
|
|
395
789
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
396
|
-
const
|
|
397
|
-
const
|
|
398
|
-
const
|
|
790
|
+
const payeeCurrentPosition = await ParticipantService.getPositionByParticipantCurrencyId(td.payee.participantCurrencyId) || {}
|
|
791
|
+
const payeeInitialPosition = td.payeeLimitAndInitialPosition.participantPosition.value
|
|
792
|
+
const payeeExpectedPosition = payeeInitialPosition - td.transferPayload.amount.amount
|
|
793
|
+
const payeePositionChange = await ParticipantService.getPositionChangeByParticipantPositionId(payeeCurrentPosition.participantPositionId) || {}
|
|
399
794
|
test.equal(producerResponse, true, 'Producer for fulfil published message')
|
|
400
|
-
test.equal(transfer.transferState,
|
|
401
|
-
test.equal(transfer.fulfilment, td.fulfilPayload.fulfilment, '
|
|
402
|
-
test.equal(
|
|
403
|
-
test.equal(
|
|
404
|
-
test.equal(
|
|
795
|
+
test.equal(transfer.transferState, TransferState.COMMITTED, `Transfer state changed to ${TransferState.COMMITTED}`)
|
|
796
|
+
test.equal(transfer.fulfilment, td.fulfilPayload.fulfilment, 'Commit ilpFulfilment saved')
|
|
797
|
+
test.equal(payeeCurrentPosition.value, payeeExpectedPosition, 'Payee position decremented by transfer amount and updated in participantPosition')
|
|
798
|
+
test.equal(payeePositionChange.value, payeeCurrentPosition.value, 'Payee position change value inserted and matches the updated participantPosition value')
|
|
799
|
+
test.equal(payeePositionChange.transferStateChangeId, transfer.transferStateChangeId, 'Payee position change record is bound to the corresponding transfer state change')
|
|
405
800
|
}
|
|
406
801
|
|
|
407
802
|
try {
|
|
408
803
|
await retry(async () => { // use bail(new Error('to break before max retries'))
|
|
409
804
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
410
|
-
if (transfer.transferState !==
|
|
805
|
+
if (transfer.transferState !== TransferState.COMMITTED) {
|
|
411
806
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
412
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
807
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#2 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
413
808
|
}
|
|
414
809
|
return tests()
|
|
415
810
|
}, retryOpts)
|
|
@@ -419,8 +814,44 @@ Test('Handlers test', async handlersTest => {
|
|
|
419
814
|
}
|
|
420
815
|
test.end()
|
|
421
816
|
})
|
|
817
|
+
transferFulfilCommit.end()
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
await handlersTest.test('transferFulfilReject should', async transferFulfilReject => {
|
|
821
|
+
testData.amount.amount = 15
|
|
822
|
+
const td = await prepareTestData(testData)
|
|
823
|
+
|
|
824
|
+
await transferFulfilReject.test('update transfer state to RESERVED by PREPARE request', async (test) => {
|
|
825
|
+
const config = Utility.getKafkaConfig(
|
|
826
|
+
Config.KAFKA_CONFIG,
|
|
827
|
+
Enum.Kafka.Config.PRODUCER,
|
|
828
|
+
TransferEventType.TRANSFER.toUpperCase(),
|
|
829
|
+
TransferEventType.PREPARE.toUpperCase())
|
|
830
|
+
config.logger = Logger
|
|
831
|
+
|
|
832
|
+
const producerResponse = await Producer.produceMessage(td.messageProtocolPrepare, td.topicConfTransferPrepare, config)
|
|
422
833
|
|
|
423
|
-
|
|
834
|
+
const tests = async () => {
|
|
835
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
836
|
+
test.equal(producerResponse, true, 'Producer for prepare published message')
|
|
837
|
+
test.equal(transfer.transferState, TransferState.RESERVED, `Transfer state changed to ${TransferState.RESERVED}`)
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
try {
|
|
841
|
+
await retry(async () => { // use bail(new Error('to break before max retries'))
|
|
842
|
+
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
843
|
+
if (transfer.transferState !== TransferState.RESERVED) {
|
|
844
|
+
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
845
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#3 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
846
|
+
}
|
|
847
|
+
return tests()
|
|
848
|
+
}, retryOpts)
|
|
849
|
+
} catch (err) {
|
|
850
|
+
Logger.error(err)
|
|
851
|
+
test.fail(err.message)
|
|
852
|
+
}
|
|
853
|
+
test.end()
|
|
854
|
+
})
|
|
424
855
|
})
|
|
425
856
|
|
|
426
857
|
await handlersTest.test('transferPrepareExceedLimit should', async transferPrepareExceedLimit => {
|
|
@@ -448,7 +879,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
448
879
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
449
880
|
if (transfer.transferState !== TransferInternalState.ABORTED_REJECTED) {
|
|
450
881
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
451
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
882
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#4 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
452
883
|
}
|
|
453
884
|
return tests()
|
|
454
885
|
}, retryOpts)
|
|
@@ -487,7 +918,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
487
918
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
488
919
|
if (transfer.transferState !== TransferState.RESERVED) {
|
|
489
920
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
490
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
921
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#5 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
491
922
|
}
|
|
492
923
|
return tests()
|
|
493
924
|
}, retryOpts)
|
|
@@ -534,7 +965,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
534
965
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
535
966
|
if (transfer.transferState !== TransferInternalState.ABORTED_ERROR) {
|
|
536
967
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
537
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR,
|
|
968
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `#6 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
538
969
|
}
|
|
539
970
|
return tests()
|
|
540
971
|
}, retryOpts)
|
|
@@ -580,7 +1011,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
580
1011
|
const transfer = await TransferService.getById(td.messageProtocolPrepare.content.payload.transferId) || {}
|
|
581
1012
|
if (transfer.transferState !== TransferState.RESERVED) {
|
|
582
1013
|
if (debug) console.log(`retrying in ${retryDelay / 1000}s..`)
|
|
583
|
-
throw new Error(
|
|
1014
|
+
throw new Error(`#7 Max retry count ${retryCount} reached after ${retryCount * retryDelay / 1000}s. Tests fail`)
|
|
584
1015
|
}
|
|
585
1016
|
return tests()
|
|
586
1017
|
}, retryOpts)
|
|
@@ -595,11 +1026,17 @@ Test('Handlers test', async handlersTest => {
|
|
|
595
1026
|
await timeoutTest.test('position resets after a timeout', async (test) => {
|
|
596
1027
|
// Arrange
|
|
597
1028
|
const payerInitialPosition = td.payerLimitAndInitialPosition.participantPosition.value
|
|
1029
|
+
|
|
598
1030
|
// Act
|
|
599
|
-
|
|
1031
|
+
const payerPositionDidReset = async () => {
|
|
1032
|
+
const payerCurrentPosition = await ParticipantService.getPositionByParticipantCurrencyId(td.payer.participantCurrencyId)
|
|
1033
|
+
return payerCurrentPosition.value === payerInitialPosition
|
|
1034
|
+
}
|
|
1035
|
+
// wait until we know the position reset, or throw after 5 tries
|
|
1036
|
+
await wrapWithRetries(payerPositionDidReset, 10, 4)
|
|
600
1037
|
const payerCurrentPosition = await ParticipantService.getPositionByParticipantCurrencyId(td.payer.participantCurrencyId) || {}
|
|
601
1038
|
|
|
602
|
-
// Assert
|
|
1039
|
+
// Assert
|
|
603
1040
|
test.equal(payerCurrentPosition.value, payerInitialPosition, 'Position resets after a timeout')
|
|
604
1041
|
test.end()
|
|
605
1042
|
})
|
|
@@ -613,6 +1050,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
613
1050
|
await Cache.destroyCache()
|
|
614
1051
|
await Db.disconnect()
|
|
615
1052
|
assert.pass('database connection closed')
|
|
1053
|
+
await testConsumer.destroy()
|
|
616
1054
|
|
|
617
1055
|
const topics = [
|
|
618
1056
|
'topic-transfer-prepare',
|
|
@@ -641,6 +1079,7 @@ Test('Handlers test', async handlersTest => {
|
|
|
641
1079
|
const elapsedTime = Math.round(((new Date()) - startTime) / 100) / 10
|
|
642
1080
|
console.log(`handlers.test.js finished in (${elapsedTime}s)`)
|
|
643
1081
|
}
|
|
1082
|
+
|
|
644
1083
|
assert.end()
|
|
645
1084
|
} catch (err) {
|
|
646
1085
|
Logger.error(`teardown failed with error - ${err}`)
|