From 20f397022eac589d41b59fce37ec9bc8df79dfe1 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 10:28:21 +0000 Subject: [PATCH 01/17] fix(csi-1926): fixed missing Slack notifications of timeout --- package-lock.json | 46 ++++++++++++++++++++++++++--------- package.json | 6 ++--- src/constants.js | 14 +++++++++++ src/extras/slack-broadcast.js | 21 +++++++++++++++- src/modes/outbound.js | 21 +++++++++++++++- src/router.js | 17 +++++++------ test/unit/router.test.js | 5 ++-- 7 files changed, 103 insertions(+), 27 deletions(-) create mode 100644 src/constants.js diff --git a/package-lock.json b/package-lock.json index a8bc90a..2947d96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,9 @@ "@slack/webhook": "7.0.6", "atob": "2.1.2", "aws-sdk": "2.1692.0", - "axios": "1.12.2", + "axios": "1.13.2", "cli-table3": "0.6.5", - "commander": "14.0.1", + "commander": "14.0.2", "dotenv": "17.2.3", "fs": "0.0.1-security", "lodash": "4.17.21", @@ -36,7 +36,7 @@ "audit-ci": "7.1.0", "jest": "30.2.0", "jest-junit": "16.0.0", - "npm-check-updates": "19.1.1", + "npm-check-updates": "19.1.2", "nyc": "17.1.0", "parse-strings-in-object": "1.6.0", "pre-commit": "1.2.2", @@ -2095,6 +2095,17 @@ } } }, + "node_modules/@mojaloop/central-services-shared/node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/@mojaloop/central-services-shared/node_modules/dotenv": { "version": "17.2.2", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", @@ -2333,6 +2344,17 @@ "jws": "4.0.0" } }, + "node_modules/@mojaloop/sdk-standard-components/node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", @@ -3897,9 +3919,9 @@ } }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -4722,9 +4744,9 @@ } }, "node_modules/commander": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", - "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", "license": "MIT", "engines": { "node": ">=20" @@ -11353,9 +11375,9 @@ } }, "node_modules/npm-check-updates": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.1.1.tgz", - "integrity": "sha512-vy/uNbaK6Xfj/QzM8OXeALZak67E0uHjUlbdT1YGy4bdj0xlBU6AVd+8bscY8vlDpyzL6Y7mxcrX8kzEDeEpNg==", + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.1.2.tgz", + "integrity": "sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index d637887..1a8c5fc 100644 --- a/package.json +++ b/package.json @@ -75,9 +75,9 @@ "@slack/webhook": "7.0.6", "atob": "2.1.2", "aws-sdk": "2.1692.0", - "axios": "1.12.2", + "axios": "1.13.2", "cli-table3": "0.6.5", - "commander": "14.0.1", + "commander": "14.0.2", "dotenv": "17.2.3", "fs": "0.0.1-security", "lodash": "4.17.21", @@ -93,7 +93,7 @@ "audit-ci": "7.1.0", "jest": "30.2.0", "jest-junit": "16.0.0", - "npm-check-updates": "19.1.1", + "npm-check-updates": "19.1.2", "nyc": "17.1.0", "parse-strings-in-object": "1.6.0", "pre-commit": "1.2.2", diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..6fa2517 --- /dev/null +++ b/src/constants.js @@ -0,0 +1,14 @@ +const { env } = require('node:process') + +const TESTS_EXECUTION_TIMEOUT = parseInt(env.TESTS_EXECUTION_TIMEOUT, 10) || 1000 * 60 * 15 // 15min timout + +const EXIT_CODES = Object.freeze({ + success: 0, + failure: 1, + timeout: 2 +}) + +module.exports = { + EXIT_CODES, + TESTS_EXECUTION_TIMEOUT, +} diff --git a/src/extras/slack-broadcast.js b/src/extras/slack-broadcast.js index 507046c..4acd07c 100644 --- a/src/extras/slack-broadcast.js +++ b/src/extras/slack-broadcast.js @@ -44,10 +44,11 @@ const millisecondsToTime = (milliseconds) => { */ const generateSlackBlocks = (progress, reportURL) => { const slackBlocks = [] + const failedTestCases = [] let totalAssertionsCount = 0 let totalPassedAssertionsCount = 0 let totalRequestsCount = 0 - const failedTestCases = [] + progress.test_cases.forEach(testCase => { // console.log(fStr.yellow(testCase.name)) totalRequestsCount += testCase.requests.length @@ -155,6 +156,7 @@ const generateSlackBlocks = (progress, reportURL) => { } } } + let extramSummaryText = '' if (config.extraSummaryInformation) { const extraSummaryInformationArr = config.extraSummaryInformation.split(',') @@ -171,6 +173,7 @@ const generateSlackBlocks = (progress, reportURL) => { }, ...additionalParams }) + if (reportURL) { slackBlocks.push({ type: 'section', @@ -183,6 +186,7 @@ const generateSlackBlocks = (progress, reportURL) => { slackBlocks.push({ type: 'divider' }) + return slackBlocks } @@ -208,6 +212,20 @@ const sendSlackNotification = async (progress, reportURL = 'http://localhost/') } } +/* istanbul ignore next */ +const sendTimeoutSlackNotification = async (progress, reportURL = 'http://localhost/') => { + const text = 'Timeout Tests Report' + const blocks = generateSlackBlocks(progress, reportURL) + + if (config.slackWebhookUrl) { + await sendWebhook(config.slackWebhookUrl, text, blocks) + } + + if (config.slackWebhookUrlForFailed) { + await sendWebhook(config.slackWebhookUrlForFailed, text, blocks) + } +} + const sendWebhook = async (url, text, blocks) => { const webhook = new IncomingWebhook(url) try { @@ -232,6 +250,7 @@ const needToNotifyFailed = (webhookUrl, progress) => { module.exports = { sendSlackNotification, + sendTimeoutSlackNotification, sendWebhook, needToNotifyFailed } diff --git a/src/modes/outbound.js b/src/modes/outbound.js index 555c89a..55a91f3 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -38,6 +38,8 @@ const releaseCd = require('../extras/release-cd') const TemplateGenerator = require('../utils/templateGenerator') const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib') +let currentProgress // is used in handleTimeout + const totalProgress = { totalTestCases: 0, totalRequests: 0, @@ -211,7 +213,9 @@ const sendTemplate = async (sessionId) => { * @returns {Promise} */ const handleIncomingProgress = async (progress) => { + currentProgress = progress const config = objectStore.get('config') + if (progress.status === 'FINISHED') { let passed try { @@ -256,8 +260,23 @@ const handleIncomingProgress = async (progress) => { } } +/* istanbul ignore next */ +const handleTimeout = async () => { + try { + console.log('Tests execution timed out....') + printTotalProgressCounts() + const testReport = await report.outbound(currentProgress.totalResult) + const slackReportURL = testReport.uploadedReportURL + console.log(`handleTimeout slackReportURL: ${slackReportURL}`) + await slackBroadcast.sendTimeoutSlackNotification(currentProgress.totalResult, slackReportURL) + } catch (err) { + console.log(fStr.red(`Error on handling tests timeout: ${err?.message}`)) + } +} + module.exports = { sendTemplate, handleIncomingProgress, - determineTemplateName + handleTimeout, + determineTemplateName, } diff --git a/src/router.js b/src/router.js index 9dbf806..5eff87e 100644 --- a/src/router.js +++ b/src/router.js @@ -26,12 +26,12 @@ * Georgi Logodazhki (Original Author) -------------- ******/ -const fs = require('fs') + +const fs = require('node:fs') const _ = require('lodash') -const objectStore = require('./objectStore') const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib') - -const TESTS_EXECUTION_TIMEOUT = 1000 * 60 * 15 // 15min timout +const { EXIT_CODES, TESTS_EXECUTION_TIMEOUT } = require('./constants'); +const objectStore = require('./objectStore') const cli = (commanderOptions) => { const configFile = { @@ -87,10 +87,11 @@ const cli = (commanderOptions) => { // Generate a session ID const sessionId = TraceHeaderUtils.generateSessionId() require('./utils/listeners').outbound(sessionId) - require('./modes/outbound').sendTemplate(sessionId) - setTimeout(() => { - console.log('Tests execution timed out....') - process.exit(1) + const { sendTemplate, handleTimeout } = require('./modes/outbound') + sendTemplate(sessionId) + setTimeout(async () => { + await handleTimeout() + process.exit(EXIT_CODES.timeout) }, TESTS_EXECUTION_TIMEOUT) } else { console.log('error: required option \'-e, --environment-file \' not specified') diff --git a/test/unit/router.test.js b/test/unit/router.test.js index 34b7363..7ed1b3c 100644 --- a/test/unit/router.test.js +++ b/test/unit/router.test.js @@ -32,6 +32,7 @@ const spyExit = jest.spyOn(process, 'exit').mockImplementation(() => {}) const { cli } = require('../../src/router') +const { EXIT_CODES, TESTS_EXECUTION_TIMEOUT } = require('../../src/constants'); jest.mock('../../src/utils/listeners') jest.mock('../../src/modes/outbound') @@ -82,8 +83,8 @@ describe('Cli client', () => { expect(() => { cli(config) }).not.toThrow() - jest.advanceTimersByTime(1000 * 60 * 15) - expect(spyExit).toHaveBeenCalledWith(1) + await jest.advanceTimersByTime(TESTS_EXECUTION_TIMEOUT) + expect(spyExit).toHaveBeenCalledWith(EXIT_CODES.timeout) }) it('when mode is outbound and inputFile was not provided should not throw an error', async () => { const config = { From 6df6b58f5b444ca4fbf7868edbcc7e4699c1b014 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 10:28:56 +0000 Subject: [PATCH 02/17] chore(snapshot): 1.12.1-snapshot.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2947d96..2af8f92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.0", + "version": "1.12.1-snapshot.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.0", + "version": "1.12.1-snapshot.6", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index 1a8c5fc..fd771b1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.0", + "version": "1.12.1-snapshot.6", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From 9f807b32677e9f9b8bfc154f281faf7069990224 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 10:33:53 +0000 Subject: [PATCH 03/17] fix(csi-1926): fixed missing Slack notifications of timeout --- src/constants.js | 2 +- src/modes/outbound.js | 2 +- src/router.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/constants.js b/src/constants.js index 6fa2517..4808a0f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -10,5 +10,5 @@ const EXIT_CODES = Object.freeze({ module.exports = { EXIT_CODES, - TESTS_EXECUTION_TIMEOUT, + TESTS_EXECUTION_TIMEOUT } diff --git a/src/modes/outbound.js b/src/modes/outbound.js index 55a91f3..f925d6a 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -278,5 +278,5 @@ module.exports = { sendTemplate, handleIncomingProgress, handleTimeout, - determineTemplateName, + determineTemplateName } diff --git a/src/router.js b/src/router.js index 5eff87e..f43935f 100644 --- a/src/router.js +++ b/src/router.js @@ -30,7 +30,7 @@ const fs = require('node:fs') const _ = require('lodash') const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib') -const { EXIT_CODES, TESTS_EXECUTION_TIMEOUT } = require('./constants'); +const { EXIT_CODES, TESTS_EXECUTION_TIMEOUT } = require('./constants') const objectStore = require('./objectStore') const cli = (commanderOptions) => { From 6065babbce6a4d2d07c3dfcb05d399632326c59e Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 10:33:58 +0000 Subject: [PATCH 04/17] chore(snapshot): 1.12.1-snapshot.7 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2af8f92..cd96f37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.6", + "version": "1.12.1-snapshot.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.6", + "version": "1.12.1-snapshot.7", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index fd771b1..f9345fe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.6", + "version": "1.12.1-snapshot.7", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From 7d2d842ec2a19bdbb624dd8725ca19bc92209a98 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 11:06:52 +0000 Subject: [PATCH 05/17] fix(csi-1926): fixed missing Slack notifications of timeout --- src/constants.js | 2 +- src/modes/outbound.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/constants.js b/src/constants.js index 4808a0f..8930525 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,6 +1,6 @@ const { env } = require('node:process') -const TESTS_EXECUTION_TIMEOUT = parseInt(env.TESTS_EXECUTION_TIMEOUT, 10) || 1000 * 60 * 15 // 15min timout +const TESTS_EXECUTION_TIMEOUT = parseInt(env.TESTS_EXECUTION_TIMEOUT, 10) || 1000 * 60 * 2 const EXIT_CODES = Object.freeze({ success: 0, diff --git a/src/modes/outbound.js b/src/modes/outbound.js index f925d6a..4363177 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -260,7 +260,6 @@ const handleIncomingProgress = async (progress) => { } } -/* istanbul ignore next */ const handleTimeout = async () => { try { console.log('Tests execution timed out....') From 3322e6b2f246dd28ce53e6bc289e2b55f967fca5 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 11:06:59 +0000 Subject: [PATCH 06/17] chore(snapshot): 1.12.1-snapshot.8 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd96f37..4cf8fcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.7", + "version": "1.12.1-snapshot.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.7", + "version": "1.12.1-snapshot.8", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index f9345fe..7faf8ef 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.7", + "version": "1.12.1-snapshot.8", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From fd577ccc5c1928f50fd2c100615b02d388808ea9 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 12:43:43 +0000 Subject: [PATCH 07/17] fix(csi-1926): added fallbackReport for timeout --- src/modes/outbound.js | 53 +++++++++++++++++++++++++++++++++++++++---- src/utils/report.js | 2 ++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/modes/outbound.js b/src/modes/outbound.js index 4363177..1e126e9 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -37,6 +37,7 @@ const slackBroadcast = require('../extras/slack-broadcast') const releaseCd = require('../extras/release-cd') const TemplateGenerator = require('../utils/templateGenerator') const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib') +const { TESTS_EXECUTION_TIMEOUT } = require('../constants') let currentProgress // is used in handleTimeout @@ -264,10 +265,54 @@ const handleTimeout = async () => { try { console.log('Tests execution timed out....') printTotalProgressCounts() - const testReport = await report.outbound(currentProgress.totalResult) - const slackReportURL = testReport.uploadedReportURL - console.log(`handleTimeout slackReportURL: ${slackReportURL}`) - await slackBroadcast.sendTimeoutSlackNotification(currentProgress.totalResult, slackReportURL) + + const config = objectStore.get('config') + + // Check if we have a complete totalResult (unlikely during timeout) + if (currentProgress?.totalResult?.test_cases?.length > 0 && + currentProgress.totalResult.runtimeInformation?.completedTimeISO) { + // We have complete data - use it + console.log('Using available totalResult data') + const testReport = await report.outbound(currentProgress.totalResult) + const slackReportURL = testReport?.uploadedReportURL + await slackBroadcast.sendTimeoutSlackNotification(currentProgress.totalResult, slackReportURL) + } else { + // Build minimal fallback report with summary statistics + const now = Date.now() + const startedTS = now - TESTS_EXECUTION_TIMEOUT + + const fallbackReport = { + name: config.reportName || determineTemplateName(config.inputFiles.split(',')), + runtimeInformation: { + testReportId: `timeout-${now}`, + completedTimeISO: new Date(now).toISOString(), + startedTime: new Date(startedTS).toUTCString(), + completedTime: new Date(now).toUTCString(), + completedTimeUTC: new Date(now).toUTCString(), + startedTS, + completedTS: now, + runDurationMs: TESTS_EXECUTION_TIMEOUT, + totalAssertions: totalProgress.totalAssertions || 0, + totalPassedAssertions: totalProgress.passedAssertions || 0 + }, + test_cases: [], // Cannot reconstruct - empty array + status: 'TERMINATED' + } + + console.log(fStr.yellow('⚠️ Timeout: Cannot generate detailed report - test execution incomplete')) + console.log(fStr.cyan(`Summary: ${totalProgress.passedAssertions}/${totalProgress.totalAssertions} assertions passed`)) + + // Only generate report if format is 'json' (HTML/printhtml require backend processing with complete data) + let testReport = null + if (config.reportFormat === 'json') { + testReport = await report.outbound(fallbackReport) + } else { + console.log(fStr.yellow('⚠️ HTML/printhtml reports unavailable for timeout - use --report-format json')) + } + + const slackReportURL = testReport?.uploadedReportURL + await slackBroadcast.sendTimeoutSlackNotification(fallbackReport, slackReportURL) + } } catch (err) { console.log(fStr.red(`Error on handling tests timeout: ${err?.message}`)) } diff --git a/src/utils/report.js b/src/utils/report.js index cee0b98..68af56b 100644 --- a/src/utils/report.js +++ b/src/utils/report.js @@ -48,6 +48,7 @@ const report = async (data, reportType) => { const config = objectStore.get('config') let reportData let reportFilename + switch (config.reportFormat) { case 'none': return returnInfo @@ -86,6 +87,7 @@ const report = async (data, reportType) => { console.log('reportFormat is not supported') return } + if (config.reportTarget) { const reportTargetRe = /(.*):\/\/(.*)/g const reportTargetArr = reportTargetRe.exec(config.reportTarget) From ab62e7e7c9987a9b6eb02c0898da678e20c47da7 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 12:43:46 +0000 Subject: [PATCH 08/17] chore(snapshot): 1.12.1-snapshot.9 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4cf8fcd..8aa755f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.8", + "version": "1.12.1-snapshot.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.8", + "version": "1.12.1-snapshot.9", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index 7faf8ef..f25c8d9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.8", + "version": "1.12.1-snapshot.9", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From feb5829e92765a7dd15d5863bb9a02555959966a Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 12:48:37 +0000 Subject: [PATCH 09/17] fix(csi-1926): added fallbackReport for timeout --- src/modes/outbound.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modes/outbound.js b/src/modes/outbound.js index 1e126e9..dc26816 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -261,6 +261,7 @@ const handleIncomingProgress = async (progress) => { } } +// istanbul ignore next const handleTimeout = async () => { try { console.log('Tests execution timed out....') From 52d87c5d9a46951980179c2f5bbd22df9c321f2d Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 12:48:40 +0000 Subject: [PATCH 10/17] chore(snapshot): 1.12.1-snapshot.10 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8aa755f..7efc317 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.9", + "version": "1.12.1-snapshot.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.9", + "version": "1.12.1-snapshot.10", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index f25c8d9..bff80f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.9", + "version": "1.12.1-snapshot.10", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From 35c61cafb250ae9cbbbab4471d8056eef07c76c6 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 13:48:37 +0000 Subject: [PATCH 11/17] fix(csi-1926): added fallbackReport for timeout --- src/extras/slack-broadcast.js | 8 +++-- src/modes/outbound.js | 68 +++++++++++++---------------------- 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/src/extras/slack-broadcast.js b/src/extras/slack-broadcast.js index 4acd07c..49c12de 100644 --- a/src/extras/slack-broadcast.js +++ b/src/extras/slack-broadcast.js @@ -54,6 +54,7 @@ const generateSlackBlocks = (progress, reportURL) => { totalRequestsCount += testCase.requests.length let testCaseAssertionsCount = 0 let testCasePassedAssertionsCount = 0 + testCase.requests.forEach(req => { const passedAssertionsCount = req.request.tests && req.request.tests.passedAssertionsCount ? req.request.tests.passedAssertionsCount : 0 const assertionsCount = req.request.tests && req.request.tests.assertions && req.request.tests.assertions.length ? req.request.tests.assertions.length : 0 @@ -62,6 +63,7 @@ const generateSlackBlocks = (progress, reportURL) => { testCaseAssertionsCount += assertionsCount testCasePassedAssertionsCount += passedAssertionsCount }) + if (testCaseAssertionsCount !== testCasePassedAssertionsCount) { failedTestCases.push({ name: testCase.name, @@ -84,6 +86,8 @@ const generateSlackBlocks = (progress, reportURL) => { // totalAssertionsCount = totalPassedAssertionsCount // failedTestCases.length = 0 + const isPassed = (totalAssertionsCount === totalPassedAssertionsCount) && (totalPassedAssertionsCount > 0) + if (config.briefSummaryPrefix) { const top5FailedTestCases = failedTestCases.sort((a, b) => b.failedAssertions - a.failedAssertions).slice(0, 5) return [{ @@ -91,7 +95,7 @@ const generateSlackBlocks = (progress, reportURL) => { elements: [{ type: 'rich_text_section', elements: [ - { type: 'text', text: `${totalAssertionsCount === totalPassedAssertionsCount ? '✅' : '⚠️'}${config.briefSummaryPrefix || ''} ` }, + { type: 'text', text: `${isPassed ? '✅' : (progress.isTimeout ? '⌛' : '⚠️')}${config.briefSummaryPrefix || ''} ` }, reportURL ? { type: 'link', url: reportURL, text: config.reportName } : { type: 'text', text: config.reportName }, { type: 'text', text: ' tests: ' }, { type: 'text', text: String(progress.test_cases.length), style: { code: true } }, @@ -139,7 +143,7 @@ const generateSlackBlocks = (progress, reportURL) => { summaryText += '>Runtime duration: *' + `${progress.runtimeInformation.runDurationMs} ms` + '*\n' const additionalParams = {} - if (totalAssertionsCount === totalPassedAssertionsCount) { + if (isPassed) { if (config.slackPassedImage) { additionalParams.accessory = { type: 'image', diff --git a/src/modes/outbound.js b/src/modes/outbound.js index dc26816..4075808 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -191,6 +191,7 @@ const sendTemplate = async (sessionId) => { * @property {string} status * @property {Object} totalResult * @property {Object} saveReportStatus + * @property {Boolean} [isTimeout] * @property {unknown} [otherFields] - see ml-testing-toolkit repo. */ @@ -266,54 +267,35 @@ const handleTimeout = async () => { try { console.log('Tests execution timed out....') printTotalProgressCounts() + console.log('') const config = objectStore.get('config') - // Check if we have a complete totalResult (unlikely during timeout) - if (currentProgress?.totalResult?.test_cases?.length > 0 && - currentProgress.totalResult.runtimeInformation?.completedTimeISO) { - // We have complete data - use it - console.log('Using available totalResult data') - const testReport = await report.outbound(currentProgress.totalResult) - const slackReportURL = testReport?.uploadedReportURL - await slackBroadcast.sendTimeoutSlackNotification(currentProgress.totalResult, slackReportURL) - } else { - // Build minimal fallback report with summary statistics - const now = Date.now() - const startedTS = now - TESTS_EXECUTION_TIMEOUT - - const fallbackReport = { - name: config.reportName || determineTemplateName(config.inputFiles.split(',')), - runtimeInformation: { - testReportId: `timeout-${now}`, - completedTimeISO: new Date(now).toISOString(), - startedTime: new Date(startedTS).toUTCString(), - completedTime: new Date(now).toUTCString(), - completedTimeUTC: new Date(now).toUTCString(), - startedTS, - completedTS: now, - runDurationMs: TESTS_EXECUTION_TIMEOUT, - totalAssertions: totalProgress.totalAssertions || 0, - totalPassedAssertions: totalProgress.passedAssertions || 0 - }, - test_cases: [], // Cannot reconstruct - empty array - status: 'TERMINATED' - } - - console.log(fStr.yellow('⚠️ Timeout: Cannot generate detailed report - test execution incomplete')) - console.log(fStr.cyan(`Summary: ${totalProgress.passedAssertions}/${totalProgress.totalAssertions} assertions passed`)) + // Build minimal report with summary statistics + const now = Date.now() + const startedTS = now - TESTS_EXECUTION_TIMEOUT - // Only generate report if format is 'json' (HTML/printhtml require backend processing with complete data) - let testReport = null - if (config.reportFormat === 'json') { - testReport = await report.outbound(fallbackReport) - } else { - console.log(fStr.yellow('⚠️ HTML/printhtml reports unavailable for timeout - use --report-format json')) - } - - const slackReportURL = testReport?.uploadedReportURL - await slackBroadcast.sendTimeoutSlackNotification(fallbackReport, slackReportURL) + const fallbackReport = { + name: config.reportName || determineTemplateName(config.inputFiles.split(',')), + runtimeInformation: { + testReportId: `timeout-${now}`, + completedTimeISO: new Date(now).toISOString(), + startedTime: new Date(startedTS).toUTCString(), + completedTime: new Date(now).toUTCString(), + completedTimeUTC: new Date(now).toUTCString(), + startedTS, + completedTS: now, + runDurationMs: TESTS_EXECUTION_TIMEOUT, + totalAssertions: totalProgress.totalAssertions || 0, + totalPassedAssertions: totalProgress.passedAssertions || 0 + }, + test_cases: [], // Cannot reconstruct + status: 'TERMINATED', + isTimeout: true, } + console.log(fStr.yellow(`⚠️ Summary (timeout): ${totalProgress.passedAssertions}/${totalProgress.totalAssertions} assertions passed`)) + + await slackBroadcast.sendTimeoutSlackNotification(fallbackReport) } catch (err) { console.log(fStr.red(`Error on handling tests timeout: ${err?.message}`)) } From 6808e3b353c4a198b833601aa0fd764294266789 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 13:48:41 +0000 Subject: [PATCH 12/17] chore(snapshot): 1.12.1-snapshot.11 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7efc317..2675e4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.10", + "version": "1.12.1-snapshot.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.10", + "version": "1.12.1-snapshot.11", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index bff80f5..3c0b338 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.10", + "version": "1.12.1-snapshot.11", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From c5d3d09530411fbd0f1dc4411df45311563e5887 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 13:49:58 +0000 Subject: [PATCH 13/17] fix(csi-1926): added fallbackReport for timeout --- src/modes/outbound.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modes/outbound.js b/src/modes/outbound.js index 4075808..5bca5e1 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -39,7 +39,7 @@ const TemplateGenerator = require('../utils/templateGenerator') const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib') const { TESTS_EXECUTION_TIMEOUT } = require('../constants') -let currentProgress // is used in handleTimeout +// let currentProgress // is used in handleTimeout const totalProgress = { totalTestCases: 0, @@ -215,7 +215,7 @@ const sendTemplate = async (sessionId) => { * @returns {Promise} */ const handleIncomingProgress = async (progress) => { - currentProgress = progress + // currentProgress = progress const config = objectStore.get('config') if (progress.status === 'FINISHED') { @@ -291,7 +291,7 @@ const handleTimeout = async () => { }, test_cases: [], // Cannot reconstruct status: 'TERMINATED', - isTimeout: true, + isTimeout: true } console.log(fStr.yellow(`⚠️ Summary (timeout): ${totalProgress.passedAssertions}/${totalProgress.totalAssertions} assertions passed`)) From ff0d9641d077f3a4cf7c6633bc5529dfcf5469e8 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 13:50:01 +0000 Subject: [PATCH 14/17] chore(snapshot): 1.12.1-snapshot.12 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2675e4f..990c574 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.11", + "version": "1.12.1-snapshot.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.11", + "version": "1.12.1-snapshot.12", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index 3c0b338..efcee87 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.11", + "version": "1.12.1-snapshot.12", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From 38f0359cdb9e3db08f521bfa92e59aefe0a45d18 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 13:51:56 +0000 Subject: [PATCH 15/17] chore(snapshot): 1.12.1-snapshot.13 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 990c574..ad1ea8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.12", + "version": "1.12.1-snapshot.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mojaloop/ml-testing-toolkit-client-lib", - "version": "1.12.1-snapshot.12", + "version": "1.12.1-snapshot.13", "license": "Apache-2.0", "dependencies": { "@mojaloop/central-services-logger": "11.10.1", diff --git a/package.json b/package.json index efcee87..012d779 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mojaloop/ml-testing-toolkit-client-lib", "description": "Testing Toolkit Client Library", - "version": "1.12.1-snapshot.12", + "version": "1.12.1-snapshot.13", "license": "Apache-2.0", "author": "Vijaya Kumar Guthi, ModusBox Inc. ", "contributors": [ From b240405e0cee43b6739a76c2ba1236593c9374a0 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 14:21:46 +0000 Subject: [PATCH 16/17] fix(csi-1926): added fallbackReport for timeout --- src/modes/outbound.js | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/modes/outbound.js b/src/modes/outbound.js index 5bca5e1..d19560b 100644 --- a/src/modes/outbound.js +++ b/src/modes/outbound.js @@ -39,8 +39,6 @@ const TemplateGenerator = require('../utils/templateGenerator') const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib') const { TESTS_EXECUTION_TIMEOUT } = require('../constants') -// let currentProgress // is used in handleTimeout - const totalProgress = { totalTestCases: 0, totalRequests: 0, @@ -215,7 +213,6 @@ const sendTemplate = async (sessionId) => { * @returns {Promise} */ const handleIncomingProgress = async (progress) => { - // currentProgress = progress const config = objectStore.get('config') if (progress.status === 'FINISHED') { @@ -266,36 +263,26 @@ const handleIncomingProgress = async (progress) => { const handleTimeout = async () => { try { console.log('Tests execution timed out....') - printTotalProgressCounts() - console.log('') - const config = objectStore.get('config') - - // Build minimal report with summary statistics const now = Date.now() - const startedTS = now - TESTS_EXECUTION_TIMEOUT - const fallbackReport = { + const timeoutReport = { name: config.reportName || determineTemplateName(config.inputFiles.split(',')), runtimeInformation: { testReportId: `timeout-${now}`, - completedTimeISO: new Date(now).toISOString(), - startedTime: new Date(startedTS).toUTCString(), + startedTime: new Date(now - TESTS_EXECUTION_TIMEOUT).toUTCString(), completedTime: new Date(now).toUTCString(), - completedTimeUTC: new Date(now).toUTCString(), - startedTS, - completedTS: now, runDurationMs: TESTS_EXECUTION_TIMEOUT, - totalAssertions: totalProgress.totalAssertions || 0, - totalPassedAssertions: totalProgress.passedAssertions || 0 + totalAssertions: totalProgress.totalAssertions, + totalPassedAssertions: totalProgress.passedAssertions }, - test_cases: [], // Cannot reconstruct + test_cases: [], // think if we need to reconstruct passed test cases status: 'TERMINATED', isTimeout: true } - console.log(fStr.yellow(`⚠️ Summary (timeout): ${totalProgress.passedAssertions}/${totalProgress.totalAssertions} assertions passed`)) + console.log(fStr.yellow(`⚠️ Summary (timeout): ${totalProgress.passedAssertions}/${totalProgress.totalAssertions} assertions passed`)) - await slackBroadcast.sendTimeoutSlackNotification(fallbackReport) + await slackBroadcast.sendTimeoutSlackNotification(timeoutReport) } catch (err) { console.log(fStr.red(`Error on handling tests timeout: ${err?.message}`)) } From a61fe70b7f9ad1e31ee5a084b902dca6f135fd0f Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 6 Nov 2025 14:27:04 +0000 Subject: [PATCH 17/17] fix(csi-1926): fixed PR comments --- src/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.js b/src/constants.js index 8930525..954720f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,6 +1,6 @@ const { env } = require('node:process') -const TESTS_EXECUTION_TIMEOUT = parseInt(env.TESTS_EXECUTION_TIMEOUT, 10) || 1000 * 60 * 2 +const TESTS_EXECUTION_TIMEOUT = parseInt(env.TESTS_EXECUTION_TIMEOUT, 10) || 1000 * 60 * 15 const EXIT_CODES = Object.freeze({ success: 0,