From 347f6e524e8493d0573f2fd0e8b6b6a6e644160d Mon Sep 17 00:00:00 2001 From: msk- Date: Thu, 5 Dec 2019 15:04:09 +0000 Subject: [PATCH 1/5] Added skeleton for fx rules unit tests --- test/unit/rules/fx.test.js | 579 +++++++++++++++++++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 test/unit/rules/fx.test.js diff --git a/test/unit/rules/fx.test.js b/test/unit/rules/fx.test.js new file mode 100644 index 00000000..e3d4f10c --- /dev/null +++ b/test/unit/rules/fx.test.js @@ -0,0 +1,579 @@ +/***** + License + -------------- + Copyright © 2017 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + + Initial contribution + -------------------- + The initial functionality and code base was donated by the Mowali project working in conjunction with MTN and Orange as service provides. + * Project: Mowali + + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + + * ModusBox + - Georgi Georgiev + - Vassilis Barzokas + -------------- + ******/ + +const fxRules = { + EURtoXOFSendEUR: { // EUR to XOF, amountType=SEND, amount.currency=EUR + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "EUR" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPEUR", + "sourceCurrency": "EUR", + "rerouteToFspCurrency": "XOF" + } + } + }, + EURtoXOFReceiveXOF: { // EUR to XOF, amountType=RECEIVE, amount.currency=XOF + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "XOF" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPEUR", + "sourceCurrency": "EUR", + "rerouteToFspCurrency": "XOF" + } + } + }, + XOFtoEURSendXOF: { // XOF to EUR, amountType=SEND, amount.currency=XOF + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "XOF" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPXOF", + "sourceCurrency": "XOF", + "rerouteToFspCurrency": "EUR" + } + } + }, + XOFtoEURReceiveEUR: { // XOF to EUR, amountType=RECEIVE, amount.currency=EUR + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + } + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "equal", + "value": "EUR" + } + ] + }, + "event": { + "type": "INTERCEPT_QUOTE", + "params": { + "rerouteToFsp": "DFSPXOF", + "sourceCurrency": "XOF", + "rerouteToFspCurrency": "EUR" + } + } + }, + payerUnsupportedCurrency: { // PAYER_UNSUPPORTED_CURRENCY + "conditions": { + "all": [ + { + "fact": "payload", + "path": "$.amountType", + "operator": "equal", + "value": "SEND" + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payer", + "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + } + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYER_UNSUPPORTED_CURRENCY", + "message": "Requested currency not available for payer. Transfer not allowed." + } + } + }, + payeeUnsupportedCurrency: { // PAYEE_UNSUPPORTED_CURRENCY + "conditions": { + "all": [ + { + "fact": "payload", + "path": "$.amountType", + "operator": "equal", + "value": "RECEIVE" + }, + { + "fact": "payload", + "path": "$.amount.currency", + "operator": "notIn", + "value": { + "fact": "payee", + "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + } + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYEE_UNSUPPORTED_CURRENCY", + "message": "Requested currency not available for payee. Transfer not allowed." + } + } + }, + FSPIOPSourceDoesNotMatchPayer: { // FSPIOP-Source not matching Payer + "conditions": { + "all": [ + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notIn", + "value": [ + "DFSPXOF", + "DFSPEUR", + "DFSPMAD" + ] + }, + { + "fact": "headers", + "path": "$.fspiop-source", + "operator": "notEqual", + "value": { + "fact": "payload", + "path": "$.partyIdInfo.fspId" + } + } + ] + }, + "event": { + "type": "INVALID_QUOTE_REQUEST", + "params": { + "FSPIOPError": "PAYER_FSPIO", + "message": "The payer FSP does not match the fspiop-source header" + } + } + } +}; + +const RulesEngine = require('../../../src/model/rules') + +describe('Forex rules', () => { + describe('EURtoXOFSendEUR', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + }, + amount: { + currency: 'EUR' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payee: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'XYZ' } + ] + } + }; + const { events } = await RulesEngine.run([ fxRules.EURtoXOFSendEUR ], testFacts); + expect(events).toEqual([fxRules.EURtoXOFSendEUR.event]); + }); + }); + describe('EURtoXOFReceiveXOF', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + }, + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payee: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'XYZ' } + ] + } + }; + const { events } = await RulesEngine.run([ fxRules.EURtoXOFSendEUR ], testFacts); + expect(events).toEqual([fxRules.EURtoXOFSendEUR.event]); + }); + }); + // describe('XOFtoEURSendXOF', () => {}); + // describe('XOFtoEURReceiveEUR', () => {}); + // describe('payerUnsupportedCurrency', () => {}); + // describe('payeeUnsupportedCurrency', () => {}); + // describe('FSPIOPSourceDoesNotMatchPayer', () => {}); +}); + +// describe('RulesEngine', () => { +// describe('run', () => { +// it('returns the expected events when using jsonpath and notDeepEqual operator', async () => { +// const conditions = { +// any: [{ +// fact: 'json-path', +// params: { +// fact: 'payload', +// path: '$.payload.payer.partyIdInfo.fspId' +// }, +// operator: 'notDeepEqual', +// value: ['payerfsp'] +// }] +// } +// const event = { +// type: RulesEngine.events.INVALID_QUOTE_REQUEST +// } +// const testFacts = { +// payload: { +// payer: { +// partyIdInfo: { +// fspId: 'payeefsp' +// } +// } +// } +// } +// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) +// expect(events).toEqual([event]) +// }) +// +// it('returns the expected events when using jsonpath fact-fact comparison', async () => { +// const conditions = { +// any: [{ +// fact: 'json-path', +// params: { +// fact: 'payload', +// path: '$.payload.payer.partyIdInfo.fspId' +// }, +// operator: 'notDeepEqual', +// value: { +// fact: 'json-path', +// params: { +// path: '$.headers[\'fspiop-source\']', +// fact: 'headers' +// } +// } +// }] +// } +// const event = { +// type: RulesEngine.events.INVALID_QUOTE_REQUEST +// } +// const testFacts = { +// payload: { +// payer: { +// partyIdInfo: { +// fspId: 'payeefsp' +// } +// } +// }, +// headers: { +// 'fspiop-source': 'payerfsp' +// } +// } +// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) +// expect(events).toEqual([event]) +// }) +// +// it('returns the expected events when using jsonpath array filter', async () => { +// const conditions = { +// any: [{ +// fact: 'json-path', +// params: { +// fact: 'payload', +// path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' +// }, +// operator: 'notDeepEqual', +// value: ['1'] +// }] +// } +// const event = { +// type: RulesEngine.events.INVALID_QUOTE_REQUEST +// } +// const testFacts = { +// payload: { +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'KYCPayerTier', value: '2' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) +// expect(events).toEqual([event]) +// }) +// +// it('returns the expected events when using deepEqual operator', async () => { +// const conditions = { +// any: [{ +// fact: 'json-path', +// params: { +// fact: 'payload', +// path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' +// }, +// operator: 'deepEqual', +// value: ['1'] +// }] +// } +// const event = { +// type: RulesEngine.events.INVALID_QUOTE_REQUEST +// } +// const testFacts = { +// payload: { +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'KYCPayerTier', value: '1' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) +// expect(events).toEqual([event]) +// }) +// +// it('returns the expected events when using example config for event INTERCEPT_QUOTE', async () => { +// const testFacts = { +// payee: { +// accounts: [{ +// ledgerAccountType: 'SETTLEMENT', +// currency: 'ZAR' +// }] +// }, +// payload: { +// amount: { +// currency: 'XOF' +// }, +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'KYCPayerTier', value: '1' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run(fxRules, testFacts) +// expect(events).toEqual([fxRules[0].event]) +// }) +// +// it('returns an empty array of events when using example config for INTERCEPT_QUOTE negative case', async () => { +// const testFacts = { +// payee: { +// accounts: [{ +// ledgerAccountType: 'SETTLEMENT', +// currency: 'XOF' +// }] +// }, +// payload: { +// amount: { +// currency: 'XOF' +// }, +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'KYCPayerTier', value: '1' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run(fxRules, testFacts) +// expect(events).toEqual([]) +// }) +// +// it('returns the expected events when using example config for INVALID_QUOTE_REQUEST triggered by missing extension value', async () => { +// const testFacts = { +// payee: { +// accounts: [{ +// ledgerAccountType: 'SETTLEMENT', +// currency: 'ZAR' +// }] +// }, +// payload: { +// amount: { +// currency: 'XOF' +// }, +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run(fxRules, testFacts) +// expect(events).toEqual([fxRules[1].event]) +// }) +// +// it('returns the expected events when using example config INVALID_QUOTE_REQUEST triggered by incorrect extension value', async () => { +// const testFacts = { +// payee: { +// accounts: [{ +// ledgerAccountType: 'SETTLEMENT', +// currency: 'ZAR' +// }] +// }, +// payload: { +// amount: { +// currency: 'XOF' +// }, +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'KYCPayerTier', value: '2' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run(fxRules, testFacts) +// expect(events).toEqual([fxRules[1].event]) +// }) +// +// it('returns the expected events when using example config INVALID_QUOTE_REQUEST event negative case', async () => { +// const testFacts = { +// payee: { +// accounts: [{ +// ledgerAccountType: 'SETTLEMENT', +// currency: 'XOF' +// }] +// }, +// payload: { +// amount: { +// currency: 'XOF' +// }, +// extensionList: [ +// { key: 'blah', value: 'whatever' }, +// { key: 'KYCPayerTier', value: '2' }, +// { key: 'noise', value: 'blah' } +// ] +// } +// } +// const { events } = await RulesEngine.run(fxRules, testFacts) +// expect(events).toEqual([]) +// }) +// }) +// }); From 5d9108535993013f5ec9c70cf4038fc2ffaea171 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 5 Dec 2019 09:57:44 -0600 Subject: [PATCH 2/5] added more tests --- test/unit/rules/fx.test.js | 472 +++++++++++++++++++++++-------------- 1 file changed, 300 insertions(+), 172 deletions(-) diff --git a/test/unit/rules/fx.test.js b/test/unit/rules/fx.test.js index e3d4f10c..935c997d 100644 --- a/test/unit/rules/fx.test.js +++ b/test/unit/rules/fx.test.js @@ -32,250 +32,250 @@ const fxRules = { EURtoXOFSendEUR: { // EUR to XOF, amountType=SEND, amount.currency=EUR - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "headers", - "path": "$.fspiop-source", - "operator": "notIn", - "value": [ - "DFSPXOF", - "DFSPEUR", - "DFSPMAD" + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' ] }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "notIn", - "value": { - "fact": "payee", - "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'SETTLEMENT\')].currency' } }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "equal", - "value": "EUR" + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'EUR' } ] }, - "event": { - "type": "INTERCEPT_QUOTE", - "params": { - "rerouteToFsp": "DFSPEUR", - "sourceCurrency": "EUR", - "rerouteToFspCurrency": "XOF" + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPEUR', + sourceCurrency: 'EUR', + rerouteToFspCurrency: 'XOF' } } }, EURtoXOFReceiveXOF: { // EUR to XOF, amountType=RECEIVE, amount.currency=XOF - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "headers", - "path": "$.fspiop-source", - "operator": "notIn", - "value": [ - "DFSPXOF", - "DFSPEUR", - "DFSPMAD" + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' ] }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "notIn", - "value": { - "fact": "payer", - "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'SETTLEMENT\')].currency' } }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "equal", - "value": "XOF" + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'XOF' } ] }, - "event": { - "type": "INTERCEPT_QUOTE", - "params": { - "rerouteToFsp": "DFSPEUR", - "sourceCurrency": "EUR", - "rerouteToFspCurrency": "XOF" + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPEUR', + sourceCurrency: 'EUR', + rerouteToFspCurrency: 'XOF' } } }, XOFtoEURSendXOF: { // XOF to EUR, amountType=SEND, amount.currency=XOF - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "headers", - "path": "$.fspiop-source", - "operator": "notIn", - "value": [ - "DFSPXOF", - "DFSPEUR", - "DFSPMAD" + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' ] }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "notIn", - "value": { - "fact": "payee", - "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'SETTLEMENT\')].currency' } }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "equal", - "value": "XOF" + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'XOF' } ] }, - "event": { - "type": "INTERCEPT_QUOTE", - "params": { - "rerouteToFsp": "DFSPXOF", - "sourceCurrency": "XOF", - "rerouteToFspCurrency": "EUR" + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPXOF', + sourceCurrency: 'XOF', + rerouteToFspCurrency: 'EUR' } } }, XOFtoEURReceiveEUR: { // XOF to EUR, amountType=RECEIVE, amount.currency=EUR - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "headers", - "path": "$.fspiop-source", - "operator": "notIn", - "value": [ - "DFSPXOF", - "DFSPEUR", - "DFSPMAD" + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' ] }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "notIn", - "value": { - "fact": "payer", - "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'SETTLEMENT\')].currency' } }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "equal", - "value": "EUR" + fact: 'payload', + path: '$.amount.currency', + operator: 'equal', + value: 'EUR' } ] }, - "event": { - "type": "INTERCEPT_QUOTE", - "params": { - "rerouteToFsp": "DFSPXOF", - "sourceCurrency": "XOF", - "rerouteToFspCurrency": "EUR" + event: { + type: 'INTERCEPT_QUOTE', + params: { + rerouteToFsp: 'DFSPXOF', + sourceCurrency: 'XOF', + rerouteToFspCurrency: 'EUR' } } }, payerUnsupportedCurrency: { // PAYER_UNSUPPORTED_CURRENCY - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "payload", - "path": "$.amountType", - "operator": "equal", - "value": "SEND" + fact: 'payload', + path: '$.amountType', + operator: 'equal', + value: 'SEND' }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "notIn", - "value": { - "fact": "payer", - "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payer', + path: '$.accounts[?(@.ledgerAccountType == \'SETTLEMENT\')].currency' } } ] }, - "event": { - "type": "INVALID_QUOTE_REQUEST", - "params": { - "FSPIOPError": "PAYER_UNSUPPORTED_CURRENCY", - "message": "Requested currency not available for payer. Transfer not allowed." + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYER_UNSUPPORTED_CURRENCY', + message: 'Requested currency not available for payer. Transfer not allowed.' } } }, payeeUnsupportedCurrency: { // PAYEE_UNSUPPORTED_CURRENCY - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "payload", - "path": "$.amountType", - "operator": "equal", - "value": "RECEIVE" + fact: 'payload', + path: '$.amountType', + operator: 'equal', + value: 'RECEIVE' }, { - "fact": "payload", - "path": "$.amount.currency", - "operator": "notIn", - "value": { - "fact": "payee", - "path": "$.accounts[?(@.ledgerAccountType == 'SETTLEMENT')].currency" + fact: 'payload', + path: '$.amount.currency', + operator: 'notIn', + value: { + fact: 'payee', + path: '$.accounts[?(@.ledgerAccountType == \'SETTLEMENT\')].currency' } } ] }, - "event": { - "type": "INVALID_QUOTE_REQUEST", - "params": { - "FSPIOPError": "PAYEE_UNSUPPORTED_CURRENCY", - "message": "Requested currency not available for payee. Transfer not allowed." + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYEE_UNSUPPORTED_CURRENCY', + message: 'Requested currency not available for payee. Transfer not allowed.' } } }, FSPIOPSourceDoesNotMatchPayer: { // FSPIOP-Source not matching Payer - "conditions": { - "all": [ + conditions: { + all: [ { - "fact": "headers", - "path": "$.fspiop-source", - "operator": "notIn", - "value": [ - "DFSPXOF", - "DFSPEUR", - "DFSPMAD" + fact: 'headers', + path: '$.fspiop-source', + operator: 'notIn', + value: [ + 'DFSPXOF', + 'DFSPEUR', + 'DFSPMAD' ] }, { - "fact": "headers", - "path": "$.fspiop-source", - "operator": "notEqual", - "value": { - "fact": "payload", - "path": "$.partyIdInfo.fspId" + fact: 'headers', + path: '$.fspiop-source', + operator: 'notEqual', + value: { + fact: 'payload', + path: '$.payer.partyIdInfo.fspId' } } ] }, - "event": { - "type": "INVALID_QUOTE_REQUEST", - "params": { - "FSPIOPError": "PAYER_FSPIO", - "message": "The payer FSP does not match the fspiop-source header" + event: { + type: 'INVALID_QUOTE_REQUEST', + params: { + FSPIOPError: 'PAYER_FSPIO', + message: 'The payer FSP does not match the fspiop-source header' } } } -}; +} const RulesEngine = require('../../../src/model/rules') @@ -301,12 +301,38 @@ describe('Forex rules', () => { { ledgerAccountType: 'SETTLEMENT', currency: 'XYZ' } ] } - }; - const { events } = await RulesEngine.run([ fxRules.EURtoXOFSendEUR ], testFacts); - expect(events).toEqual([fxRules.EURtoXOFSendEUR.event]); - }); - }); + } + const { events } = await RulesEngine.run([fxRules.EURtoXOFSendEUR], testFacts) + expect(events).toEqual([fxRules.EURtoXOFSendEUR.event]) + }) + }) describe('EURtoXOFReceiveXOF', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payer: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.EURtoXOFReceiveXOF], testFacts) + expect(events).toEqual([fxRules.EURtoXOFReceiveXOF.event]) + }) + }) + describe('XOFtoEURSendXOF', () => { it('raises INTERCEPT_QUOTE', async () => { const testFacts = { payload: { @@ -324,20 +350,122 @@ describe('Forex rules', () => { }, payee: { accounts: [ - { ledgerAccountType: 'SETTLEMENT', currency: 'XYZ' } + { ledgerAccountType: 'SETTLEMENT', currency: 'EUR' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.XOFtoEURSendXOF], testFacts) + expect(events).toEqual([fxRules.XOFtoEURSendXOF.event]) + }) + }) + describe('XOFtoEURReceiveEUR', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payeefsp' + } + }, + amount: { + currency: 'EUR' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payer: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.XOFtoEURReceiveEUR], testFacts) + expect(events).toEqual([fxRules.XOFtoEURReceiveEUR.event]) + }) + }) + describe('payerUnsupportedCurrency', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'SEND', + amount: { + currency: 'EUR' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payer: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'xyz' } ] } - }; - const { events } = await RulesEngine.run([ fxRules.EURtoXOFSendEUR ], testFacts); - expect(events).toEqual([fxRules.EURtoXOFSendEUR.event]); - }); - }); - // describe('XOFtoEURSendXOF', () => {}); - // describe('XOFtoEURReceiveEUR', () => {}); - // describe('payerUnsupportedCurrency', () => {}); - // describe('payeeUnsupportedCurrency', () => {}); - // describe('FSPIOPSourceDoesNotMatchPayer', () => {}); -}); + } + const { events } = await RulesEngine.run([fxRules.payerUnsupportedCurrency], testFacts) + expect(events).toEqual([fxRules.payerUnsupportedCurrency.event]) + }) + }) + describe('payeeUnsupportedCurrency', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'payerfsp' + }, + payee: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.payeeUnsupportedCurrency], testFacts) + expect(events).toEqual([fxRules.payeeUnsupportedCurrency.event]) + }) + }) + describe('FSPIOPSourceDoesNotMatchPayer', () => { + it('raises INTERCEPT_QUOTE', async () => { + const testFacts = { + payload: { + payer: { + partyIdInfo: { + fspId: 'payerfsp' + } + }, + amountType: 'RECEIVE', + amount: { + currency: 'XOF' + } + }, + headers: { + 'fspiop-source': 'blah' + }, + payee: { + accounts: [ + { ledgerAccountType: 'SETTLEMENT', currency: 'xyz' } + ] + } + } + const { events } = await RulesEngine.run([fxRules.FSPIOPSourceDoesNotMatchPayer], testFacts) + expect(events).toEqual([fxRules.FSPIOPSourceDoesNotMatchPayer.event]) + }) + }) +}) // describe('RulesEngine', () => { // describe('run', () => { From 3b63c5852883f8f0cc56c5fa5aa4b6c340cfa111 Mon Sep 17 00:00:00 2001 From: shashi165 Date: Thu, 5 Dec 2019 09:59:42 -0600 Subject: [PATCH 3/5] added more tests --- package-lock.json | 41 ++++++++++++++++++++++++----------------- package.json | 4 ++-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 032c73fd..19e798e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -732,17 +732,24 @@ "parse-strings-in-object": "1.2.0", "rc": "1.2.8", "winston": "3.2.1" + }, + "dependencies": { + "parse-strings-in-object": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-1.2.0.tgz", + "integrity": "sha512-lI8XgBWZ5COL0G2G6MsLqPSc4X/SnYPw5jGDiins/qzdOdlY493j/niCY9UiJqWjDoeY20k7vhEXvKRHTy6Dfw==" + } } }, "@mojaloop/central-services-shared": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-8.6.2.tgz", - "integrity": "sha512-zgzqUMHHU/CwB3dIqAvb1rHuVz7auzQdPCq+8/JOj3wqzzoQ4CH0Om4oxkRQiYt5yP1eh9TdEwKBp7dSustGsw==", + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-8.6.3.tgz", + "integrity": "sha512-qBRmtJN1FNBYEM8ORd49wr5999s39+U8ahbFMsVmGE7MJVF3HzvoYMndw2hF4rNXaSGmMGfUOikTht0D6TW/tQ==", "requires": { "@hapi/catbox": "10.2.3", "@hapi/catbox-memory": "4.1.1", "@mojaloop/central-services-error-handling": "8.6.2", - "@mojaloop/central-services-logger": "8.5.2", + "@mojaloop/central-services-logger": "8.6.0", "@mojaloop/central-services-stream": "8.4.0", "@mojaloop/event-sdk": "8.3.0", "axios": "0.19.0", @@ -756,16 +763,6 @@ "raw-body": "2.4.1" }, "dependencies": { - "@mojaloop/central-services-logger": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-8.5.2.tgz", - "integrity": "sha512-9nnpk82Q3UKeY5Tq4xuTuZAwGNNf6PR5NArJiSwx2LA4Kp43Det+6/E01nhqEcA4e5GkdAnraxwk8jOFBQoTkQ==", - "requires": { - "parse-strings-in-object": "1.2.0", - "rc": "1.2.8", - "winston": "3.2.1" - } - }, "@mojaloop/event-sdk": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/@mojaloop/event-sdk/-/event-sdk-8.3.0.tgz", @@ -797,6 +794,11 @@ } } } + }, + "parse-strings-in-object": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-1.2.0.tgz", + "integrity": "sha512-lI8XgBWZ5COL0G2G6MsLqPSc4X/SnYPw5jGDiins/qzdOdlY493j/niCY9UiJqWjDoeY20k7vhEXvKRHTy6Dfw==" } } }, @@ -1311,6 +1313,11 @@ "bundled": true } } + }, + "parse-strings-in-object": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-1.2.0.tgz", + "integrity": "sha512-lI8XgBWZ5COL0G2G6MsLqPSc4X/SnYPw5jGDiins/qzdOdlY493j/niCY9UiJqWjDoeY20k7vhEXvKRHTy6Dfw==" } } }, @@ -8358,9 +8365,9 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" }, "parse-strings-in-object": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-1.2.0.tgz", - "integrity": "sha512-lI8XgBWZ5COL0G2G6MsLqPSc4X/SnYPw5jGDiins/qzdOdlY493j/niCY9UiJqWjDoeY20k7vhEXvKRHTy6Dfw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-strings-in-object/-/parse-strings-in-object-2.0.0.tgz", + "integrity": "sha512-hb50xDyEo8boMtyzB1IdVE4KcTNVbIirk/ZqC8na1irOf/70DyZS30y1FIIAUe9jyHJk9s2QoZ4aBNHR9NXHsg==" }, "parse5": { "version": "4.0.0", diff --git a/package.json b/package.json index 60c5cfa7..50b797c6 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@hapi/hapi": "18.4.0", "@mojaloop/central-services-error-handling": "8.6.2", "@mojaloop/central-services-logger": "8.6.0", - "@mojaloop/central-services-shared": "8.6.2", + "@mojaloop/central-services-shared": "8.6.3", "@mojaloop/event-sdk": "8.6.1", "@mojaloop/ml-number": "8.2.0", "axios": "0.19.0", @@ -64,7 +64,7 @@ "memory-cache": "0.2.0", "mysql": "2.17.1", "node-fetch": "2.6.0", - "parse-strings-in-object": "1.2.0", + "parse-strings-in-object": "2.0.0", "rc": "1.2.8" }, "devDependencies": { From 7adf22248bd5cfd71378772c4be2a9016649967e Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Thu, 5 Dec 2019 16:03:30 +0000 Subject: [PATCH 4/5] Removed commented tests from original file --- test/unit/rules/fx.test.js | 239 ------------------------------------- 1 file changed, 239 deletions(-) diff --git a/test/unit/rules/fx.test.js b/test/unit/rules/fx.test.js index 935c997d..ecfd5bac 100644 --- a/test/unit/rules/fx.test.js +++ b/test/unit/rules/fx.test.js @@ -466,242 +466,3 @@ describe('Forex rules', () => { }) }) }) - -// describe('RulesEngine', () => { -// describe('run', () => { -// it('returns the expected events when using jsonpath and notDeepEqual operator', async () => { -// const conditions = { -// any: [{ -// fact: 'json-path', -// params: { -// fact: 'payload', -// path: '$.payload.payer.partyIdInfo.fspId' -// }, -// operator: 'notDeepEqual', -// value: ['payerfsp'] -// }] -// } -// const event = { -// type: RulesEngine.events.INVALID_QUOTE_REQUEST -// } -// const testFacts = { -// payload: { -// payer: { -// partyIdInfo: { -// fspId: 'payeefsp' -// } -// } -// } -// } -// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) -// expect(events).toEqual([event]) -// }) -// -// it('returns the expected events when using jsonpath fact-fact comparison', async () => { -// const conditions = { -// any: [{ -// fact: 'json-path', -// params: { -// fact: 'payload', -// path: '$.payload.payer.partyIdInfo.fspId' -// }, -// operator: 'notDeepEqual', -// value: { -// fact: 'json-path', -// params: { -// path: '$.headers[\'fspiop-source\']', -// fact: 'headers' -// } -// } -// }] -// } -// const event = { -// type: RulesEngine.events.INVALID_QUOTE_REQUEST -// } -// const testFacts = { -// payload: { -// payer: { -// partyIdInfo: { -// fspId: 'payeefsp' -// } -// } -// }, -// headers: { -// 'fspiop-source': 'payerfsp' -// } -// } -// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) -// expect(events).toEqual([event]) -// }) -// -// it('returns the expected events when using jsonpath array filter', async () => { -// const conditions = { -// any: [{ -// fact: 'json-path', -// params: { -// fact: 'payload', -// path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' -// }, -// operator: 'notDeepEqual', -// value: ['1'] -// }] -// } -// const event = { -// type: RulesEngine.events.INVALID_QUOTE_REQUEST -// } -// const testFacts = { -// payload: { -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'KYCPayerTier', value: '2' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) -// expect(events).toEqual([event]) -// }) -// -// it('returns the expected events when using deepEqual operator', async () => { -// const conditions = { -// any: [{ -// fact: 'json-path', -// params: { -// fact: 'payload', -// path: '$.payload.extensionList[?(@.key === \'KYCPayerTier\')].value' -// }, -// operator: 'deepEqual', -// value: ['1'] -// }] -// } -// const event = { -// type: RulesEngine.events.INVALID_QUOTE_REQUEST -// } -// const testFacts = { -// payload: { -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'KYCPayerTier', value: '1' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run([{ conditions, event }], testFacts) -// expect(events).toEqual([event]) -// }) -// -// it('returns the expected events when using example config for event INTERCEPT_QUOTE', async () => { -// const testFacts = { -// payee: { -// accounts: [{ -// ledgerAccountType: 'SETTLEMENT', -// currency: 'ZAR' -// }] -// }, -// payload: { -// amount: { -// currency: 'XOF' -// }, -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'KYCPayerTier', value: '1' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run(fxRules, testFacts) -// expect(events).toEqual([fxRules[0].event]) -// }) -// -// it('returns an empty array of events when using example config for INTERCEPT_QUOTE negative case', async () => { -// const testFacts = { -// payee: { -// accounts: [{ -// ledgerAccountType: 'SETTLEMENT', -// currency: 'XOF' -// }] -// }, -// payload: { -// amount: { -// currency: 'XOF' -// }, -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'KYCPayerTier', value: '1' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run(fxRules, testFacts) -// expect(events).toEqual([]) -// }) -// -// it('returns the expected events when using example config for INVALID_QUOTE_REQUEST triggered by missing extension value', async () => { -// const testFacts = { -// payee: { -// accounts: [{ -// ledgerAccountType: 'SETTLEMENT', -// currency: 'ZAR' -// }] -// }, -// payload: { -// amount: { -// currency: 'XOF' -// }, -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run(fxRules, testFacts) -// expect(events).toEqual([fxRules[1].event]) -// }) -// -// it('returns the expected events when using example config INVALID_QUOTE_REQUEST triggered by incorrect extension value', async () => { -// const testFacts = { -// payee: { -// accounts: [{ -// ledgerAccountType: 'SETTLEMENT', -// currency: 'ZAR' -// }] -// }, -// payload: { -// amount: { -// currency: 'XOF' -// }, -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'KYCPayerTier', value: '2' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run(fxRules, testFacts) -// expect(events).toEqual([fxRules[1].event]) -// }) -// -// it('returns the expected events when using example config INVALID_QUOTE_REQUEST event negative case', async () => { -// const testFacts = { -// payee: { -// accounts: [{ -// ledgerAccountType: 'SETTLEMENT', -// currency: 'XOF' -// }] -// }, -// payload: { -// amount: { -// currency: 'XOF' -// }, -// extensionList: [ -// { key: 'blah', value: 'whatever' }, -// { key: 'KYCPayerTier', value: '2' }, -// { key: 'noise', value: 'blah' } -// ] -// } -// } -// const { events } = await RulesEngine.run(fxRules, testFacts) -// expect(events).toEqual([]) -// }) -// }) -// }); From 5de0935ab43607f24332545fee11510cb52c559c Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Thu, 5 Dec 2019 16:13:43 +0000 Subject: [PATCH 5/5] Update fx.test.js --- test/unit/rules/fx.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/rules/fx.test.js b/test/unit/rules/fx.test.js index ecfd5bac..8651d3dc 100644 --- a/test/unit/rules/fx.test.js +++ b/test/unit/rules/fx.test.js @@ -30,6 +30,8 @@ -------------- ******/ +const RulesEngine = require('../../../src/model/rules') + const fxRules = { EURtoXOFSendEUR: { // EUR to XOF, amountType=SEND, amount.currency=EUR conditions: { @@ -277,8 +279,6 @@ const fxRules = { } } -const RulesEngine = require('../../../src/model/rules') - describe('Forex rules', () => { describe('EURtoXOFSendEUR', () => { it('raises INTERCEPT_QUOTE', async () => {