loadtest 7.1.1 → 8.0.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/README.md +60 -42
- package/bin/loadtest.js +3 -2
- package/bin/tcp-performance.js +21 -0
- package/bin/testserver.js +28 -26
- package/doc/api.md +103 -52
- package/doc/tcp-sockets.md +569 -0
- package/lib/baseClient.js +3 -7
- package/lib/cluster.js +1 -1
- package/lib/httpClient.js +18 -43
- package/lib/latency.js +27 -27
- package/lib/loadtest.js +26 -69
- package/lib/options.js +5 -1
- package/lib/parser.js +167 -0
- package/lib/pool.js +106 -0
- package/lib/result.js +22 -14
- package/lib/tcpClient.js +198 -0
- package/lib/testserver.js +24 -7
- package/lib/websocket.js +5 -11
- package/package.json +3 -2
- package/test/all.js +5 -0
- package/test/body-generator.js +3 -3
- package/test/httpClient.js +3 -3
- package/test/integration.js +47 -12
- package/test/latency.js +29 -25
- package/test/loadtest.js +7 -7
- package/test/request-generator.js +3 -3
- package/test/result.js +1 -1
- package/test/tcpClient.js +23 -0
- package/test/websocket.js +3 -3
package/test/integration.js
CHANGED
|
@@ -3,9 +3,9 @@ import {execFile} from 'child_process'
|
|
|
3
3
|
import {join} from 'path'
|
|
4
4
|
import {loadTest, startServer} from '../index.js'
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const port = 10408;
|
|
7
7
|
const serverOptions = {
|
|
8
|
-
port
|
|
8
|
+
port,
|
|
9
9
|
quiet: true,
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ function testIntegration(callback) {
|
|
|
19
19
|
return callback(error);
|
|
20
20
|
}
|
|
21
21
|
const options = {
|
|
22
|
-
url:
|
|
22
|
+
url: `http://localhost:${port}`,
|
|
23
23
|
maxRequests: 100,
|
|
24
24
|
concurrency: 10,
|
|
25
25
|
method: 'POST',
|
|
@@ -52,7 +52,7 @@ function testIntegrationFile(callback) {
|
|
|
52
52
|
return callback(error);
|
|
53
53
|
}
|
|
54
54
|
execFile('node',
|
|
55
|
-
[join('./', 'bin', 'loadtest.js'), `http://localhost:${
|
|
55
|
+
[join('./', 'bin', 'loadtest.js'), `http://localhost:${port}/`,
|
|
56
56
|
'-n', '100', '--quiet'],
|
|
57
57
|
(error, stdout) => {
|
|
58
58
|
if (error) {
|
|
@@ -79,7 +79,7 @@ function testWSIntegration(callback) {
|
|
|
79
79
|
return callback(error);
|
|
80
80
|
}
|
|
81
81
|
const options = {
|
|
82
|
-
url:
|
|
82
|
+
url: `ws://localhost:${port}`,
|
|
83
83
|
maxRequests: 10,
|
|
84
84
|
concurrency: 10,
|
|
85
85
|
body: {
|
|
@@ -113,7 +113,7 @@ function testWSIntegration(callback) {
|
|
|
113
113
|
function testDelay(callback) {
|
|
114
114
|
const delay = 10;
|
|
115
115
|
const serverOptions = {
|
|
116
|
-
port:
|
|
116
|
+
port: port + 1,
|
|
117
117
|
delay,
|
|
118
118
|
quiet: true,
|
|
119
119
|
};
|
|
@@ -122,7 +122,7 @@ function testDelay(callback) {
|
|
|
122
122
|
return callback(error);
|
|
123
123
|
}
|
|
124
124
|
const options = {
|
|
125
|
-
url: 'http://localhost:' + (
|
|
125
|
+
url: 'http://localhost:' + (port + 1),
|
|
126
126
|
maxRequests: 10,
|
|
127
127
|
quiet: true,
|
|
128
128
|
};
|
|
@@ -145,7 +145,7 @@ function testDelay(callback) {
|
|
|
145
145
|
async function testPromise() {
|
|
146
146
|
const server = await startServer(serverOptions)
|
|
147
147
|
const options = {
|
|
148
|
-
url:
|
|
148
|
+
url: `http://localhost:${port}`,
|
|
149
149
|
maxRequests: 100,
|
|
150
150
|
concurrency: 10,
|
|
151
151
|
method: 'POST',
|
|
@@ -174,7 +174,7 @@ async function testIndexParam() {
|
|
|
174
174
|
}
|
|
175
175
|
const server = await startServer({logger, ...serverOptions})
|
|
176
176
|
const options = {
|
|
177
|
-
url: `http://localhost:${
|
|
177
|
+
url: `http://localhost:${port}/?param=index`,
|
|
178
178
|
maxRequests: 100,
|
|
179
179
|
concurrency: 10,
|
|
180
180
|
postBody: {
|
|
@@ -191,7 +191,7 @@ async function testStatusCallback() {
|
|
|
191
191
|
let calls = 0
|
|
192
192
|
const server = await startServer(serverOptions)
|
|
193
193
|
const options = {
|
|
194
|
-
url: `http://localhost:${
|
|
194
|
+
url: `http://localhost:${port}/`,
|
|
195
195
|
maxRequests: 100,
|
|
196
196
|
concurrency: 10,
|
|
197
197
|
postBody: {
|
|
@@ -203,18 +203,53 @@ async function testStatusCallback() {
|
|
|
203
203
|
calls += 1
|
|
204
204
|
}
|
|
205
205
|
};
|
|
206
|
-
await loadTest(options)
|
|
206
|
+
const result = await loadTest(options)
|
|
207
|
+
testing.assertEquals(result.totalRequests, 100, 'Should have 100 requests')
|
|
207
208
|
testing.assertEquals(calls, 100, 'Should have 100 calls')
|
|
208
209
|
await server.close()
|
|
209
210
|
}
|
|
210
211
|
|
|
212
|
+
async function testTcpClient() {
|
|
213
|
+
const server = await startServer(serverOptions)
|
|
214
|
+
const options = {
|
|
215
|
+
url: `http://localhost:${port}`,
|
|
216
|
+
maxRequests: 100,
|
|
217
|
+
method: 'POST',
|
|
218
|
+
body: {
|
|
219
|
+
hi: 'there',
|
|
220
|
+
},
|
|
221
|
+
quiet: true,
|
|
222
|
+
tcp: true,
|
|
223
|
+
};
|
|
224
|
+
const result = await loadTest(options)
|
|
225
|
+
await server.close()
|
|
226
|
+
return 'Test result: ' + JSON.stringify(result)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function testTcpNoServer() {
|
|
230
|
+
const options = {
|
|
231
|
+
url: `http://localhost:${port}`,
|
|
232
|
+
maxRequests: 100,
|
|
233
|
+
rps: 1000,
|
|
234
|
+
method: 'POST',
|
|
235
|
+
body: {
|
|
236
|
+
hi: 'there',
|
|
237
|
+
},
|
|
238
|
+
quiet: true,
|
|
239
|
+
tcp: true,
|
|
240
|
+
};
|
|
241
|
+
const result = await loadTest(options)
|
|
242
|
+
return 'Test result: ' + JSON.stringify(result)
|
|
243
|
+
}
|
|
244
|
+
|
|
211
245
|
/**
|
|
212
246
|
* Run all tests.
|
|
213
247
|
*/
|
|
214
248
|
export function test(callback) {
|
|
215
249
|
testing.run([
|
|
216
250
|
testIntegration, testIntegrationFile, testDelay, testWSIntegration,
|
|
217
|
-
testPromise, testIndexParam, testStatusCallback,
|
|
251
|
+
testPromise, testIndexParam, testStatusCallback, testTcpClient,
|
|
252
|
+
testTcpNoServer,
|
|
218
253
|
], 4000, callback);
|
|
219
254
|
}
|
|
220
255
|
|
package/test/latency.js
CHANGED
|
@@ -2,14 +2,16 @@ import testing from 'testing'
|
|
|
2
2
|
import {Latency} from '../lib/latency.js'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
const mockLoadTest = {running: true, checkStop: () => false, countClients: () => 0}
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Test latency ids.
|
|
7
9
|
*/
|
|
8
10
|
function testLatencyIds(callback) {
|
|
9
|
-
const latency = new Latency(
|
|
10
|
-
const firstId = latency.
|
|
11
|
+
const latency = new Latency(mockLoadTest);
|
|
12
|
+
const firstId = latency.begin();
|
|
11
13
|
testing.assert(firstId, 'Invalid first latency id %s', firstId, callback);
|
|
12
|
-
const secondId = latency.
|
|
14
|
+
const secondId = latency.begin();
|
|
13
15
|
testing.assert(secondId, 'Invalid second latency id', callback);
|
|
14
16
|
testing.assert(firstId != secondId, 'Repeated latency ids', callback);
|
|
15
17
|
testing.success(callback);
|
|
@@ -23,21 +25,21 @@ function testLatencyRequests(callback) {
|
|
|
23
25
|
maxRequests: 10,
|
|
24
26
|
};
|
|
25
27
|
const errorCode = '500';
|
|
26
|
-
const latency = new Latency(options,
|
|
27
|
-
testing.check(error, 'Could not compute latency', callback);
|
|
28
|
-
testing.assertEquals(result.totalRequests, 10, 'Invalid total requests', callback);
|
|
29
|
-
testing.assertEquals(result.totalErrors, 1, 'Invalid total errors', callback);
|
|
30
|
-
testing.assert(errorCode in result.errorCodes, 'Error code not found', callback);
|
|
31
|
-
testing.assertEquals(result.errorCodes[errorCode], 1, 'Should have one ' + errorCode, callback);
|
|
32
|
-
testing.success(callback);
|
|
33
|
-
});
|
|
34
|
-
let id;
|
|
28
|
+
const latency = new Latency({options, ...mockLoadTest})
|
|
35
29
|
for (let i = 0; i < 9; i++) {
|
|
36
|
-
id = latency.
|
|
30
|
+
const id = latency.begin();
|
|
37
31
|
latency.end(id);
|
|
38
32
|
}
|
|
39
|
-
id = latency.
|
|
33
|
+
const id = latency.begin();
|
|
40
34
|
latency.end(id, errorCode);
|
|
35
|
+
testing.assert(latency.shouldStop(), 'Should stop now', callback);
|
|
36
|
+
latency.stop()
|
|
37
|
+
const result = latency.getResult()
|
|
38
|
+
testing.assertEquals(result.totalRequests, 10, 'Invalid total requests', callback);
|
|
39
|
+
testing.assertEquals(result.totalErrors, 1, 'Invalid total errors', callback);
|
|
40
|
+
testing.assert(errorCode in result.errorCodes, 'Error code not found', callback);
|
|
41
|
+
testing.assertEquals(result.errorCodes[errorCode], 1, 'Should have one ' + errorCode, callback);
|
|
42
|
+
testing.success(callback);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
/**
|
|
@@ -47,24 +49,26 @@ function testLatencyPercentiles(callback) {
|
|
|
47
49
|
const options = {
|
|
48
50
|
maxRequests: 10
|
|
49
51
|
};
|
|
50
|
-
const latency = new Latency(options,
|
|
51
|
-
testing.check(error, 'Error while testing latency percentiles', callback);
|
|
52
|
-
const percentiles = latency.getResult().percentiles;
|
|
53
|
-
|
|
54
|
-
Object.keys(percentiles).forEach(percentile => {
|
|
55
|
-
testing.assert(percentiles[percentile] !== false, 'Empty percentile for %s', percentile, callback);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
testing.success(percentiles, callback);
|
|
59
|
-
});
|
|
52
|
+
const latency = new Latency({options, ...mockLoadTest})
|
|
60
53
|
for (let ms = 1; ms <= 10; ms++) {
|
|
61
54
|
(function() {
|
|
62
|
-
const id = latency.
|
|
55
|
+
const id = latency.begin();
|
|
63
56
|
setTimeout(() => {
|
|
64
57
|
latency.end(id);
|
|
65
58
|
}, ms);
|
|
66
59
|
})();
|
|
67
60
|
}
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
testing.assert(latency.shouldStop(), 'Should stop now', callback);
|
|
63
|
+
latency.stop()
|
|
64
|
+
const percentiles = latency.getResult().percentiles;
|
|
65
|
+
|
|
66
|
+
Object.keys(percentiles).forEach(percentile => {
|
|
67
|
+
testing.assert(percentiles[percentile] !== false, 'Empty percentile for %s', percentile, callback);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
testing.success(percentiles, callback);
|
|
71
|
+
}, 20)
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
/**
|
package/test/loadtest.js
CHANGED
|
@@ -4,7 +4,7 @@ import {loadTest} from '../lib/loadtest.js'
|
|
|
4
4
|
|
|
5
5
|
function testMaxSeconds(callback) {
|
|
6
6
|
const options = {
|
|
7
|
-
url: 'http://localhost:
|
|
7
|
+
url: 'http://localhost:7358/',
|
|
8
8
|
maxSeconds: 0.1,
|
|
9
9
|
concurrency: 1,
|
|
10
10
|
quiet: true,
|
|
@@ -14,7 +14,7 @@ function testMaxSeconds(callback) {
|
|
|
14
14
|
|
|
15
15
|
function testWSEcho(callback) {
|
|
16
16
|
const options = {
|
|
17
|
-
url: 'ws://localhost:
|
|
17
|
+
url: 'ws://localhost:7358/',
|
|
18
18
|
maxSeconds: 0.1,
|
|
19
19
|
concurrency: 1,
|
|
20
20
|
quiet: true,
|
|
@@ -24,7 +24,7 @@ function testWSEcho(callback) {
|
|
|
24
24
|
|
|
25
25
|
function testIndexParam(callback) {
|
|
26
26
|
const options = {
|
|
27
|
-
url: 'http://localhost:
|
|
27
|
+
url: 'http://localhost:7358/replace',
|
|
28
28
|
concurrency:1,
|
|
29
29
|
maxSeconds: 0.1,
|
|
30
30
|
indexParam: "replace",
|
|
@@ -35,7 +35,7 @@ function testIndexParam(callback) {
|
|
|
35
35
|
|
|
36
36
|
function testIndexParamWithBody(callback) {
|
|
37
37
|
const options = {
|
|
38
|
-
url: 'http://localhost:
|
|
38
|
+
url: 'http://localhost:7358/replace',
|
|
39
39
|
concurrency:1,
|
|
40
40
|
maxSeconds: 0.1,
|
|
41
41
|
indexParam: "replace",
|
|
@@ -47,7 +47,7 @@ function testIndexParamWithBody(callback) {
|
|
|
47
47
|
|
|
48
48
|
function testIndexParamWithCallback(callback) {
|
|
49
49
|
const options = {
|
|
50
|
-
url: 'http://localhost:
|
|
50
|
+
url: 'http://localhost:7358/replace',
|
|
51
51
|
concurrency:1,
|
|
52
52
|
maxSeconds: 0.1,
|
|
53
53
|
indexParam: "replace",
|
|
@@ -62,7 +62,7 @@ function testIndexParamWithCallback(callback) {
|
|
|
62
62
|
|
|
63
63
|
function testIndexParamWithCallbackAndBody(callback) {
|
|
64
64
|
const options = {
|
|
65
|
-
url: 'http://localhost:
|
|
65
|
+
url: 'http://localhost:7358/replace',
|
|
66
66
|
concurrency:1,
|
|
67
67
|
maxSeconds: 0.1,
|
|
68
68
|
body: '{"id": "replace"}',
|
|
@@ -95,7 +95,7 @@ function testError(callback) {
|
|
|
95
95
|
*/
|
|
96
96
|
function testKeepAlive(callback) {
|
|
97
97
|
const options = {
|
|
98
|
-
url: 'http://localhost:
|
|
98
|
+
url: 'http://localhost:7358/',
|
|
99
99
|
maxSeconds: 0.1,
|
|
100
100
|
concurrency: 1,
|
|
101
101
|
quiet: true,
|
|
@@ -2,16 +2,16 @@ import testing from 'testing'
|
|
|
2
2
|
import {loadTest} from '../lib/loadtest.js'
|
|
3
3
|
import {startServer} from '../lib/testserver.js'
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const port = 10453;
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
function testRequestGenerator(callback) {
|
|
9
|
-
const server = startServer({port
|
|
9
|
+
const server = startServer({port, quiet: true}, error => {
|
|
10
10
|
if (error) {
|
|
11
11
|
return callback('Could not start test server');
|
|
12
12
|
}
|
|
13
13
|
const options = {
|
|
14
|
-
url:
|
|
14
|
+
url: `http://localhost:${port}`,
|
|
15
15
|
method: 'POST',
|
|
16
16
|
requestsPerSecond: 1000,
|
|
17
17
|
maxRequests: 100,
|
package/test/result.js
CHANGED
|
@@ -23,7 +23,7 @@ function testCombineResults(callback) {
|
|
|
23
23
|
totalRequests: 330,
|
|
24
24
|
totalErrors: 10,
|
|
25
25
|
startTimeMs: 1000 + index * 1000,
|
|
26
|
-
|
|
26
|
+
stopTimeMs: 1000 + index * 2000,
|
|
27
27
|
accumulatedMs: 5000,
|
|
28
28
|
maxLatencyMs: 350 + index,
|
|
29
29
|
minLatencyMs: 2 + index,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import testing from 'testing'
|
|
2
|
+
import {TcpClient} from '../lib/tcpClient.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function testHttpClient(callback) {
|
|
6
|
+
const options = {
|
|
7
|
+
url: 'http://localhost:7358/',
|
|
8
|
+
maxSeconds: 0.1,
|
|
9
|
+
concurrency: 1,
|
|
10
|
+
};
|
|
11
|
+
const client = new TcpClient({options});
|
|
12
|
+
client.stop()
|
|
13
|
+
testing.success(callback);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run all tests.
|
|
19
|
+
*/
|
|
20
|
+
export function test(callback) {
|
|
21
|
+
testing.run([testHttpClient], callback)
|
|
22
|
+
}
|
|
23
|
+
|
package/test/websocket.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import testing from 'testing'
|
|
2
|
-
import {
|
|
2
|
+
import {WebsocketClient} from '../lib/websocket.js'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
function testWebsocketClient(callback) {
|
|
6
6
|
const options = {
|
|
7
|
-
url: 'ws://localhost:
|
|
7
|
+
url: 'ws://localhost:7358/',
|
|
8
8
|
maxSeconds: 0.1,
|
|
9
9
|
concurrency: 1,
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
new WebsocketClient({options});
|
|
12
12
|
testing.success(callback);
|
|
13
13
|
}
|
|
14
14
|
|