From 47ebcca9b72e7b1693d6799ee6ccb0ee8d3014e2 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Fri, 18 Oct 2024 16:50:42 +0000 Subject: [PATCH 01/13] feat: call rules during fx quote --- src/handlers/QuotingHandler.js | 2 +- src/model/executeRules.js | 80 ++++++++++++++++++++++++++++++++ src/model/fxQuotes.js | 30 +++++++++++- src/model/quotes.js | 80 ++------------------------------ src/model/rules.js | 3 ++ test/unit/model/fxQuotes.test.js | 3 ++ test/unit/model/quotes.test.js | 14 ++++-- 7 files changed, 131 insertions(+), 81 deletions(-) create mode 100644 src/model/executeRules.js diff --git a/src/handlers/QuotingHandler.js b/src/handlers/QuotingHandler.js index 0daeb8e5..4cdf858c 100644 --- a/src/handlers/QuotingHandler.js +++ b/src/handlers/QuotingHandler.js @@ -212,7 +212,7 @@ class QuotingHandler { try { span = await this.createSpan(requestData) - await model.handleFxQuoteRequest(headers, payload, span, originalPayload) + await model.handleFxQuoteRequest(headers, payload, span, originalPayload, this.cache) this.logger.debug('handlePostFxQuotes is done') } catch (err) { this.logger.error(`error in handlePostFxQuotes: ${err?.stack}`) diff --git a/src/model/executeRules.js b/src/model/executeRules.js new file mode 100644 index 00000000..6b3f8565 --- /dev/null +++ b/src/model/executeRules.js @@ -0,0 +1,80 @@ +const ErrorHandler = require('@mojaloop/central-services-error-handling') + +const rules = require('../../config/rules.json') +const RulesEngine = require('./rules.js') + +module.exports.executeRules = async function executeRules (headers, quoteRequest, originalPayload, payer, payee, operation) { + if (rules.length === 0) { + return [] + } + + const facts = { + operation, + payer, + payee, + payload: quoteRequest, + headers + } + + const { events } = await RulesEngine.run(rules, facts) + + this.writeLog(`Rules engine returned events ${JSON.stringify(events)}`) + + return await this.handleRuleEvents(events, headers, quoteRequest, originalPayload) +} + +module.exports.handleRuleEvents = async function handleRuleEvents (events, headers, payload, originalPayload) { + const quoteRequest = originalPayload || payload + // todo: pass only originalPayload (added this logic only for passing tests) + + // At the time of writing, all events cause the "normal" flow of execution to be interrupted. + // So we'll return false when there have been no events whatsoever. + if (events.length === 0) { + return { terminate: false, quoteRequest, headers } + } + + const { INVALID_QUOTE_REQUEST, INTERCEPT_QUOTE } = RulesEngine.events + + const unhandledEvents = events.filter(ev => !(ev.type in RulesEngine.events)) + + if (unhandledEvents.length > 0) { + // The rules configuration contains events not handled in the code + // TODO: validate supplied rules at startup and fail if any invalid rules are discovered. + throw new Error('Unhandled event returned by rules engine') + } + + const invalidQuoteRequestEvents = events.filter(ev => ev.type === INVALID_QUOTE_REQUEST) + if (invalidQuoteRequestEvents.length > 0) { + // Use the first event, ignore the others for now. This is ergonomically worse for someone + // developing against this service, as they can't see all reasons their quote was invalid at + // once. But is a valid solution in the short-term. + const { FSPIOPError: code, message } = invalidQuoteRequestEvents[0].params + // Will throw an internal server error if property doesn't exist + throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes[code], + message, null, headers['fspiop-source']) + } + + const interceptQuoteEvents = events.filter(ev => ev.type === INTERCEPT_QUOTE) + if (interceptQuoteEvents.length > 1) { + // TODO: handle priority. Can we stream events? + throw new Error('Multiple intercept quote events received') + } + if (interceptQuoteEvents.length > 0) { + // send the quote request to the recipient in the event + const result = { + terminate: false, + quoteRequest, + headers: { + ...headers, + 'fspiop-destination': interceptQuoteEvents[0].params.rerouteToFsp + } + } + // if additionalHeaders are present then add the additional non-standard headers (e.g. used by forex) + // Note these headers are not part of the mojaloop specification + if (interceptQuoteEvents[0].params.additionalHeaders) { + result.headers = { ...result.headers, ...interceptQuoteEvents[0].params.additionalHeaders } + result.additionalHeaders = interceptQuoteEvents[0].params.additionalHeaders + } + return result + } +} diff --git a/src/model/fxQuotes.js b/src/model/fxQuotes.js index 105327fa..e9c1f752 100644 --- a/src/model/fxQuotes.js +++ b/src/model/fxQuotes.js @@ -29,9 +29,10 @@ const Metrics = require('@mojaloop/central-services-metrics') const Config = require('../lib/config') const { logger } = require('../lib') const { httpRequest } = require('../lib/http') -const { getStackOrInspect, generateRequestHeadersForJWS, generateRequestHeaders, getParticipantEndpoint, calculateRequestHash } = require('../lib/util') +const { getStackOrInspect, generateRequestHeadersForJWS, generateRequestHeaders, getParticipantEndpoint, calculateRequestHash, fetchParticipantInfo } = require('../lib/util') const LOCAL_ENUM = require('../lib/enum') const { RESOURCES, ERROR_MESSAGES } = require('../constants') +const { executeRules, handleRuleEvents } = require('./executeRules') axios.defaults.headers.common = {} @@ -48,6 +49,10 @@ class FxQuotesModel { }) } + executeRules = executeRules + handleRuleEvents = handleRuleEvents + _fetchParticipantInfo = fetchParticipantInfo + /** * Validates the fxQuote request object * @@ -160,7 +165,7 @@ class FxQuotesModel { * * @returns {undefined} */ - async handleFxQuoteRequest (headers, fxQuoteRequest, span, originalPayload = fxQuoteRequest) { + async handleFxQuoteRequest (headers, fxQuoteRequest, span, originalPayload = fxQuoteRequest, cache) { // todo: remove default value for originalPayload (added just for passing tests) const histTimer = Metrics.getHistogram( 'model_fxquote', @@ -227,6 +232,17 @@ class FxQuotesModel { await txn.commit() } + const { payer, payee } = await this._fetchParticipantInfo(fspiopSource, fspiopDestination, cache) + this.writeLog(`Got payer ${payer} and payee ${payee}`) + + // Run the rules engine. If the user does not want to run the rules engine, they need only to + // supply a rules file containing an empty array. + const handledRuleEvents = await this.executeRules(headers, fxQuoteRequest, originalPayload, payer, payee, 'fxQuoteRequest') + + if (handledRuleEvents.terminate) { + return + } + await this.forwardFxQuoteRequest(headers, fxQuoteRequest.conversionRequestId, originalPayload, childSpan) histTimer({ success: true, queryName: 'handleFxQuoteRequest' }) } catch (err) { @@ -810,6 +826,16 @@ class FxQuotesModel { opts.headers['fspiop-signature'] = jwsSigner.getSignature(opts) } } + + /** + * Writes a formatted message to the console + * + * @returns {undefined} + */ + // eslint-disable-next-line no-unused-vars + writeLog (message) { + Logger.isDebugEnabled && Logger.debug(`(${this.requestId}) [quotesmodel]: ${message}`) + } } module.exports = FxQuotesModel diff --git a/src/model/quotes.js b/src/model/quotes.js index f5ce3605..9ef19a99 100644 --- a/src/model/quotes.js +++ b/src/model/quotes.js @@ -52,8 +52,7 @@ const { httpRequest } = require('../lib/http') const { getStackOrInspect, generateRequestHeadersForJWS, generateRequestHeaders, calculateRequestHash, fetchParticipantInfo, getParticipantEndpoint } = require('../lib/util') const { RESOURCES } = require('../constants') const LOCAL_ENUM = require('../lib/enum') -const rules = require('../../config/rules.json') -const RulesEngine = require('./rules.js') +const { executeRules, handleRuleEvents } = require('./executeRules') delete axios.defaults.headers.common.Accept delete axios.defaults.headers.common['Content-Type'] @@ -75,79 +74,11 @@ class QuotesModel { }) } - async executeRules (headers, quoteRequest, payer, payee) { - if (rules.length === 0) { - return [] - } - - const facts = { - payer, - payee, - payload: quoteRequest, - headers - } - - const { events } = await RulesEngine.run(rules, facts) - this.log.debug('Rules engine returned events:', { events }) - - return events + executeRules () { + return executeRules.apply(this, arguments) } - async handleRuleEvents (events, headers, payload, originalPayload) { - const quoteRequest = originalPayload || payload - // todo: pass only originalPayload (added this logic only for passing tests) - - // At the time of writing, all events cause the "normal" flow of execution to be interrupted. - // So we'll return false when there have been no events whatsoever. - if (events.length === 0) { - return { terminate: false, quoteRequest, headers } - } - - const { INVALID_QUOTE_REQUEST, INTERCEPT_QUOTE } = RulesEngine.events - - const unhandledEvents = events.filter(ev => !(ev.type in RulesEngine.events)) - - if (unhandledEvents.length > 0) { - // The rules configuration contains events not handled in the code - // TODO: validate supplied rules at startup and fail if any invalid rules are discovered. - throw new Error('Unhandled event returned by rules engine') - } - - const invalidQuoteRequestEvents = events.filter(ev => ev.type === INVALID_QUOTE_REQUEST) - if (invalidQuoteRequestEvents.length > 0) { - // Use the first event, ignore the others for now. This is ergonomically worse for someone - // developing against this service, as they can't see all reasons their quote was invalid at - // once. But is a valid solution in the short-term. - const { FSPIOPError: code, message } = invalidQuoteRequestEvents[0].params - // Will throw an internal server error if property doesn't exist - throw ErrorHandler.CreateFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes[code], - message, null, headers['fspiop-source']) - } - - const interceptQuoteEvents = events.filter(ev => ev.type === INTERCEPT_QUOTE) - if (interceptQuoteEvents.length > 1) { - // TODO: handle priority. Can we stream events? - throw new Error('Multiple intercept quote events received') - } - if (interceptQuoteEvents.length > 0) { - // send the quote request to the recipient in the event - const result = { - terminate: false, - quoteRequest, - headers: { - ...headers, - 'fspiop-destination': interceptQuoteEvents[0].params.rerouteToFsp - } - } - // if additionalHeaders are present then add the additional non-standard headers (e.g. used by forex) - // Note these headers are not part of the mojaloop specification - if (interceptQuoteEvents[0].params.additionalHeaders) { - result.headers = { ...result.headers, ...interceptQuoteEvents[0].params.additionalHeaders } - result.additionalHeaders = interceptQuoteEvents[0].params.additionalHeaders - } - return result - } - } + handleRuleEvents = handleRuleEvents /** * Validates the quote request object @@ -281,9 +212,8 @@ class QuotesModel { // Run the rules engine. If the user does not want to run the rules engine, they need only to // supply a rules file containing an empty array. - const events = await this.executeRules(headers, quoteRequest, payer, payee) + handledRuleEvents = await this.executeRules(headers, quoteRequest, originalPayload, payer, payee, 'quoteRequest') - handledRuleEvents = await this.handleRuleEvents(events, headers, quoteRequest, originalPayload) if (handledRuleEvents.terminate) { return } diff --git a/src/model/rules.js b/src/model/rules.js index c8d0a430..aceebe64 100644 --- a/src/model/rules.js +++ b/src/model/rules.js @@ -59,6 +59,9 @@ const createEngine = () => { } } + engine.addOperator('truthy', (factValue, ruleValue) => { + return !!factValue === ruleValue + }) engine.addOperator('notDeepEqual', (factValue, ruleValue) => { return !deepEqual(factValue, ruleValue) }) diff --git a/test/unit/model/fxQuotes.test.js b/test/unit/model/fxQuotes.test.js index dd141e8d..fd225751 100644 --- a/test/unit/model/fxQuotes.test.js +++ b/test/unit/model/fxQuotes.test.js @@ -136,6 +136,7 @@ describe('FxQuotesModel Tests -->', () => { describe('handleFxQuoteRequest', () => { test('should handle fx quote request', async () => { fxQuotesModel = new FxQuotesModel({ db, requestId, proxyClient, log }) + fxQuotesModel._fetchParticipantInfo = jest.fn(() => ({ payer: 'payer', payee: 'payee' })) jest.spyOn(fxQuotesModel, 'forwardFxQuoteRequest').mockResolvedValue() jest.spyOn(fxQuotesModel, 'validateFxQuoteRequest') @@ -175,6 +176,7 @@ describe('FxQuotesModel Tests -->', () => { test('should handle fx quote request in persistent mode', async () => { fxQuotesModel = new FxQuotesModel({ db, requestId, proxyClient, log }) + fxQuotesModel._fetchParticipantInfo = jest.fn(() => ({ payer: 'payer', payee: 'payee' })) fxQuotesModel.envConfig.simpleRoutingMode = false jest.spyOn(fxQuotesModel, 'checkDuplicateFxQuoteRequest').mockResolvedValue({ @@ -215,6 +217,7 @@ describe('FxQuotesModel Tests -->', () => { test('should handle error thrown', async () => { fxQuotesModel = new FxQuotesModel({ db, requestId, proxyClient, log }) + fxQuotesModel._fetchParticipantInfo = jest.fn(() => ({ payer: 'payer', payee: 'payee' })) jest.spyOn(fxQuotesModel, 'forwardFxQuoteRequest').mockRejectedValue(new Error('Forward Error')) jest.spyOn(fxQuotesModel, 'validateFxQuoteRequest') jest.spyOn(fxQuotesModel, 'handleException').mockResolvedValue() diff --git a/test/unit/model/quotes.test.js b/test/unit/model/quotes.test.js index a5eae643..aad75fa5 100644 --- a/test/unit/model/quotes.test.js +++ b/test/unit/model/quotes.test.js @@ -428,9 +428,8 @@ describe('QuotesModel', () => { const payer = { accounts: [{ accountId: 1, ledgerAccountType: 'POSITION', isActive: 1 }] } const payee = { accounts: [{ accountId: 2, ledgerAccountType: 'POSITION', isActive: 1 }] } - await expect(quotesModel.executeRules(mockData.headers, mockData.quoteRequest, payer, payee)) - .resolves - .toEqual(expectedEvents) + await quotesModel.executeRules(mockData.headers, mockData.quoteRequest, payer, payee) + expect(quotesModel.handleRuleEvents).toHaveBeenCalledWith(expectedEvents, expect.anything(), expect.anything(), expect.anything()) }) }) }) @@ -718,6 +717,10 @@ describe('QuotesModel', () => { describe('Failures:', () => { describe('Before forwarding the request:', () => { + beforeEach(() => { + quotesModel.executeRules.mockRestore() + }) + it('throws an exception if `executeRules` fails', async () => { expect.assertions(1) @@ -1012,6 +1015,7 @@ describe('QuotesModel', () => { describe('In case environment is configured for simple routing mode', () => { beforeEach(() => { mockConfig.simpleRoutingMode = true + quotesModel.executeRules.mockRestore() }) it('calls `handleException` with the proper arguments if `span.audit` fails', async () => { @@ -1058,6 +1062,7 @@ describe('QuotesModel', () => { beforeEach(() => { mockConfig.simpleRoutingMode = false + quotesModel.executeRules.mockRestore() expectedResult = { amountTypeId: mockData.amountTypeId, @@ -1138,6 +1143,7 @@ describe('QuotesModel', () => { } })) + quotesModel.executeRules.mockRestore() const result = await quotesModel.handleQuoteRequest(mockData.headers, mockData.quoteRequest, mockSpan) expect(quotesModel.db.createQuoteDuplicateCheck.mock.calls.length).toBe(0) @@ -1149,6 +1155,7 @@ describe('QuotesModel', () => { describe('In case environment is configured for simple routing mode', () => { beforeEach(() => { mockConfig.simpleRoutingMode = true + quotesModel.executeRules.mockRestore() }) it('forwards the quote request properly', async () => { @@ -1174,6 +1181,7 @@ describe('QuotesModel', () => { beforeEach(() => { mockConfig.simpleRoutingMode = false + quotesModel.executeRules.mockRestore() expectedResult = { amountTypeId: mockData.amountTypeId, From d4440d84a7106a5308bc7c1fa533c9891647b005 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 08:26:54 +0000 Subject: [PATCH 02/13] test: fix integration tests --- docker-compose.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index c4a5573c..5acb4b6a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -130,6 +130,7 @@ services: # To use with proxyCache.type === 'redis-cluster' redis-node-0: + container_name: redis-node-0 <<: *REDIS_NODE environment: <<: *REDIS_ENVS @@ -142,6 +143,7 @@ services: - redis-node-4 - redis-node-5 redis-node-1: + container_name: redis-node-1 <<: *REDIS_NODE environment: <<: *REDIS_ENVS @@ -149,6 +151,7 @@ services: ports: - "16380:16380" redis-node-2: + container_name: redis-node-2 <<: *REDIS_NODE environment: <<: *REDIS_ENVS @@ -156,6 +159,7 @@ services: ports: - "16381:16381" redis-node-3: + container_name: redis-node-3 <<: *REDIS_NODE environment: <<: *REDIS_ENVS @@ -163,6 +167,7 @@ services: ports: - "16382:16382" redis-node-4: + container_name: redis-node-4 <<: *REDIS_NODE environment: <<: *REDIS_ENVS @@ -170,6 +175,7 @@ services: ports: - "16383:16383" redis-node-5: + container_name: redis-node-5 <<: *REDIS_NODE environment: <<: *REDIS_ENVS From 5514c840d9537867eb85d65f4ec859e4078c0c40 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 08:47:01 +0000 Subject: [PATCH 03/13] test: fix integration tests --- test/integration/fxQuotes.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration/fxQuotes.test.js b/test/integration/fxQuotes.test.js index 190ea68a..a0a64f08 100644 --- a/test/integration/fxQuotes.test.js +++ b/test/integration/fxQuotes.test.js @@ -122,6 +122,7 @@ describe('POST /fxQuotes request tests --> ', () => { expect(isOk).toBe(true) response = await getResponseWithRetry() + if (response.data.history.length !== 1) console.log(response.data.history) expect(response.data.history.length).toBe(1) // assert that the request was received by the proxy @@ -194,6 +195,7 @@ describe('POST /fxQuotes request tests --> ', () => { expect(isOk).toBe(true) response = await getResponseWithRetry() + if (response.data.history.length !== 1) console.log(response.data.history) expect(response.data.history.length).toBe(1) // assert that the callback was received by the payer dfsp @@ -266,6 +268,7 @@ describe('POST /fxQuotes request tests --> ', () => { expect(isOk).toBe(true) response = await getResponseWithRetry() + if (response.data.history.length !== 1) console.log(response.data.history) expect(response.data.history.length).toBe(1) // assert that the request was received by the payee dfsp From 6ed18ae94076354afa5ac256c83db9412bbf7f9a Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 09:17:25 +0000 Subject: [PATCH 04/13] test: fix integration tests --- test/integration/fxQuotes.test.js | 6 ++---- test/integration/postRequest.test.js | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/integration/fxQuotes.test.js b/test/integration/fxQuotes.test.js index a0a64f08..80b59557 100644 --- a/test/integration/fxQuotes.test.js +++ b/test/integration/fxQuotes.test.js @@ -122,8 +122,7 @@ describe('POST /fxQuotes request tests --> ', () => { expect(isOk).toBe(true) response = await getResponseWithRetry() - if (response.data.history.length !== 1) console.log(response.data.history) - expect(response.data.history.length).toBe(1) + expect(response.data.history.length).toBe(3) // count 2 extra calls to redbank and pinkbank // assert that the request was received by the proxy const request = response.data.history[0] @@ -268,8 +267,7 @@ describe('POST /fxQuotes request tests --> ', () => { expect(isOk).toBe(true) response = await getResponseWithRetry() - if (response.data.history.length !== 1) console.log(response.data.history) - expect(response.data.history.length).toBe(1) + expect(response.data.history.length).toBe(2) // count 1 extra call to greenbank // assert that the request was received by the payee dfsp const request = response.data.history[0] diff --git a/test/integration/postRequest.test.js b/test/integration/postRequest.test.js index aed22f13..57530f54 100644 --- a/test/integration/postRequest.test.js +++ b/test/integration/postRequest.test.js @@ -92,6 +92,7 @@ describe('POST request tests --> ', () => { expect(response.data.history.length).toBeGreaterThan(0) const { url } = response.data.history[0] + console.log('95 ===>', response.data.history) expect(url).toBe(`/${message.to}/quotes`) }) From e97519bfa27e3f88a99f08b043891f3e4006004c Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 12:22:56 +0000 Subject: [PATCH 05/13] fix: github-advanced-security alerts --- test/integration/postRequest.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/postRequest.test.js b/test/integration/postRequest.test.js index 57530f54..6baca154 100644 --- a/test/integration/postRequest.test.js +++ b/test/integration/postRequest.test.js @@ -92,7 +92,7 @@ describe('POST request tests --> ', () => { expect(response.data.history.length).toBeGreaterThan(0) const { url } = response.data.history[0] - console.log('95 ===>', response.data.history) + console.log('95 ===>', response.data.history[0]) expect(url).toBe(`/${message.to}/quotes`) }) From 7c3b66d363bcd14df9f6c7177783549db2f9a1a4 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 13:41:57 +0000 Subject: [PATCH 06/13] fix: executeRules --- src/model/executeRules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/executeRules.js b/src/model/executeRules.js index 6b3f8565..fe9c9b09 100644 --- a/src/model/executeRules.js +++ b/src/model/executeRules.js @@ -5,7 +5,7 @@ const RulesEngine = require('./rules.js') module.exports.executeRules = async function executeRules (headers, quoteRequest, originalPayload, payer, payee, operation) { if (rules.length === 0) { - return [] + this.handleRuleEvents([], headers, quoteRequest, originalPayload) } const facts = { From 9ebe28cf068fc73807365169fd9b1ef74fb3d58c Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 14:28:20 +0000 Subject: [PATCH 07/13] fix: executeRules --- src/model/executeRules.js | 2 +- test/unit/model/quotes.test.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/model/executeRules.js b/src/model/executeRules.js index fe9c9b09..3032e5f1 100644 --- a/src/model/executeRules.js +++ b/src/model/executeRules.js @@ -5,7 +5,7 @@ const RulesEngine = require('./rules.js') module.exports.executeRules = async function executeRules (headers, quoteRequest, originalPayload, payer, payee, operation) { if (rules.length === 0) { - this.handleRuleEvents([], headers, quoteRequest, originalPayload) + return await this.handleRuleEvents([], headers, quoteRequest, originalPayload) } const facts = { diff --git a/test/unit/model/quotes.test.js b/test/unit/model/quotes.test.js index aad75fa5..556e5eb5 100644 --- a/test/unit/model/quotes.test.js +++ b/test/unit/model/quotes.test.js @@ -406,9 +406,10 @@ describe('QuotesModel', () => { it('stops execution', async () => { expect(rules.length).toBe(0) + quotesModel.handleRuleEvents.mockRestore() await expect(quotesModel.executeRules(mockData.headers, mockData.quoteRequest)) .resolves - .toEqual([]) + .toEqual({ terminate: false, headers: mockData.headers, quoteRequest: mockData.quoteRequest }) expect(axios.request.mock.calls.length).toBe(0) }) From c8d0b3336e35ed149064a3c5d8b526cb83bfbd65 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 14:34:49 +0000 Subject: [PATCH 08/13] fix: executeRules --- package-lock.json | 9 +++++---- package.json | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index fab4cb26..b03865c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@mojaloop/event-sdk": "14.1.1", "@mojaloop/inter-scheme-proxy-cache-lib": "2.3.0", "@mojaloop/ml-number": "11.2.4", - "@mojaloop/ml-schema-transformer-lib": "1.1.1", + "@mojaloop/ml-schema-transformer-lib": "1.1.3", "@mojaloop/sdk-standard-components": "18.1.0", "ajv": "8.17.1", "ajv-keywords": "5.1.0", @@ -2042,9 +2042,10 @@ } }, "node_modules/@mojaloop/ml-schema-transformer-lib": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mojaloop/ml-schema-transformer-lib/-/ml-schema-transformer-lib-1.1.1.tgz", - "integrity": "sha512-+zKE2IVwV6sXwwdWnwyXN2qRjLhfztqwHPVciBici3bGx4S7LNSaQ1dfQSueZJA1qwR4TGARZjv2WiKxC4eOxw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@mojaloop/ml-schema-transformer-lib/-/ml-schema-transformer-lib-1.1.3.tgz", + "integrity": "sha512-vAFnooDnGtfzrxAhsBg7ER3ufhzDaFv/Kdi2DF4/UTVb/EKVNb4JnLs2rcRgL3Mhvn439pw19iqOiK8b0rS+lg==", + "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-error-handling": "^13.0.1", "@mojaloop/central-services-logger": "^11.5.1", diff --git a/package.json b/package.json index 31f11656..4e9a28f6 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "test:coverage": "jest --coverage --coverageThreshold='{}' --testMatch '**/test/unit/**/*.test.js'", "test:coverage-check": "jest --runInBand --forceExit --coverage --testMatch '**/test/unit/**/*.test.js'", "test:junit": "jest --runInBand --forceExit --reporters=default --reporters=jest-junit --testMatch '**/test/unit/**/*.test.js'", - "test:int": "jest --runInBand --testMatch '**/test/integration/**/*.test.js'", + "test:int": "jest --runInBand --testMatch '**/test/integration/postRequest.test.js'", "test:integration": "./test/integration/scripts/start.sh && npm run test:int", "test:functional": "true", "regenerate": "yo swaggerize:test --framework hapi --apiPath './src/interface/swagger.json'", @@ -116,7 +116,7 @@ "@mojaloop/event-sdk": "14.1.1", "@mojaloop/inter-scheme-proxy-cache-lib": "2.3.0", "@mojaloop/ml-number": "11.2.4", - "@mojaloop/ml-schema-transformer-lib": "1.1.1", + "@mojaloop/ml-schema-transformer-lib": "1.1.3", "@mojaloop/sdk-standard-components": "18.1.0", "ajv": "8.17.1", "ajv-keywords": "5.1.0", From 2d3bbe6cafe898eb5af5a8cce0aaa0e9ab977beb Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 15:01:27 +0000 Subject: [PATCH 09/13] fix: executeRules --- test/mocks.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/mocks.js b/test/mocks.js index 51396997..43ea3455 100644 --- a/test/mocks.js +++ b/test/mocks.js @@ -140,7 +140,8 @@ const postFxQuotesPayloadDto = ({ amount: 300 }, targetAmount = { - currency: 'ZMW' + currency: 'ZMW', + amount: 0 }, expiration = new Date(Date.now() + 5 * 60 * 1000).toISOString(), extensionList = { From 54a31da239834ff56e0513252bdaed24183c804d Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 15:27:48 +0000 Subject: [PATCH 10/13] fix: executeRules --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e9a28f6..72ddb2be 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "test:coverage": "jest --coverage --coverageThreshold='{}' --testMatch '**/test/unit/**/*.test.js'", "test:coverage-check": "jest --runInBand --forceExit --coverage --testMatch '**/test/unit/**/*.test.js'", "test:junit": "jest --runInBand --forceExit --reporters=default --reporters=jest-junit --testMatch '**/test/unit/**/*.test.js'", - "test:int": "jest --runInBand --testMatch '**/test/integration/postRequest.test.js'", + "test:int": "jest --runInBand --testMatch '**/test/integration/**/*.test.js'", "test:integration": "./test/integration/scripts/start.sh && npm run test:int", "test:functional": "true", "regenerate": "yo swaggerize:test --framework hapi --apiPath './src/interface/swagger.json'", From 77831fdfb8df6ba06535af01e3bd48266958c42e Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 15:29:54 +0000 Subject: [PATCH 11/13] fix: executeRules --- test/integration/postRequest.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/integration/postRequest.test.js b/test/integration/postRequest.test.js index 6baca154..aed22f13 100644 --- a/test/integration/postRequest.test.js +++ b/test/integration/postRequest.test.js @@ -92,7 +92,6 @@ describe('POST request tests --> ', () => { expect(response.data.history.length).toBeGreaterThan(0) const { url } = response.data.history[0] - console.log('95 ===>', response.data.history[0]) expect(url).toBe(`/${message.to}/quotes`) }) From b97575a89369c5cb3784582f1493d96ff1f26d2f Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Mon, 21 Oct 2024 15:49:09 +0000 Subject: [PATCH 12/13] fix: executeRules --- test/integration/fxQuotes.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/fxQuotes.test.js b/test/integration/fxQuotes.test.js index 80b59557..83e4bfd8 100644 --- a/test/integration/fxQuotes.test.js +++ b/test/integration/fxQuotes.test.js @@ -143,7 +143,7 @@ describe('POST /fxQuotes request tests --> ', () => { counterPartyFsp: payload.conversionTerms.counterPartyFsp, sourceAmount: payload.conversionTerms.sourceAmount.amount, sourceCurrency: payload.conversionTerms.sourceAmount.currency, - targetAmount: null, + targetAmount: 0, targetCurrency: payload.conversionTerms.targetAmount.currency, extensions: expect.anything(), expirationDate: expect.anything(), From 3888928d03365e5c2a18025dc97c85ed7e72c24e Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Tue, 22 Oct 2024 06:19:22 +0000 Subject: [PATCH 13/13] test: allow rules.js --- src/model/executeRules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/executeRules.js b/src/model/executeRules.js index 3032e5f1..9fd5e686 100644 --- a/src/model/executeRules.js +++ b/src/model/executeRules.js @@ -1,6 +1,6 @@ const ErrorHandler = require('@mojaloop/central-services-error-handling') -const rules = require('../../config/rules.json') +const rules = require('../../config/rules') const RulesEngine = require('./rules.js') module.exports.executeRules = async function executeRules (headers, quoteRequest, originalPayload, payer, payee, operation) {