ml-testing-toolkit 18.15.1 → 18.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.ncurc.yaml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
# Changelog: [mojaloop/thirdparty-api-svc](https://github.com/mojaloop/thirdparty-api-svc)
|
|
2
|
+
## [18.16.0](https://github.com/mojaloop/ml-testing-toolkit/compare/v18.15.1...v18.16.0) (2025-09-16)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* **csi-1782:** fix MyEmitter memory leak ([#342](https://github.com/mojaloop/ml-testing-toolkit/issues/342)) ([c141048](https://github.com/mojaloop/ml-testing-toolkit/commit/c1410487a3c17824b0869b6920c2132d491a6007))
|
|
8
|
+
|
|
2
9
|
### [18.15.1](https://github.com/mojaloop/ml-testing-toolkit/compare/v18.15.0...v18.15.1) (2025-09-01)
|
|
3
10
|
|
|
4
11
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ml-testing-toolkit",
|
|
3
3
|
"description": "Testing Toolkit for Mojaloop implementations",
|
|
4
|
-
"version": "18.
|
|
4
|
+
"version": "18.16.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Vijaya Kumar Guthi, ModusBox Inc. ",
|
|
7
7
|
"contributors": [
|
|
@@ -78,23 +78,23 @@
|
|
|
78
78
|
"@hapi/hapi": "21.4.3",
|
|
79
79
|
"@hapi/inert": "7.1.0",
|
|
80
80
|
"@hapi/vision": "7.0.3",
|
|
81
|
-
"@mojaloop/central-services-logger": "11.9.
|
|
82
|
-
"@mojaloop/central-services-metrics": "12.
|
|
83
|
-
"@mojaloop/ml-schema-transformer-lib": "2.7.
|
|
81
|
+
"@mojaloop/central-services-logger": "11.9.3",
|
|
82
|
+
"@mojaloop/central-services-metrics": "12.7.1",
|
|
83
|
+
"@mojaloop/ml-schema-transformer-lib": "2.7.8",
|
|
84
84
|
"@mojaloop/ml-testing-toolkit-shared-lib": "14.2.0",
|
|
85
|
-
"@mojaloop/sdk-standard-components": "19.
|
|
85
|
+
"@mojaloop/sdk-standard-components": "19.17.0",
|
|
86
86
|
"@now-ims/hapi-now-auth": "2.1.0",
|
|
87
87
|
"@types/socket.io": "3.0.2",
|
|
88
88
|
"adm-zip": "0.5.16",
|
|
89
89
|
"ajv-formats": "3.0.1",
|
|
90
90
|
"atob": "2.1.2",
|
|
91
|
-
"axios": "1.
|
|
91
|
+
"axios": "1.12.2",
|
|
92
92
|
"chai": "4.4.1",
|
|
93
93
|
"connection-string": "^5.0.0",
|
|
94
94
|
"cookie-parser": "1.4.7",
|
|
95
95
|
"cookies": "0.9.1",
|
|
96
96
|
"cors": "2.8.5",
|
|
97
|
-
"dotenv": "17.2.
|
|
97
|
+
"dotenv": "17.2.2",
|
|
98
98
|
"express": "5.1.0",
|
|
99
99
|
"express-validator": "7.2.1",
|
|
100
100
|
"fs": "0.0.1-security",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"json-rules-engine": "7.3.1",
|
|
109
109
|
"jsonwebtoken": "9.0.2",
|
|
110
110
|
"lodash": "4.17.21",
|
|
111
|
-
"mongoose": "8.18.
|
|
111
|
+
"mongoose": "8.18.1",
|
|
112
112
|
"multer": "2.0.2",
|
|
113
113
|
"mustache": "4.2.0",
|
|
114
114
|
"mv": "2.1.1",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"jest": "29.7.0",
|
|
139
139
|
"jest-junit": "16.0.0",
|
|
140
140
|
"nodemon": "3.1.10",
|
|
141
|
-
"npm-check-updates": "18.
|
|
141
|
+
"npm-check-updates": "18.1.1",
|
|
142
142
|
"nyc": "17.1.0",
|
|
143
143
|
"parse-strings-in-object": "1.6.0",
|
|
144
144
|
"pre-commit": "1.2.2",
|
|
@@ -47,6 +47,12 @@ class InboundEventListener {
|
|
|
47
47
|
|
|
48
48
|
async init () {
|
|
49
49
|
this.userConfig = await Config.getStoredUserConfig()
|
|
50
|
+
|
|
51
|
+
// Fixes the MyEmitter listener leak issue
|
|
52
|
+
if (this.emitter.listenerCount('newInbound') > 0) {
|
|
53
|
+
this.emitter.removeAllListeners('newInbound')
|
|
54
|
+
}
|
|
55
|
+
|
|
50
56
|
this.emitter.on('newInbound', (data) => {
|
|
51
57
|
for (const [, eventListener] of Object.entries(this.eventListeners)) {
|
|
52
58
|
// Match method, path and condition for each inbound request
|
|
@@ -98,59 +104,74 @@ class InboundEventListener {
|
|
|
98
104
|
|
|
99
105
|
getMessage (clientName, timeout = 5000) {
|
|
100
106
|
return new Promise((resolve, reject) => {
|
|
107
|
+
let timer = null
|
|
108
|
+
|
|
109
|
+
const cleanup = () => {
|
|
110
|
+
if (timer) {
|
|
111
|
+
clearTimeout(timer)
|
|
112
|
+
timer = null
|
|
113
|
+
}
|
|
114
|
+
if (this.eventListeners[clientName] && this.eventListeners[clientName].eventEmitter) {
|
|
115
|
+
this.eventListeners[clientName].eventEmitter.removeAllListeners('newMessage')
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
101
119
|
if (!this.eventListeners[clientName]) {
|
|
102
120
|
resolve(null)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check for the message received already
|
|
125
|
+
if (this.eventListeners[clientName].message !== null) {
|
|
126
|
+
// Store the message somewhere
|
|
127
|
+
const retMessage = this.parseMessage(this.eventListeners[clientName].message)
|
|
128
|
+
// Destroy the event listener
|
|
129
|
+
this.destroy(clientName)
|
|
130
|
+
// Return the stored message
|
|
131
|
+
// this.customLog('Returning stored message...')
|
|
132
|
+
if (this.transformer.reverseTransform) {
|
|
133
|
+
this.transformer.reverseTransform(retMessage).then((result) => {
|
|
134
|
+
resolve(result)
|
|
135
|
+
}).catch((err) => {
|
|
136
|
+
this.customLog('Error transforming message: ' + err)
|
|
137
|
+
resolve(retMessage)
|
|
138
|
+
})
|
|
139
|
+
} else {
|
|
140
|
+
resolve(retMessage)
|
|
141
|
+
}
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Listen for the new message for some time
|
|
146
|
+
// Set the timer
|
|
147
|
+
timer = setTimeout(() => {
|
|
148
|
+
try {
|
|
149
|
+
this.customLog('Error: Timeout')
|
|
108
150
|
// Destroy the event listener
|
|
109
151
|
this.destroy(clientName)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
152
|
+
resolve(null)
|
|
153
|
+
} catch (err) {
|
|
154
|
+
reject(err)
|
|
155
|
+
}
|
|
156
|
+
}, timeout)
|
|
157
|
+
|
|
158
|
+
// Listen for message
|
|
159
|
+
this.eventListeners[clientName].eventEmitter.once('newMessage', (message) => {
|
|
160
|
+
cleanup()
|
|
161
|
+
this.destroy(clientName)
|
|
162
|
+
const retMessage = this.parseMessage(message)
|
|
163
|
+
|
|
164
|
+
if (this.transformer.reverseTransform) {
|
|
165
|
+
this.transformer.reverseTransform(retMessage).then((result) => {
|
|
166
|
+
resolve(result)
|
|
167
|
+
}).catch((err) => {
|
|
168
|
+
this.customLog('Error transforming message: ' + err)
|
|
120
169
|
resolve(retMessage)
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
// Listen for the new message for some time
|
|
124
|
-
let timer = null
|
|
125
|
-
// Set the timer
|
|
126
|
-
timer = setTimeout(() => {
|
|
127
|
-
try {
|
|
128
|
-
this.customLog('Error: Timeout')
|
|
129
|
-
// Destroy the event listener
|
|
130
|
-
this.destroy(clientName)
|
|
131
|
-
resolve(null)
|
|
132
|
-
} catch (err) {
|
|
133
|
-
reject(err)
|
|
134
|
-
}
|
|
135
|
-
}, timeout)
|
|
136
|
-
// Listen for message
|
|
137
|
-
this.eventListeners[clientName].eventEmitter.once('newMessage', (message) => {
|
|
138
|
-
clearTimeout(timer)
|
|
139
|
-
this.destroy(clientName)
|
|
140
|
-
const retMessage = this.parseMessage(message)
|
|
141
|
-
if (this.transformer.reverseTransform) {
|
|
142
|
-
this.transformer.reverseTransform(retMessage).then((result) => {
|
|
143
|
-
resolve(result)
|
|
144
|
-
}).catch((err) => {
|
|
145
|
-
this.customLog('Error transforming message: ' + err)
|
|
146
|
-
resolve(retMessage)
|
|
147
|
-
})
|
|
148
|
-
} else {
|
|
149
|
-
resolve(retMessage)
|
|
150
|
-
}
|
|
151
170
|
})
|
|
171
|
+
} else {
|
|
172
|
+
resolve(retMessage)
|
|
152
173
|
}
|
|
153
|
-
}
|
|
174
|
+
})
|
|
154
175
|
})
|
|
155
176
|
}
|
|
156
177
|
|
|
@@ -53,6 +53,8 @@ class WebSocketClientManager {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
connect (url, clientName, timeout = 15000) {
|
|
56
|
+
this.customLog(`Connecting to WebSocket URL: ${url} with client name: ${clientName} and timeout: ${timeout}ms`)
|
|
57
|
+
|
|
56
58
|
const tlsOptions = { rejectUnauthorized: false }
|
|
57
59
|
const urlObject = new URL(url)
|
|
58
60
|
if (this.userConfig.CLIENT_MUTUAL_TLS_ENABLED) {
|
|
@@ -107,41 +109,48 @@ class WebSocketClientManager {
|
|
|
107
109
|
|
|
108
110
|
getMessage (clientName, timeout = 5000) {
|
|
109
111
|
return new Promise((resolve, reject) => {
|
|
112
|
+
let timer = null
|
|
113
|
+
|
|
114
|
+
const cleanup = () => {
|
|
115
|
+
if (timer) {
|
|
116
|
+
clearTimeout(timer)
|
|
117
|
+
timer = null
|
|
118
|
+
}
|
|
119
|
+
if (this.ws[clientName] && this.ws[clientName].eventEmitter) {
|
|
120
|
+
this.ws[clientName].eventEmitter.removeAllListeners('newMessage')
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
110
124
|
if (!this.ws[clientName]) {
|
|
111
125
|
resolve(null)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check for already received message
|
|
130
|
+
if (this.ws[clientName].message !== null) {
|
|
131
|
+
const retMessage = this.parseMessage(this.ws[clientName].message)
|
|
132
|
+
this.disconnect(clientName)
|
|
133
|
+
resolve(retMessage)
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Set timeout
|
|
138
|
+
timer = setTimeout(() => {
|
|
139
|
+
try {
|
|
140
|
+
cleanup()
|
|
118
141
|
this.disconnect(clientName)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
} else {
|
|
123
|
-
// Listen for the new message for some time
|
|
124
|
-
let timer = null
|
|
125
|
-
// Set the timer
|
|
126
|
-
timer = setTimeout(() => {
|
|
127
|
-
try {
|
|
128
|
-
this.ws[clientName].eventEmitter.removeAllListeners('newMessage')
|
|
129
|
-
// Disconnect the websocket connection
|
|
130
|
-
this.disconnect(clientName)
|
|
131
|
-
resolve(null)
|
|
132
|
-
} catch (err) {
|
|
133
|
-
reject(err)
|
|
134
|
-
}
|
|
135
|
-
}, timeout)
|
|
136
|
-
// Listen for message
|
|
137
|
-
this.ws[clientName].eventEmitter.once('newMessage', (message) => {
|
|
138
|
-
clearTimeout(timer)
|
|
139
|
-
this.ws[clientName].eventEmitter.removeAllListeners('newMessage')
|
|
140
|
-
this.disconnect(clientName)
|
|
141
|
-
resolve(this.parseMessage(message))
|
|
142
|
-
})
|
|
142
|
+
resolve(null)
|
|
143
|
+
} catch (err) {
|
|
144
|
+
reject(err)
|
|
143
145
|
}
|
|
144
|
-
}
|
|
146
|
+
}, timeout)
|
|
147
|
+
|
|
148
|
+
// Listen for message
|
|
149
|
+
this.ws[clientName].eventEmitter.once('newMessage', (message) => {
|
|
150
|
+
cleanup()
|
|
151
|
+
this.disconnect(clientName)
|
|
152
|
+
resolve(this.parseMessage(message))
|
|
153
|
+
})
|
|
145
154
|
})
|
|
146
155
|
}
|
|
147
156
|
|
|
@@ -155,7 +164,10 @@ class WebSocketClientManager {
|
|
|
155
164
|
|
|
156
165
|
disconnect (clientName) {
|
|
157
166
|
if (this.ws[clientName]) {
|
|
158
|
-
this.ws[clientName].client
|
|
167
|
+
if (this.ws[clientName].client) {
|
|
168
|
+
this.ws[clientName].client.removeAllListeners()
|
|
169
|
+
this.ws[clientName].client.close()
|
|
170
|
+
}
|
|
159
171
|
if (this.ws[clientName].eventEmitter) {
|
|
160
172
|
this.ws[clientName].eventEmitter.removeAllListeners()
|
|
161
173
|
}
|
|
@@ -170,7 +182,10 @@ class WebSocketClientManager {
|
|
|
170
182
|
|
|
171
183
|
disconnectAll () {
|
|
172
184
|
for (const clientName in this.ws) {
|
|
173
|
-
this.ws[clientName].client
|
|
185
|
+
if (this.ws[clientName].client) {
|
|
186
|
+
this.ws[clientName].client.removeAllListeners()
|
|
187
|
+
this.ws[clientName].client.close()
|
|
188
|
+
}
|
|
174
189
|
if (this.ws[clientName].eventEmitter) {
|
|
175
190
|
this.ws[clientName].eventEmitter.removeAllListeners()
|
|
176
191
|
}
|
|
@@ -183,13 +198,6 @@ class WebSocketClientManager {
|
|
|
183
198
|
}
|
|
184
199
|
return true
|
|
185
200
|
}
|
|
186
|
-
|
|
187
|
-
clearAllTimers () {
|
|
188
|
-
Object.keys(this.timers).forEach((clientName) => {
|
|
189
|
-
clearTimeout(this.timers[clientName])
|
|
190
|
-
delete this.timers[clientName]
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
201
|
}
|
|
194
202
|
|
|
195
203
|
module.exports = {
|