mocha-distributed 0.9.1 → 0.9.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/README.md +18 -5
- package/docker-compose.yml +9 -0
- package/index.js +16 -3
- package/list-tests-from-redis.js +85 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -148,16 +148,29 @@ You will see something like this on each of the items of the list:
|
|
|
148
148
|
"type": "test",
|
|
149
149
|
"title": "test-1.1-async",
|
|
150
150
|
"timedOut": false,
|
|
151
|
+
"startTime": 1642705594300,
|
|
152
|
+
"endTime": 1642705594802,
|
|
151
153
|
"duration": 502,
|
|
152
154
|
"file": "/home/psanchez/github/mocha-distributed/example/suite-1.js",
|
|
153
155
|
"state": "passed",
|
|
156
|
+
"failed": false,
|
|
154
157
|
"speed": "slow",
|
|
155
158
|
"err": 0
|
|
156
|
-
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
157
161
|
|
|
158
162
|
The JSON formatting will differ since it is saved in a single line.
|
|
159
163
|
|
|
160
|
-
|
|
164
|
+
Keep in mind that:
|
|
165
|
+
|
|
166
|
+
* Duration and start/end times are in milliseconds.
|
|
167
|
+
* Some fields are duplicated in a way, like "state" and "failed" by design
|
|
168
|
+
because sometimes is handy to have this when reading results back.
|
|
169
|
+
* You can access test_result, passed_count and failed_count in redis
|
|
170
|
+
* Skipped tests are never saved in redis by design, unfortunately
|
|
171
|
+
|
|
172
|
+
You might have a look at list-tests-from-redis.js for an example on how to
|
|
173
|
+
query redis and list all tests.
|
|
161
174
|
|
|
162
175
|
## Examples
|
|
163
176
|
|
|
@@ -243,9 +256,9 @@ or have been skipped will return 0.
|
|
|
243
256
|
If you use jenkins, bamboo or any other build system, make sure
|
|
244
257
|
one redis is installed somewhere and all runners can access to it.
|
|
245
258
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
259
|
+
Create as many processes, nodes, dockers, kubernetes pods as you wish,
|
|
260
|
+
but for each of the runners that you create, make sure each of them can connect
|
|
261
|
+
to the redis instance (e.g are in the same network).
|
|
249
262
|
|
|
250
263
|
You can use the project name and build ID or job id as the execution ID for
|
|
251
264
|
mocha-distributed. Use something unique among the builds of all your projects.
|
package/docker-compose.yml
CHANGED
|
@@ -7,6 +7,9 @@ services:
|
|
|
7
7
|
ports:
|
|
8
8
|
- 6379:6379
|
|
9
9
|
|
|
10
|
+
networks:
|
|
11
|
+
- mordor_gh_network
|
|
12
|
+
|
|
10
13
|
redis-commander:
|
|
11
14
|
image: rediscommander/redis-commander:latest
|
|
12
15
|
environment:
|
|
@@ -16,3 +19,9 @@ services:
|
|
|
16
19
|
depends_on:
|
|
17
20
|
- redis
|
|
18
21
|
|
|
22
|
+
networks:
|
|
23
|
+
- mordor_gh_network
|
|
24
|
+
|
|
25
|
+
networks:
|
|
26
|
+
mordor_gh_network:
|
|
27
|
+
external: true
|
package/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// -----------------------------------------------------------------------------
|
|
2
|
+
// Copyright (c) 2018 Pau Sanchez
|
|
3
|
+
//
|
|
4
|
+
// MIT Licensed
|
|
5
|
+
// -----------------------------------------------------------------------------
|
|
1
6
|
const redis = require("redis");
|
|
2
7
|
const crypto = require("crypto");
|
|
3
8
|
|
|
@@ -129,6 +134,7 @@ exports.mochaHooks = {
|
|
|
129
134
|
},
|
|
130
135
|
afterEach(done) {
|
|
131
136
|
const SKIPPED = "pending";
|
|
137
|
+
const FAILED = "failed";
|
|
132
138
|
|
|
133
139
|
// Save all data in redis in a way it can be retrieved and aggregated
|
|
134
140
|
// easily for all test by an external reporter
|
|
@@ -139,17 +145,24 @@ exports.mochaHooks = {
|
|
|
139
145
|
title: this.currentTest.title,
|
|
140
146
|
timedOut: this.currentTest.timedOut,
|
|
141
147
|
duration: this.currentTest.duration,
|
|
148
|
+
startTime: Date.now() - (this.currentTest.duration || 0),
|
|
149
|
+
endTime: Date.now(),
|
|
142
150
|
file: this.currentTest.file,
|
|
143
151
|
state: this.currentTest.state,
|
|
152
|
+
failed: this.currentTest.state === FAILED,
|
|
144
153
|
speed: this.currentTest.speed,
|
|
145
|
-
err: this.currentTest.err
|
|
154
|
+
err: this.currentTest.err || null,
|
|
146
155
|
};
|
|
147
156
|
|
|
148
|
-
// save as single line on purpose
|
|
157
|
+
// save results as single line on purpose
|
|
149
158
|
const key = `${g_testExecutionId}:test_result`;
|
|
150
159
|
g_redis.rPush(key, JSON.stringify(testResult));
|
|
151
160
|
g_redis.expire(key, g_expirationTime);
|
|
152
|
-
|
|
161
|
+
|
|
162
|
+
// increment passed_count/failed_count & set expiry time
|
|
163
|
+
const countKey = `${g_testExecutionId}:${this.currentTest.state}_count`
|
|
164
|
+
g_redis.incr(countKey);
|
|
165
|
+
g_redis.expire(countKey, g_expirationTime);
|
|
153
166
|
}
|
|
154
167
|
|
|
155
168
|
done();
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// -----------------------------------------------------------------------------
|
|
2
|
+
// Copyright (c) 2018 Pau Sanchez
|
|
3
|
+
//
|
|
4
|
+
// MIT Licensed
|
|
5
|
+
// -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
const redis = require("redis");
|
|
8
|
+
|
|
9
|
+
async function getTestResults(redisHost = 'localhost', redisPort = 6379) {
|
|
10
|
+
const allResults = []
|
|
11
|
+
try {
|
|
12
|
+
const redisClient = redis.createClient({
|
|
13
|
+
url: `redis://${redisHost}:${redisPort}/`
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
await redisClient.connect()
|
|
17
|
+
|
|
18
|
+
// get all potential test results keys
|
|
19
|
+
const keyResults = await redisClient.keys('*:test_result')
|
|
20
|
+
|
|
21
|
+
// we can get all in parallel
|
|
22
|
+
const parallelResults = []
|
|
23
|
+
for(const key of keyResults) {
|
|
24
|
+
const rawResultList = await redisClient.lRange(key, 0, -1)
|
|
25
|
+
|
|
26
|
+
let passed = 0
|
|
27
|
+
let failed = 0
|
|
28
|
+
let aggregatedDurationMs = 0
|
|
29
|
+
let firstStartTime = null
|
|
30
|
+
let lastEndTime = null
|
|
31
|
+
const jsonResultList = []
|
|
32
|
+
for (const rawResult of rawResultList) {
|
|
33
|
+
const jsonResult = JSON.parse(rawResult)
|
|
34
|
+
jsonResultList.push(jsonResult)
|
|
35
|
+
|
|
36
|
+
// compute some extra stuff
|
|
37
|
+
if (firstStartTime === null || jsonResult.startTime < firstStartTime) {
|
|
38
|
+
firstStartTime = jsonResult.startTime
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (lastEndTime === null || jsonResult.endTime > lastEndTime) {
|
|
42
|
+
lastEndTime = jsonResult.endTime
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
passed += (jsonResult.state === "passed")
|
|
46
|
+
failed += (jsonResult.state === "failed")
|
|
47
|
+
|
|
48
|
+
aggregatedDurationMs += (jsonResult.duration || 0)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// sort all jsonResultList by the full test route, because they will
|
|
52
|
+
// be visualized better
|
|
53
|
+
jsonResultList.sort((a, b) => (a.id.join('/') > b.id.join('/')) ? 1 : -1)
|
|
54
|
+
|
|
55
|
+
allResults.push({
|
|
56
|
+
key: key,
|
|
57
|
+
start_time : firstStartTime || 0,
|
|
58
|
+
end_time : lastEndTime || 0,
|
|
59
|
+
aggregated_duration: aggregatedDurationMs,
|
|
60
|
+
real_duration: (firstStartTime && lastEndTime) ? lastEndTime - firstStartTime : aggregatedDurationMs,
|
|
61
|
+
tests_passed : passed,
|
|
62
|
+
tests_failed : failed,
|
|
63
|
+
test_results : jsonResultList
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// sort results by startTime, most recent first
|
|
68
|
+
allResults.sort((a, b) => (a.start_time < b.start_time) ? 1 : -1)
|
|
69
|
+
|
|
70
|
+
await redisClient.quit()
|
|
71
|
+
return allResults
|
|
72
|
+
}
|
|
73
|
+
catch(e) {
|
|
74
|
+
console.error ("Test Error: ", e)
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
// -----------------------------------------------------------------------------
|
|
81
|
+
// Print results as JSON output
|
|
82
|
+
// -----------------------------------------------------------------------------
|
|
83
|
+
getTestResults().then( (results) => {
|
|
84
|
+
console.log (JSON.stringify(results, null, 2))
|
|
85
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mocha-distributed",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Run multiple mocha suites and tests in parallel, from different processes or different machines",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"author": "Pau Sanchez",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"redis": "^4.0.
|
|
30
|
+
"redis": "^4.0.2"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"chai": "^4.2.0",
|
|
34
|
-
"mocha": "^9.1.
|
|
34
|
+
"mocha": "^9.1.4"
|
|
35
35
|
}
|
|
36
36
|
}
|