Skip to content

Commit

Permalink
chore: add scenario for complex quote testing (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
kleyow authored Oct 23, 2023
1 parent 251cdc3 commit 4c649b2
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ACCOUNT_LOOKUP_SERVICE_VERSION=v14.2.3
## ALS snapshot release with fix: v14.2.3 + caching for validateParticipant and resolve Participants via Oracles
# ACCOUNT_LOOKUP_SERVICE_VERSION=v14.2.4-snapshot.3
# QUOTING_SERVICE_VERSION=v15.2.1
QUOTING_SERVICE_VERSION=v15.2.3-snapshot.2
QUOTING_SERVICE_VERSION=v15.4.0
## CL initial baseline with version included in Mojaloop v15.1.0 Helm Release
# CENTRAL_LEDGER_VERSION=v17.0.3
## Cl latest version
Expand Down
5 changes: 1 addition & 4 deletions docker/config-modifier/configs/quoting-service-perf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@ module.exports = {
"HOST": "mysql-cl"
},
"SIMPLE_ROUTING_MODE": false,
"SWITCH_ENDPOINT": "http://callback-handler-svc-cl-sim:3001/admin",
"CACHE": {
"EXPIRES_IN_MS": 60000
}
"SWITCH_ENDPOINT": "http://callback-handler-svc-cl-sim:3001/admin"
}
21 changes: 21 additions & 0 deletions packages/k6-tests/config/fspiopQuotesPersonalInfoExtensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"scenarios": {
"fspiopQuotes": {
"executor": "ramping-vus",
"exec": "fspiopQuotesScenarios",
"env": {
"UNIDIRECTIONAL": "false"
},
"startVUs": 1,
"stages": [
{ "duration": "30s", "target": 50 },
{ "duration": "5m", "target": 50 }
]
}
},
"thresholds": {
"iteration_duration": [ "p(95)<1000" ],
"http_req_failed": [ "rate<0.01" ],
"http_req_duration": [ "p(95)<1000" ]
}
}
1 change: 1 addition & 0 deletions packages/k6-tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { fspiopDiscoveryScenarios } from './scenarios/fspiopDiscovery.js';
export { fspiopTransfersScenarios } from './scenarios/fspiopTransfers.js';
export { fspiopTransfersNoCallbackScenarios } from './scenarios/fspiopTransfersNoCallback.js';
export { fspiopQuotesScenarios } from './scenarios/fspiopQuotes.js';
export { fspiopQuotesPersonalInfoExtensionsScenarios } from './scenarios/fspiopQuotesPersonalInfoExtensions.js';

const configFile = __ENV.K6_SCRIPT_CONFIG_FILE_NAME ? './config/' + __ENV.K6_SCRIPT_CONFIG_FILE_NAME : './config/test.json';
const testConfig = JSON.parse(open(configFile));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { postQuotesPersonalInfoExtensions } from "../scripts/postQuotesPersonalInfoExtensions.js";


export function fspiopQuotesPersonalInfoExtensionsScenarios() {
postQuotesPersonalInfoExtensions();
}
182 changes: 182 additions & 0 deletions packages/k6-tests/scripts/postQuotesPersonalInfoExtensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import http from 'k6/http';
import { crypto } from "k6/experimental/webcrypto";
import { check, fail, sleep, group } from 'k6';
import { WebSocket } from 'k6/experimental/websockets';
import { setTimeout, clearTimeout, setInterval, clearInterval } from 'k6/experimental/timers';
import { Trace } from "../common/trace.js";
import { getTwoItemsFromArray } from "../common/utils.js";

console.log(`Env Vars -->
K6_SCRIPT_WS_TIMEOUT_MS=${__ENV.K6_SCRIPT_WS_TIMEOUT_MS},
K6_SCRIPT_FSPIOP_QUOTES_ENDPOINT_URL=${__ENV.K6_SCRIPT_FSPIOP_QUOTES_ENDPOINT_URL},
K6_SCRIPT_FSPIOP_FSP_POOL=${__ENV.K6_SCRIPT_FSPIOP_FSP_POOL}
`);

const fspList = JSON.parse(__ENV.K6_SCRIPT_FSPIOP_FSP_POOL)
const amount = __ENV.K6_SCRIPT_FSPIOP_QUOTES_AMOUNT.toString()
const currency = __ENV.K6_SCRIPT_FSPIOP_QUOTES_CURRENCY

export function postQuotes() {
group("Post Quotes", function () {
let payerFsp
let payeeFsp

if (__ENV.UNIDIRECTIONAL === "true" || __ENV.UNIDIRECTIONAL === "TRUE") {
payerFsp = fspList[0]
payeeFsp = fspList[1]
} else {
const selectedFsps = getTwoItemsFromArray(fspList)
payerFsp = selectedFsps[0]
payeeFsp = selectedFsps[1]
}

const startTs = Date.now();
const quoteId = crypto.randomUUID();
const transactionId = crypto.randomUUID();
const payerFspId = payerFsp['fspId'];
const payeeFspId = payeeFsp['fspId'];
const wsUrl = payerFsp['wsUrl'];
const traceParent = Trace();
const traceId = traceParent.traceId;
const wsChannel = `${traceParent.traceId}/PUT/quotes/${quoteId}`;
const wsURL = `${wsUrl}/${wsChannel}`
const ws = new WebSocket(wsURL);
const wsTimeoutMs = Number(__ENV.K6_SCRIPT_WS_TIMEOUT_MS) || 2000; // user session between 5s and 1m

var wsTimeoutId = null;

const clearTimers = () => {
if (wsTimeoutId) { clearTimeout(wsTimeoutId); wsTimeoutId=null }
}

ws.onclose(() => {
clearTimers();
});

ws.onerror((err) => {
console.error(traceId, err);
check(err, { 'QUOTES_E2E_FSPIOP_POST_QUOTES_SUCCESS': (cbMessage) => false });
clearTimers();
ws.close();
});

ws.onmessage = (event) => {
console.info(traceId, `WS message received [${wsChannel}]: ${event.data}`);
check(event.data, { 'QUOTES_E2E_FSPIOP_POST_QUOTES_SUCCESS': (cbMessage) => cbMessage == 'SUCCESS_CALLBACK_RECEIVED' });
clearTimers();
ws.close();
// sleep(1);
};

ws.onopen = () => {
console.info(traceId, `WS open on URL: ${wsURL}`);
const params = {
tags: {
payerFspId,
payeeFspId
},
headers: {
'accept': 'application/vnd.interoperability.quotes+json;version=1.0',
'Content-Type': 'application/vnd.interoperability.quotes+json;version=1.0',
'FSPIOP-Source': payerFspId,
'FSPIOP-Destination': payeeFspId,
'Date': (new Date()).toUTCString(),
'traceparent': traceParent.toString(),
'tracestate': `tx_end2end_start_ts=${startTs}`
},
};

const body = {
"quoteId": quoteId,
"transactionId": transactionId,
"payer": {
"partyIdInfo": {
"partyIdType": "MSISDN",
"partyIdentifier": `${payerFsp['partyId']}`,
"fspId": payerFspId,
"extensionList": {
"extension": [
{
"key": "test1",
"value": "test1"
},
{
"key": "test2",
"value": "test2"
}
]
}
},
"personalInfo": {
"complexName": {
"firstName": "Alice",
"middleName": "A",
"lastName": "Alison"
},
"dateOfBirth": "1970-01-01"
}
},
"payee": {
"partyIdInfo": {
"partyIdType": "MSISDN",
"partyIdentifier": `${payeeFsp['partyId']}`,
"fspId": payeeFspId,
"extensionList": {
"extension": [
{
"key": "test3",
"value": "test3"
},
{
"key": "test4",
"value": "test4"
}
]
}
},
"personalInfo": {
"complexName": {
"firstName": "Bob",
"middleName": "B",
"lastName": "Bloggs"
},
"dateOfBirth": "1970-01-01"
}
},
"amountType": "SEND",
"amount": {
"amount": `${amount}`,
"currency": `${currency}`
},
"transactionType": {
"scenario": "TRANSFER",
"initiator": "PAYER",
"initiatorType": "CONSUMER"
},
"extensionList": {
"extension": [
{
"key": "quoteExtension1",
"value": "quoteExtension1"
},
{
"key": "quoteExtension2",
"value": "quoteExtension2"
}
]
}
}

// Lets send the FSPIOP POST /quotes request
const res = http.post(`${__ENV.K6_SCRIPT_FSPIOP_QUOTES_ENDPOINT_URL}/quotes`, JSON.stringify(body), params);
check(res, { 'QUOTES_FSPIOP_POST_QUOTES_RESPONSE_IS_202' : (r) => r.status == 202 });

wsTimeoutId = setTimeout(() => {
const errorMsg = `WS timed-out on URL: ${wsURL}`
console.error(traceId, errorMsg);
check(res, { 'QUOTES_E2E_FSPIOP_POST_QUOTES_SUCCESS': (cbMessage) => false });
ws.close();
}, wsTimeoutMs);
};
});
}
6 changes: 6 additions & 0 deletions perf.env
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,9 @@ CONF_CL_HANDLER_ADMIN=central-handlers.js
# CONF_CL_HANDLER_POSITION=central-handlers-kafka.js
# CONF_CL_HANDLER_POSITION_BATCH=central-handlers-kafka.js
# CONF_CL_HANDLER_FULFIL=central-handlers-kafka.js

## QS - Quoting Service Config
QS_CACHE__ENUM_DATA_EXPIRES_IN_MS=4170000
QS_CACHE__PARTICIPANT_DATA_EXPIRES_IN_MS=60000
QS_SWITCH_ENDPOINT="http://callback-handler-svc-cl-sim:3001/admin"
QS_SIMPLE_ROUTING_MODE=false

0 comments on commit 4c649b2

Please sign in to comment.