diff --git a/package-lock.json b/package-lock.json index d7114f865..d0a87db1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "proxyquire": "2.1.3", "replace": "^1.2.2", "sinon": "17.0.0", - "standard": "17.1.1", + "standard": "17.1.2", "standard-version": "^9.5.0", "tap-spec": "^5.0.0", "tap-xunit": "2.4.1", @@ -5108,9 +5108,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.35.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz", - "integrity": "sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==", + "version": "7.36.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", + "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", "dev": true, "dependencies": { "array-includes": "^3.1.8", @@ -12738,9 +12738,9 @@ } }, "node_modules/standard": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.1.tgz", - "integrity": "sha512-GuqFtDMmpcIMX3R/kLaq+Cm18Pjx6IOpR9KhOYKetmkR5ryCxFtus4rC3JNvSE3l9GarlOZLZpBRHqDA9wY8zw==", + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.2.tgz", + "integrity": "sha512-WLm12WoXveKkvnPnPnaFUUHuOB2cUdAsJ4AiGHL2G0UNMrcRAWY2WriQaV8IQ3oRmYr0AWUbLNr94ekYFAHOrA==", "dev": true, "funding": [ { @@ -12763,7 +12763,7 @@ "eslint-plugin-import": "^2.27.5", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "7.35.2", + "eslint-plugin-react": "^7.36.1", "standard-engine": "^15.1.0", "version-guard": "^1.1.1" }, diff --git a/package.json b/package.json index 81dedb0c5..55275ab12 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "proxyquire": "2.1.3", "replace": "^1.2.2", "sinon": "17.0.0", - "standard": "17.1.1", + "standard": "17.1.2", "standard-version": "^9.5.0", "tap-spec": "^5.0.0", "tap-xunit": "2.4.1", diff --git a/test/integration-override/handlers/transfers/handlers.test.js b/test/integration-override/handlers/transfers/handlers.test.js index 7762ade49..010ae0f86 100644 --- a/test/integration-override/handlers/transfers/handlers.test.js +++ b/test/integration-override/handlers/transfers/handlers.test.js @@ -630,7 +630,7 @@ Test('Handlers test', async handlersTest => { test.end() }) - await transferPrepare.test('send fxTransfer information callback when fxTransfer is RESERVED on duplicate request', async (test) => { + await transferPrepare.test('send fxTransfer information callback when fxTransfer is (RECEIVED_FULFIL_DEPENDENT) RESERVED on duplicate request', async (test) => { const td = await prepareTestData(testData) const prepareConfig = Utility.getKafkaConfig( Config.KAFKA_CONFIG, @@ -684,7 +684,110 @@ Test('Handlers test', async handlersTest => { test.fail(err.message) } - // Resend fx-prepare after state is RESERVED + // Resend fx-prepare after state is RECEIVED_FULFIL_DEPENDENT + await new Promise(resolve => setTimeout(resolve, 2000)) + await Producer.produceMessage(td.messageProtocolFxPrepare, td.topicConfTransferPrepare, prepareConfig) + + // Should send fxTransfer state in callback + // Internal state RECEIVED_FULFIL_DEPENDENT maps to TransferStateEnum.RESERVED enumeration. + try { + const positionPrepare = await wrapWithRetries(() => testConsumer.getEventsForFilter({ + topicFilter: 'topic-notification-event', + action: TransferEventAction.FX_PREPARE_DUPLICATE + }), wrapWithRetriesConf.remainingRetries, wrapWithRetriesConf.timeout) + test.ok(positionPrepare[0], 'Position prepare duplicate message with key found') + // Check if the error message is correct + test.equal(positionPrepare[0].value.content.payload.conversionState, TransferStateEnum.RESERVED) + } catch (err) { + test.notOk('Error should not be thrown') + console.error(err) + } + + test.end() + }) + + await transferPrepare.test('send fxTransfer information callback when fxTransfer is COMMITTED on duplicate request', async (test) => { + const td = await prepareTestData(testData) + const prepareConfig = Utility.getKafkaConfig( + Config.KAFKA_CONFIG, + Enum.Kafka.Config.PRODUCER, + TransferEventType.TRANSFER.toUpperCase(), + TransferEventType.PREPARE.toUpperCase()) + prepareConfig.logger = Logger + const fulfilConfig = Utility.getKafkaConfig( + Config.KAFKA_CONFIG, + Enum.Kafka.Config.PRODUCER, + TransferEventType.TRANSFER.toUpperCase(), + TransferEventType.FULFIL.toUpperCase()) + fulfilConfig.logger = Logger + + // Set up the fxTransfer + await Producer.produceMessage(td.messageProtocolFxPrepare, td.topicConfTransferPrepare, prepareConfig) + try { + const positionPrepare = await wrapWithRetries(() => testConsumer.getEventsForFilter({ + topicFilter: 'topic-transfer-position-batch', + action: TransferEventAction.FX_PREPARE, + // To be keyed with the Payer DFSP participantCurrencyId + keyFilter: td.payer.participantCurrencyId.toString() + }), wrapWithRetriesConf.remainingRetries, wrapWithRetriesConf.timeout) + test.ok(positionPrepare[0], 'Position prepare message with key found') + } catch (err) { + test.notOk('Error should not be thrown') + console.error(err) + } + testConsumer.clearEvents() + + await new Promise(resolve => setTimeout(resolve, 2000)) + await Producer.produceMessage(td.messageProtocolFxFulfil, td.topicConfTransferFulfil, fulfilConfig) + try { + const positionFxFulfil = await wrapWithRetries(() => testConsumer.getEventsForFilter({ + topicFilter: 'topic-notification-event', + action: TransferEventAction.FX_RESERVE, + valueToFilter: td.payer.name + }), wrapWithRetriesConf.remainingRetries, wrapWithRetriesConf.timeout) + test.ok(positionFxFulfil[0], 'Position fulfil message with key found') + } catch (err) { + test.notOk('Error should not be thrown') + console.error(err) + } + testConsumer.clearEvents() + + try { + const fxTransfer = await FxTransferService.getByIdLight(td.messageProtocolFxPrepare.content.payload.commitRequestId) || {} + test.equal(fxTransfer?.fxTransferState, TransferInternalState.RECEIVED_FULFIL_DEPENDENT, 'FxTransfer state updated to RECEIVED_FULFIL_DEPENDENT') + } catch (err) { + Logger.error(err) + test.fail(err.message) + } + + // Complete dependent transfer + await Producer.produceMessage(td.messageProtocolPrepare, td.topicConfTransferPrepare, fulfilConfig) + try { + const positionFxFulfil = await wrapWithRetries(() => testConsumer.getEventsForFilter({ + topicFilter: 'topic-notification-event', + action: TransferEventAction.PREPARE + }), wrapWithRetriesConf.remainingRetries, wrapWithRetriesConf.timeout) + test.ok(positionFxFulfil[0], 'Prepare message with key found') + } catch (err) { + test.notOk('Error should not be thrown') + console.error(err) + } + testConsumer.clearEvents() + + await Producer.produceMessage(td.messageProtocolFulfil, td.topicConfTransferFulfil, fulfilConfig) + try { + const positionFxFulfil = await wrapWithRetries(() => testConsumer.getEventsForFilter({ + topicFilter: 'topic-notification-event', + action: TransferEventAction.COMMIT + }), wrapWithRetriesConf.remainingRetries, wrapWithRetriesConf.timeout) + test.ok(positionFxFulfil[0], 'Fulfil message with key found') + } catch (err) { + test.notOk('Error should not be thrown') + console.error(err) + } + testConsumer.clearEvents() + + // Resend fx-prepare after fxtransfer state is COMMITTED await new Promise(resolve => setTimeout(resolve, 2000)) await Producer.produceMessage(td.messageProtocolFxPrepare, td.topicConfTransferPrepare, prepareConfig)