@mojaloop/ml-testing-toolkit-client-lib 0.0.2
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/.circleci/config.yml +502 -0
- package/.dockerignore +10 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +5 -0
- package/Dockerfile +25 -0
- package/LICENSE.md +10 -0
- package/README.md +213 -0
- package/audit-resolve.json +14 -0
- package/bin/cli.js +2 -0
- package/jest.config.js +16 -0
- package/native-app-generation/assets/macos/start.sh +7 -0
- package/native-app-generation/build-native-app.sh +57 -0
- package/package.json +132 -0
- package/src/client.js +49 -0
- package/src/extras/s3-upload.js +69 -0
- package/src/extras/slack-broadcast.js +149 -0
- package/src/modes/monitoring.js +32 -0
- package/src/modes/outbound.js +179 -0
- package/src/modes/testcaseDefinitionReport.js +53 -0
- package/src/objectStore.js +39 -0
- package/src/router.js +110 -0
- package/src/sample-config.json +11 -0
- package/src/utils/file-utils.js +53 -0
- package/src/utils/listeners.js +46 -0
- package/src/utils/logger.js +93 -0
- package/src/utils/report.js +127 -0
- package/src/utils/templateGenerator.js +65 -0
- package/test/lib/mockRequest.js +38 -0
- package/test/lib/mockResponse.js +53 -0
- package/test/unit/client.test.js +36 -0
- package/test/unit/extras/s3-upload.test.js +99 -0
- package/test/unit/extras/slack-broadcast.test.js +125 -0
- package/test/unit/listener.test.js +58 -0
- package/test/unit/logger.test.js +259 -0
- package/test/unit/monitoring-mode.test.js +38 -0
- package/test/unit/outbound-mode.test.js +192 -0
- package/test/unit/report.test.js +258 -0
- package/test/unit/router.test.js +110 -0
- package/test/unit/templateGenerator.test.js +119 -0
- package/test/unit/testcaseDefinitionReport-mode.test.js +72 -0
- package/test/util/testConfig.js +38 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Vijay Kumar Guthi <vijaya.guthi@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
const { IncomingWebhook } = require('@slack/webhook')
|
|
25
|
+
const objectStore = require('../objectStore')
|
|
26
|
+
|
|
27
|
+
const config = objectStore.get('config')
|
|
28
|
+
|
|
29
|
+
const generateSlackBlocks = (progress) => {
|
|
30
|
+
const slackBlocks = []
|
|
31
|
+
let totalAssertionsCount = 0
|
|
32
|
+
let totalPassedAssertionsCount = 0
|
|
33
|
+
let totalRequestsCount = 0
|
|
34
|
+
progress.test_cases.forEach(testCase => {
|
|
35
|
+
// console.log(fStr.yellow(testCase.name))
|
|
36
|
+
totalRequestsCount += testCase.requests.length
|
|
37
|
+
// let testCaseAssertionsCount = 0
|
|
38
|
+
// let testCasePassedAssertionsCount = 0
|
|
39
|
+
testCase.requests.forEach(req => {
|
|
40
|
+
const passedAssertionsCount = req.request.tests && req.request.tests.passedAssertionsCount ? req.request.tests.passedAssertionsCount : 0
|
|
41
|
+
const assertionsCount = req.request.tests && req.request.tests.assertions && req.request.tests.assertions.length ? req.request.tests.assertions.length : 0
|
|
42
|
+
totalAssertionsCount += assertionsCount
|
|
43
|
+
totalPassedAssertionsCount += passedAssertionsCount
|
|
44
|
+
// testCaseAssertionsCount += assertionsCount
|
|
45
|
+
// testCasePassedAssertionsCount += passedAssertionsCount
|
|
46
|
+
})
|
|
47
|
+
// const passed = testCasePassedAssertionsCount === testCaseAssertionsCount
|
|
48
|
+
// // TODO: make sure this list should not be more than 40 because we can add only max 50 blocks in a slack message
|
|
49
|
+
// if(!passed) {
|
|
50
|
+
// slackBlocks.push({
|
|
51
|
+
// type: 'section',
|
|
52
|
+
// text: {
|
|
53
|
+
// type: 'mrkdwn',
|
|
54
|
+
// text: `${testCase.name} - [ *${testCasePassedAssertionsCount}/${testCaseAssertionsCount}* ]` + ' `FAILED`'
|
|
55
|
+
// }
|
|
56
|
+
// })
|
|
57
|
+
// }
|
|
58
|
+
})
|
|
59
|
+
let summaryText = ''
|
|
60
|
+
|
|
61
|
+
summaryText += '>Total assertions: *' + totalAssertionsCount + '*\n'
|
|
62
|
+
summaryText += '>Passed assertions: *' + totalPassedAssertionsCount + '*\n'
|
|
63
|
+
summaryText += '>Failed assertions: *' + (totalAssertionsCount - totalPassedAssertionsCount) + '*\n'
|
|
64
|
+
summaryText += '>Total requests: *' + totalRequestsCount + '*\n'
|
|
65
|
+
summaryText += '>Total test cases: *' + progress.test_cases.length + '*\n'
|
|
66
|
+
summaryText += '>Passed percentage: *' + `${(100 * (totalPassedAssertionsCount / totalAssertionsCount)).toFixed(2)}%` + '*\n'
|
|
67
|
+
summaryText += '>Started time: *' + progress.runtimeInformation.startedTime + '*\n'
|
|
68
|
+
summaryText += '>Completed time: *' + progress.runtimeInformation.completedTime + '*\n'
|
|
69
|
+
summaryText += '>Runtime duration: *' + `${progress.runtimeInformation.runDurationMs} ms` + '*\n'
|
|
70
|
+
|
|
71
|
+
const additionalParams = {}
|
|
72
|
+
if (totalAssertionsCount === totalPassedAssertionsCount) {
|
|
73
|
+
if (config.slackPassedImage) {
|
|
74
|
+
additionalParams.accessory = {
|
|
75
|
+
type: 'image',
|
|
76
|
+
image_url: config.slackPassedImage,
|
|
77
|
+
alt_text: 'PASSED'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
if (config.slackFailedImage) {
|
|
82
|
+
additionalParams.accessory = {
|
|
83
|
+
type: 'image',
|
|
84
|
+
image_url: config.slackFailedImage,
|
|
85
|
+
alt_text: 'FAILED'
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
let extramSummaryText = ''
|
|
90
|
+
if (config.extraSummaryInformation) {
|
|
91
|
+
const extraSummaryInformationArr = config.extraSummaryInformation.split(',')
|
|
92
|
+
extraSummaryInformationArr.forEach(info => {
|
|
93
|
+
const infoArr = info.split(':')
|
|
94
|
+
extramSummaryText += infoArr[0] + ': `' + infoArr[1] + '`\n'
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
slackBlocks.push({
|
|
98
|
+
type: 'section',
|
|
99
|
+
text: {
|
|
100
|
+
type: 'mrkdwn',
|
|
101
|
+
text: '*Test Result:*' + ((totalAssertionsCount === totalPassedAssertionsCount) ? ' `PASSED` ' : ' `FAILED` ') + '\n' + extramSummaryText + summaryText
|
|
102
|
+
},
|
|
103
|
+
...additionalParams
|
|
104
|
+
})
|
|
105
|
+
return slackBlocks
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const sendSlackNotification = async (progress, reportURL = null) => {
|
|
109
|
+
if (config.slackWebhookUrl) {
|
|
110
|
+
const url = config.slackWebhookUrl
|
|
111
|
+
const webhook = new IncomingWebhook(url)
|
|
112
|
+
let slackBlocks = []
|
|
113
|
+
slackBlocks.push({
|
|
114
|
+
type: 'header',
|
|
115
|
+
text: {
|
|
116
|
+
type: 'plain_text',
|
|
117
|
+
text: 'Testing Toolkit Report',
|
|
118
|
+
emoji: true
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
slackBlocks = slackBlocks.concat(generateSlackBlocks(progress))
|
|
122
|
+
if (reportURL) {
|
|
123
|
+
slackBlocks.push({
|
|
124
|
+
type: 'section',
|
|
125
|
+
text: {
|
|
126
|
+
type: 'mrkdwn',
|
|
127
|
+
text: '<' + reportURL + '|View Report>'
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
slackBlocks.push({
|
|
132
|
+
type: 'divider'
|
|
133
|
+
})
|
|
134
|
+
try {
|
|
135
|
+
// console.log(JSON.stringify(slackBlocks, null, 2))
|
|
136
|
+
await webhook.send({
|
|
137
|
+
text: 'Test Report',
|
|
138
|
+
blocks: slackBlocks
|
|
139
|
+
})
|
|
140
|
+
console.log('Slack notification sent.')
|
|
141
|
+
} catch (err) {
|
|
142
|
+
console.log('ERROR: Sending slack notification failed. ', err.message)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
sendSlackNotification
|
|
149
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
const logger = require('../utils/logger')
|
|
25
|
+
|
|
26
|
+
const handleIncomingProgress = (progress) => {
|
|
27
|
+
logger.monitoring(progress)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
handleIncomingProgress
|
|
32
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
const axios = require('axios').default
|
|
25
|
+
const report = require('../utils/report')
|
|
26
|
+
const logger = require('../utils/logger')
|
|
27
|
+
const fStr = require('node-strings')
|
|
28
|
+
const fs = require('fs')
|
|
29
|
+
const { promisify } = require('util')
|
|
30
|
+
const objectStore = require('../objectStore')
|
|
31
|
+
const slackBroadcast = require('../extras/slack-broadcast')
|
|
32
|
+
const TemplateGenerator = require('../utils/templateGenerator')
|
|
33
|
+
const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib')
|
|
34
|
+
|
|
35
|
+
const totalProgress = {
|
|
36
|
+
totalTestCases: 0,
|
|
37
|
+
totalRequests: 0,
|
|
38
|
+
totalAssertions: 0,
|
|
39
|
+
passedAssertions: 0,
|
|
40
|
+
skippedAssertions: 0,
|
|
41
|
+
failedAssertions: 0
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const updateTotalProgressCounts = (progress) => {
|
|
45
|
+
if (progress.requestSent && progress.requestSent.tests && progress.requestSent.tests.assertions) {
|
|
46
|
+
progress.requestSent.tests.assertions.forEach(assertion => {
|
|
47
|
+
if (progress.testResult.results[assertion.id].status === 'SUCCESS') {
|
|
48
|
+
totalProgress.passedAssertions++
|
|
49
|
+
} else if (progress.testResult.results[assertion.id].status === 'SKIPPED') {
|
|
50
|
+
totalProgress.skippedAssertions++
|
|
51
|
+
} else {
|
|
52
|
+
totalProgress.failedAssertions++
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const printTotalProgressCounts = () => {
|
|
59
|
+
const progressStr = '[ ' + fStr.green(totalProgress.passedAssertions + ' passed, ') + fStr.yellow(totalProgress.skippedAssertions + ' skipped, ') + fStr.red(totalProgress.failedAssertions + ' failed') + ' of ' + totalProgress.totalAssertions + ' ]'
|
|
60
|
+
process.stdout.write(progressStr)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const printProgress = (progress) => {
|
|
64
|
+
const config = objectStore.get('config')
|
|
65
|
+
switch (config.logLevel) {
|
|
66
|
+
// Only Errors
|
|
67
|
+
case '1':
|
|
68
|
+
{
|
|
69
|
+
printTotalProgressCounts()
|
|
70
|
+
let failedAssertions = ''
|
|
71
|
+
if (progress.requestSent && progress.requestSent.tests && progress.requestSent.tests.assertions) {
|
|
72
|
+
progress.requestSent.tests.assertions.forEach(assertion => {
|
|
73
|
+
if (progress.testResult.results[assertion.id].status !== 'SUCCESS') {
|
|
74
|
+
failedAssertions += '\t' + fStr.red('[ ' + progress.testResult.results[assertion.id].status + ' ]') + '\t' + fStr.red(assertion.description) + '\n'
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
console.log('\n ' + fStr.blue(progress.testCaseName + ' -> ' + progress.requestSent.description))
|
|
79
|
+
if (failedAssertions) {
|
|
80
|
+
console.log(failedAssertions)
|
|
81
|
+
} else {
|
|
82
|
+
console.log()
|
|
83
|
+
}
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
// All assertions
|
|
87
|
+
case '2':
|
|
88
|
+
{
|
|
89
|
+
printTotalProgressCounts()
|
|
90
|
+
console.log('\n ' + fStr.cyan(progress.testCaseName + ' -> ' + progress.requestSent.description))
|
|
91
|
+
if (progress.status === 'SKIPPED') {
|
|
92
|
+
console.log(' ' + fStr.yellow('(Request Skipped)'))
|
|
93
|
+
}
|
|
94
|
+
if (progress.requestSent && progress.requestSent.tests && progress.requestSent.tests.assertions) {
|
|
95
|
+
progress.requestSent.tests.assertions.forEach(assertion => {
|
|
96
|
+
if (progress.testResult.results[assertion.id].status === 'SUCCESS') {
|
|
97
|
+
console.log('\t' + fStr.green('[ ' + progress.testResult.results[assertion.id].status + ' ]') + '\t' + fStr.green(assertion.description))
|
|
98
|
+
} else if (progress.testResult.results[assertion.id].status === 'SKIPPED') {
|
|
99
|
+
console.log('\t' + fStr.yellow('[ ' + progress.testResult.results[assertion.id].status + ' ]') + '\t' + fStr.yellow(assertion.description))
|
|
100
|
+
} else {
|
|
101
|
+
console.log('\t' + fStr.red('[ ' + progress.testResult.results[assertion.id].status + ' ]') + '\t' + fStr.red(assertion.description))
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
// Only Requests and test counts
|
|
108
|
+
default:
|
|
109
|
+
printTotalProgressCounts()
|
|
110
|
+
console.log('\t' + fStr.blue(progress.testCaseName + ' -> ' + progress.requestSent?.description))
|
|
111
|
+
break
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const sendTemplate = async (sessionId) => {
|
|
116
|
+
const config = objectStore.get('config')
|
|
117
|
+
try {
|
|
118
|
+
const readFileAsync = promisify(fs.readFile)
|
|
119
|
+
|
|
120
|
+
// Calculate the outbound request ID based on sessionId for catching progress notifications
|
|
121
|
+
const traceIdPrefix = TraceHeaderUtils.getTraceIdPrefix()
|
|
122
|
+
const currentEndToEndId = TraceHeaderUtils.generateEndToEndId()
|
|
123
|
+
const outboundRequestID = traceIdPrefix + sessionId + currentEndToEndId
|
|
124
|
+
|
|
125
|
+
const inputFiles = config.inputFiles.split(',')
|
|
126
|
+
const selectedLabels = config.labels ? config.labels.split(',') : []
|
|
127
|
+
const template = await TemplateGenerator.generateTemplate(inputFiles, selectedLabels)
|
|
128
|
+
template.inputValues = JSON.parse(await readFileAsync(config.environmentFile, 'utf8')).inputValues
|
|
129
|
+
|
|
130
|
+
template.test_cases.forEach(testCase => {
|
|
131
|
+
totalProgress.totalTestCases++
|
|
132
|
+
if (testCase.requests) {
|
|
133
|
+
totalProgress.totalRequests += testCase.requests.length
|
|
134
|
+
}
|
|
135
|
+
testCase.requests.forEach(request => {
|
|
136
|
+
if (request.tests && request.tests.assertions) {
|
|
137
|
+
totalProgress.totalAssertions += request.tests.assertions.length
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
testCase.breakOnError = (config.breakRunOnError === 'true')
|
|
141
|
+
})
|
|
142
|
+
await axios.post(`${config.baseURL}/api/outbound/template/` + outboundRequestID, template, { headers: { 'Content-Type': 'application/json' } })
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.log(err)
|
|
145
|
+
process.exit(1)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const handleIncomingProgress = async (progress) => {
|
|
150
|
+
if (progress.status === 'FINISHED') {
|
|
151
|
+
let passed
|
|
152
|
+
try {
|
|
153
|
+
passed = logger.outbound(progress.totalResult)
|
|
154
|
+
const resultReport = await report.outbound(progress.totalResult)
|
|
155
|
+
await slackBroadcast.sendSlackNotification(progress.totalResult, resultReport.uploadedReportURL)
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.log(err)
|
|
158
|
+
passed = false
|
|
159
|
+
}
|
|
160
|
+
if (passed) {
|
|
161
|
+
console.log(fStr.green('Terminate with exit code 0'))
|
|
162
|
+
process.exit(0)
|
|
163
|
+
} else {
|
|
164
|
+
console.log(fStr.red('Terminate with exit code 1'))
|
|
165
|
+
process.exit(1)
|
|
166
|
+
}
|
|
167
|
+
} else if (progress.status === 'TERMINATED') {
|
|
168
|
+
console.log(fStr.red('Terminate with exit code 1'))
|
|
169
|
+
process.exit(1)
|
|
170
|
+
} else {
|
|
171
|
+
updateTotalProgressCounts(progress)
|
|
172
|
+
printProgress(progress)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
sendTemplate,
|
|
178
|
+
handleIncomingProgress
|
|
179
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
|
|
25
|
+
const report = require('../utils/report')
|
|
26
|
+
const fStr = require('node-strings')
|
|
27
|
+
const utils = require('../utils/file-utils.js')
|
|
28
|
+
const objectStore = require('../objectStore')
|
|
29
|
+
const templateGenerator = require('../utils/templateGenerator')
|
|
30
|
+
|
|
31
|
+
const download = async () => {
|
|
32
|
+
const config = objectStore.get('config')
|
|
33
|
+
try {
|
|
34
|
+
const inputFiles = config.inputFiles.split(',')
|
|
35
|
+
const selectedLabels = config.labels ? config.labels.split(',') : null
|
|
36
|
+
const template = await templateGenerator.generateTemplate(inputFiles, selectedLabels)
|
|
37
|
+
if (config.environmentFile) {
|
|
38
|
+
const environmentFileContent = await utils.readFileAsync(config.environmentFile, 'utf8')
|
|
39
|
+
template.inputValues = JSON.parse(environmentFileContent).inputValues
|
|
40
|
+
}
|
|
41
|
+
await report.testcaseDefinition(template)
|
|
42
|
+
console.log(fStr.green('Terminate with exit code 0'))
|
|
43
|
+
process.exit(0)
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.log(err)
|
|
46
|
+
console.log(fStr.red('Terminate with exit code 1'))
|
|
47
|
+
process.exit(1)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
download
|
|
53
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
|
|
25
|
+
const storedObject = {
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const set = (key, value) => {
|
|
29
|
+
storedObject[key] = { ...value }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const get = (key) => {
|
|
33
|
+
return { ...storedObject[key] }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
set,
|
|
38
|
+
get
|
|
39
|
+
}
|
package/src/router.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
const fs = require('fs')
|
|
25
|
+
const _ = require('lodash')
|
|
26
|
+
const objectStore = require('./objectStore')
|
|
27
|
+
const { TraceHeaderUtils } = require('@mojaloop/ml-testing-toolkit-shared-lib')
|
|
28
|
+
|
|
29
|
+
const TESTS_EXECUTION_TIMEOUT = 1000 * 60 * 15 // 15min timout
|
|
30
|
+
|
|
31
|
+
const cli = (commander) => {
|
|
32
|
+
const configFile = {
|
|
33
|
+
mode: 'outbound',
|
|
34
|
+
reportFormat: 'json',
|
|
35
|
+
baseURL: 'http://localhost:5050',
|
|
36
|
+
logLevel: '0',
|
|
37
|
+
reportAutoFilenameEnable: false,
|
|
38
|
+
breakRunOnError: false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (fs.existsSync(commander.config)) {
|
|
42
|
+
const newConfig = JSON.parse(fs.readFileSync(commander.config, 'utf8'))
|
|
43
|
+
_.merge(configFile, newConfig)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const config = {
|
|
47
|
+
mode: commander.mode || configFile.mode,
|
|
48
|
+
inputFiles: commander.inputFiles,
|
|
49
|
+
logLevel: commander.logLevel || configFile.logLevel,
|
|
50
|
+
breakRunOnError: commander.breakRunOnError || configFile.breakRunOnError,
|
|
51
|
+
environmentFile: commander.environmentFile,
|
|
52
|
+
reportFormat: commander.reportFormat || configFile.reportFormat,
|
|
53
|
+
reportAutoFilenameEnable: commander.reportAutoFilenameEnable === 'true' || configFile.reportAutoFilenameEnable === true,
|
|
54
|
+
reportTarget: commander.reportTarget || configFile.reportTarget,
|
|
55
|
+
slackWebhookUrl: commander.slackWebhookUrl || configFile.slackWebhookUrl,
|
|
56
|
+
slackPassedImage: configFile.slackPassedImage,
|
|
57
|
+
slackFailedImage: configFile.slackFailedImage,
|
|
58
|
+
baseURL: commander.baseUrl || configFile.baseURL,
|
|
59
|
+
extraSummaryInformation: commander.extraSummaryInformation || configFile.extraSummaryInformation,
|
|
60
|
+
labels: commander.labels || configFile.labels
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
objectStore.set('config', config)
|
|
64
|
+
|
|
65
|
+
switch (config.mode) {
|
|
66
|
+
case 'monitoring':
|
|
67
|
+
require('./utils/listeners').monitoring()
|
|
68
|
+
break
|
|
69
|
+
case 'outbound':
|
|
70
|
+
if (config.inputFiles) {
|
|
71
|
+
if (config.environmentFile) {
|
|
72
|
+
// Generate a session ID
|
|
73
|
+
const sessionId = TraceHeaderUtils.generateSessionId()
|
|
74
|
+
require('./utils/listeners').outbound(sessionId)
|
|
75
|
+
require('./modes/outbound').sendTemplate(sessionId)
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
console.log('Tests execution timed out....')
|
|
78
|
+
process.exit(1)
|
|
79
|
+
}, TESTS_EXECUTION_TIMEOUT)
|
|
80
|
+
} else {
|
|
81
|
+
console.log('error: required option \'-e, --environment-file <environmentFile>\' not specified')
|
|
82
|
+
process.exit(1)
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
console.log('error: required option \'-i, --input-files <inputFiles>\' not specified')
|
|
86
|
+
process.exit(1)
|
|
87
|
+
}
|
|
88
|
+
break
|
|
89
|
+
case 'testcaseDefinitionReport':
|
|
90
|
+
if (config.inputFiles) {
|
|
91
|
+
if (!commander.reportFormat) {
|
|
92
|
+
config.reportFormat = 'printhtml'
|
|
93
|
+
objectStore.set('config', config)
|
|
94
|
+
}
|
|
95
|
+
require('./modes/testcaseDefinitionReport').download()
|
|
96
|
+
} else {
|
|
97
|
+
console.log('error: required option \'-i, --input-files <inputFiles>\' not specified')
|
|
98
|
+
process.exit(1)
|
|
99
|
+
}
|
|
100
|
+
break
|
|
101
|
+
default:
|
|
102
|
+
console.log('Mode is not supported')
|
|
103
|
+
console.log('Terminate with exit code 1')
|
|
104
|
+
process.exit(1)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = {
|
|
109
|
+
cli
|
|
110
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mode": "outbound",
|
|
3
|
+
"logLevel": "2",
|
|
4
|
+
"reportFormat": "html",
|
|
5
|
+
"baseURL": "http://localhost:5050",
|
|
6
|
+
"reportTarget": "s3://qa-results/ttk-tests/reports/asdf.html",
|
|
7
|
+
"reportAutoFilenameEnable": true,
|
|
8
|
+
"slackWebhookUrl": "https://hooks.slack.com/services/some-ids-here",
|
|
9
|
+
"slackPassedImage": "https://passed-image-url/file.png",
|
|
10
|
+
"slackFailedImage": "https://failed-image-url/file.png"
|
|
11
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
|
|
25
|
+
const fs = require('fs')
|
|
26
|
+
const mv = require('mv')
|
|
27
|
+
const { files } = require('node-dir')
|
|
28
|
+
const { promisify } = require('util')
|
|
29
|
+
const readFileAsync = promisify(fs.readFile)
|
|
30
|
+
const writeFileAsync = promisify(fs.writeFile)
|
|
31
|
+
const accessFileAsync = promisify(fs.access)
|
|
32
|
+
const readDirAsync = promisify(fs.readdir)
|
|
33
|
+
const deleteFileAsync = promisify(fs.unlink)
|
|
34
|
+
const renameFileAsync = promisify(fs.rename)
|
|
35
|
+
const makeDirectoryAsync = promisify(fs.mkdir)
|
|
36
|
+
const fileStatAsync = promisify(fs.stat)
|
|
37
|
+
const readRecursiveAsync = promisify(files)
|
|
38
|
+
const rmdirAsync = promisify(fs.rmdir)
|
|
39
|
+
const mvAsync = promisify(mv)
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
readFileAsync,
|
|
43
|
+
writeFileAsync,
|
|
44
|
+
accessFileAsync,
|
|
45
|
+
readDirAsync,
|
|
46
|
+
deleteFileAsync,
|
|
47
|
+
renameFileAsync,
|
|
48
|
+
makeDirectoryAsync,
|
|
49
|
+
fileStatAsync,
|
|
50
|
+
readRecursiveAsync,
|
|
51
|
+
rmdirAsync,
|
|
52
|
+
mvAsync
|
|
53
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
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
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
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.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
|
|
20
|
+
* ModusBox
|
|
21
|
+
* Georgi Logodazhki <georgi.logodazhki@modusbox.com> (Original Author)
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
const socketIOClient = require('socket.io-client')
|
|
25
|
+
const outboundMode = require('../modes/outbound')
|
|
26
|
+
const monitoringMode = require('../modes/monitoring')
|
|
27
|
+
const objectStore = require('../objectStore')
|
|
28
|
+
|
|
29
|
+
const outbound = (sessionId) => {
|
|
30
|
+
const config = objectStore.get('config')
|
|
31
|
+
const socket = socketIOClient(config.baseURL)
|
|
32
|
+
socket.on('outboundProgress/' + sessionId, outboundMode.handleIncomingProgress)
|
|
33
|
+
console.log(`Listening on ${config.baseURL} outboundProgress events...`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const monitoring = () => {
|
|
37
|
+
const config = objectStore.get('config')
|
|
38
|
+
const socket = socketIOClient(config.baseURL)
|
|
39
|
+
socket.on('newLog', monitoringMode.handleIncomingProgress)
|
|
40
|
+
console.log(`Listening on ${config.baseURL} newLog events...`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
outbound,
|
|
45
|
+
monitoring
|
|
46
|
+
}
|