loadtest 5.1.2 → 6.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/.eslintrc +1 -1
- package/README.md +80 -45
- package/bin/loadtest.js +26 -154
- package/bin/testserver.js +5 -12
- package/index.js +6 -12
- package/lib/baseClient.js +5 -22
- package/lib/config.js +9 -24
- package/lib/headers.js +3 -64
- package/lib/hrtimer.js +2 -55
- package/lib/httpClient.js +19 -64
- package/lib/latency.js +25 -147
- package/lib/loadtest.js +19 -150
- package/lib/options.js +156 -0
- package/lib/testserver.js +15 -65
- package/lib/websocket.js +8 -54
- package/package.json +8 -8
- package/sample/post-file.js +13 -0
- package/sample/request-generator.js +2 -4
- package/test/all.js +33 -0
- package/test/body-generator.js +41 -0
- package/test/headers.js +51 -0
- package/test/hrtimer.js +39 -0
- package/test/httpClient.js +22 -0
- package/{lib → test}/integration.js +13 -35
- package/test/latency.js +81 -0
- package/test/loadtest.js +87 -0
- package/{lib → test}/request-generator.js +9 -21
- package/test/testserver.js +24 -0
- package/test/websocket.js +23 -0
- package/test.js +0 -36
- /package/{test → sample}/.loadtestrc +0 -0
package/.eslintrc
CHANGED
package/README.md
CHANGED
|
@@ -33,8 +33,9 @@ For access to the API just add package `loadtest` to your `package.json` devDepe
|
|
|
33
33
|
|
|
34
34
|
### Compatibility
|
|
35
35
|
|
|
36
|
-
Versions
|
|
36
|
+
Versions 6 and later should be used at least with Node.js v16 or later:
|
|
37
37
|
|
|
38
|
+
* Node.js v16 or later: ^6.0.0
|
|
38
39
|
* Node.js v10 or later: ^5.0.0
|
|
39
40
|
* Node.js v8 or later: 4.x.y.
|
|
40
41
|
* Node.js v6 or earlier: ^3.1.0.
|
|
@@ -189,44 +190,46 @@ It required `-m` and `-T 'application/x-www-form-urlencoded'`
|
|
|
189
190
|
Send the data contained in the given file in the POST body.
|
|
190
191
|
Remember to set `-T` to the correct content-type.
|
|
191
192
|
|
|
192
|
-
If `POST-file` has `.js` extension it will be `
|
|
193
|
-
should `export` a
|
|
193
|
+
If `POST-file` has `.js` extension it will be `import`ed. It should be a valid node module and it
|
|
194
|
+
should `export` a default function, which is invoked with an automatically generated request identifier
|
|
194
195
|
to provide the body of each request.
|
|
195
196
|
This is useful if you want to generate request bodies dynamically and vary them for each request.
|
|
196
197
|
|
|
197
198
|
Example:
|
|
198
199
|
|
|
199
200
|
```javascript
|
|
200
|
-
|
|
201
|
+
export default function request(requestId) {
|
|
201
202
|
// this object will be serialized to JSON and sent in the body of the request
|
|
202
203
|
return {
|
|
203
204
|
key: 'value',
|
|
204
205
|
requestId: requestId
|
|
205
|
-
}
|
|
206
|
-
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
207
208
|
```
|
|
208
209
|
|
|
210
|
+
See sample file in `sample/post-file.js`, and test in `test/body-generator.js`.
|
|
211
|
+
|
|
209
212
|
#### `-u PUT-file`
|
|
210
213
|
|
|
211
214
|
Send the data contained in the given file as a PUT request.
|
|
212
215
|
Remember to set `-T` to the correct content-type.
|
|
213
216
|
|
|
214
|
-
If `PUT-file` has `.js` extension it will be `
|
|
215
|
-
should `export` a
|
|
217
|
+
If `PUT-file` has `.js` extension it will be `import`ed. It should be a valid node module and it
|
|
218
|
+
should `export` a default function, which is invoked with an automatically generated request identifier
|
|
216
219
|
to provide the body of each request.
|
|
217
220
|
This is useful if you want to generate request bodies dynamically and vary them for each request.
|
|
218
|
-
For
|
|
221
|
+
For examples see above for `-p`.
|
|
219
222
|
|
|
220
223
|
#### `-a PATCH-file`
|
|
221
224
|
|
|
222
225
|
Send the data contained in the given file as a PATCH request.
|
|
223
226
|
Remember to set `-T` to the correct content-type.
|
|
224
227
|
|
|
225
|
-
If `PATCH-file` has `.js` extension it will be `
|
|
226
|
-
should `export` a
|
|
228
|
+
If `PATCH-file` has `.js` extension it will be `import`ed. It should be a valid node module and it
|
|
229
|
+
should `export` a default function, which is invoked with an automatically generated request identifier
|
|
227
230
|
to provide the body of each request.
|
|
228
231
|
This is useful if you want to generate request bodies dynamically and vary them for each request.
|
|
229
|
-
For
|
|
232
|
+
For examples see above for `-p`.
|
|
230
233
|
|
|
231
234
|
##### `-r`
|
|
232
235
|
|
|
@@ -306,14 +309,18 @@ Open connections using keep-alive.
|
|
|
306
309
|
|
|
307
310
|
Note: instead of using the default agent, this option is now an alias for `-k`.
|
|
308
311
|
|
|
309
|
-
#### `--quiet`
|
|
312
|
+
#### `--quiet` (deprecated)
|
|
310
313
|
|
|
311
314
|
Do not show any messages.
|
|
312
315
|
|
|
313
|
-
|
|
316
|
+
Note: deprecated in version 6+, shows a warning.
|
|
317
|
+
|
|
318
|
+
#### `--debug` (deprecated)
|
|
314
319
|
|
|
315
320
|
Show debug messages.
|
|
316
321
|
|
|
322
|
+
Note: deprecated in version 6+, shows a warning.
|
|
323
|
+
|
|
317
324
|
#### `--insecure`
|
|
318
325
|
|
|
319
326
|
Allow invalid and self-signed certificates over https.
|
|
@@ -473,19 +480,18 @@ thus allowing you to load test your application in your own tests.
|
|
|
473
480
|
To run a load test, just call the exported function `loadTest()` with a set of options and an optional callback:
|
|
474
481
|
|
|
475
482
|
```javascript
|
|
476
|
-
|
|
483
|
+
import {loadTest} from 'loadtest'
|
|
484
|
+
|
|
477
485
|
const options = {
|
|
478
486
|
url: 'http://localhost:8000',
|
|
479
487
|
maxRequests: 1000,
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
{
|
|
483
|
-
|
|
484
|
-
{
|
|
485
|
-
return console.error('Got an error: %s', error);
|
|
488
|
+
}
|
|
489
|
+
loadTest(options, function(error, result) {
|
|
490
|
+
if (error) {
|
|
491
|
+
return console.error('Got an error: %s', error)
|
|
486
492
|
}
|
|
487
|
-
console.log('Tests run successfully')
|
|
488
|
-
})
|
|
493
|
+
console.log('Tests run successfully')
|
|
494
|
+
})
|
|
489
495
|
```
|
|
490
496
|
|
|
491
497
|
The callback `function(error, result)` will be invoked when the max number of requests is reached,
|
|
@@ -588,10 +594,12 @@ Use an agent with 'Connection: Keep-alive'.
|
|
|
588
594
|
Note: Uses [agentkeepalive](https://npmjs.org/package/agentkeepalive),
|
|
589
595
|
which performs better than the default node.js agent.
|
|
590
596
|
|
|
591
|
-
#### `quiet`
|
|
597
|
+
#### `quiet` (deprecated)
|
|
592
598
|
|
|
593
599
|
Do not show any messages.
|
|
594
600
|
|
|
601
|
+
Note: deprecated in version 6+, shows a warning.
|
|
602
|
+
|
|
595
603
|
#### `indexParam`
|
|
596
604
|
|
|
597
605
|
The given string will be replaced in the final URL with a unique index.
|
|
@@ -633,25 +641,25 @@ The TLS/SSL method to use. (e.g. TLSv1_method)
|
|
|
633
641
|
Example:
|
|
634
642
|
|
|
635
643
|
```javascript
|
|
636
|
-
|
|
644
|
+
import {loadTest} from 'loadtest'
|
|
637
645
|
|
|
638
646
|
const options = {
|
|
639
647
|
url: 'https://www.example.com',
|
|
640
648
|
maxRequests: 100,
|
|
641
649
|
secureProtocol: 'TLSv1_method'
|
|
642
|
-
}
|
|
650
|
+
}
|
|
643
651
|
|
|
644
|
-
|
|
652
|
+
loadTest(options, function(error) {
|
|
645
653
|
if (error) {
|
|
646
|
-
return console.error('Got an error: %s', error)
|
|
654
|
+
return console.error('Got an error: %s', error)
|
|
647
655
|
}
|
|
648
|
-
console.log('Tests run successfully')
|
|
649
|
-
})
|
|
656
|
+
console.log('Tests run successfully')
|
|
657
|
+
})
|
|
650
658
|
```
|
|
651
659
|
|
|
652
660
|
#### `statusCallback`
|
|
653
661
|
|
|
654
|
-
|
|
662
|
+
If present, this function executes after every request operation completes. Provides immediate access to test results while the
|
|
655
663
|
test batch is still running. This can be used for more detailed custom logging or developing your own spreadsheet or
|
|
656
664
|
statistical analysis of results.
|
|
657
665
|
|
|
@@ -668,28 +676,53 @@ You will need to check if `error` is populated in order to determine which objec
|
|
|
668
676
|
Example:
|
|
669
677
|
|
|
670
678
|
```javascript
|
|
671
|
-
|
|
679
|
+
import {loadTest} from 'loadtest'
|
|
672
680
|
|
|
673
681
|
function statusCallback(error, result, latency) {
|
|
674
|
-
console.log('Current latency %j, result %j, error %j', latency, result, error)
|
|
675
|
-
console.log('----')
|
|
676
|
-
console.log('Request elapsed milliseconds: ', result.requestElapsed)
|
|
677
|
-
console.log('Request index: ', result.requestIndex)
|
|
678
|
-
console.log('Request loadtest() instance index: ', result.instanceIndex)
|
|
682
|
+
console.log('Current latency %j, result %j, error %j', latency, result, error)
|
|
683
|
+
console.log('----')
|
|
684
|
+
console.log('Request elapsed milliseconds: ', result.requestElapsed)
|
|
685
|
+
console.log('Request index: ', result.requestIndex)
|
|
686
|
+
console.log('Request loadtest() instance index: ', result.instanceIndex)
|
|
679
687
|
}
|
|
680
688
|
|
|
681
689
|
const options = {
|
|
682
690
|
url: 'http://localhost:8000',
|
|
683
691
|
maxRequests: 1000,
|
|
684
692
|
statusCallback: statusCallback
|
|
685
|
-
}
|
|
693
|
+
}
|
|
686
694
|
|
|
687
|
-
|
|
695
|
+
loadTest(options, function(error) {
|
|
688
696
|
if (error) {
|
|
689
|
-
return console.error('Got an error: %s', error)
|
|
697
|
+
return console.error('Got an error: %s', error)
|
|
690
698
|
}
|
|
691
|
-
console.log('Tests run successfully')
|
|
692
|
-
})
|
|
699
|
+
console.log('Tests run successfully')
|
|
700
|
+
})
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
In some situations request data needs to be available in the statusCallBack.
|
|
705
|
+
This data can be assigned to `request.labels` in the requestGenerator:
|
|
706
|
+
```javascript
|
|
707
|
+
const options = {
|
|
708
|
+
// ...
|
|
709
|
+
requestGenerator: (params, options, client, callback) => {
|
|
710
|
+
// ...
|
|
711
|
+
const randomInputData = Math.random().toString().substr(2, 8);
|
|
712
|
+
const message = JSON.stringify({ randomInputData })
|
|
713
|
+
const request = client(options, callback);
|
|
714
|
+
request.labels = randomInputData;
|
|
715
|
+
request.write(message);
|
|
716
|
+
return request;
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
Then in statusCallBack the labels can be accessed through `result.labels`:
|
|
722
|
+
```javascript
|
|
723
|
+
function statusCallback(error, result, latency) {
|
|
724
|
+
console.log(result.labels);
|
|
725
|
+
}
|
|
693
726
|
```
|
|
694
727
|
|
|
695
728
|
**Warning**: The format for `statusCallback` has changed in version 2.0.0 onwards.
|
|
@@ -766,8 +799,8 @@ The second parameter contains info about the current request:
|
|
|
766
799
|
To start the test server use the exported function `startServer()` with a set of options and an optional callback:
|
|
767
800
|
|
|
768
801
|
```javascript
|
|
769
|
-
|
|
770
|
-
const server =
|
|
802
|
+
import {startServer} from 'loadtest'
|
|
803
|
+
const server = startServer({port: 8000})
|
|
771
804
|
```
|
|
772
805
|
|
|
773
806
|
This function returns an HTTP server which can be `close()`d when it is no longer useful.
|
|
@@ -831,11 +864,13 @@ The expected structure of the file is the following:
|
|
|
831
864
|
}
|
|
832
865
|
```
|
|
833
866
|
|
|
867
|
+
See sample file in `sample/.loadtestrc`.
|
|
868
|
+
|
|
834
869
|
For more information about the actual configuration file name, read the [confinode user manual](https://github.com/slune-org/confinode/blob/master/doc/en/usermanual.md#configuration-search). In the list of the [supported file types](https://github.com/slune-org/confinode/blob/master/doc/extensions.md), please note that only synchronous loaders can be used with _loadtest_.
|
|
835
870
|
|
|
836
871
|
### Complete Example
|
|
837
872
|
|
|
838
|
-
The file `
|
|
873
|
+
The file `test/integration.js` shows a complete example, which is also a full integration test:
|
|
839
874
|
it starts the server, send 1000 requests, waits for the callback and closes down the server.
|
|
840
875
|
|
|
841
876
|
## Versioning
|
package/bin/loadtest.js
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
*/
|
|
3
|
+
import {readFile} from 'fs/promises'
|
|
4
|
+
import * as stdio from 'stdio'
|
|
5
|
+
import {loadTest} from '../lib/loadtest.js'
|
|
8
6
|
|
|
9
|
-
// requires
|
|
10
|
-
const stdio = require('stdio');
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const urlLib = require('url');
|
|
14
|
-
const loadTest = require('../lib/loadtest.js');
|
|
15
|
-
const headers = require('../lib/headers.js');
|
|
16
|
-
const packageJson = require(__dirname + '/../package.json');
|
|
17
|
-
const config = require('../lib/config');
|
|
18
7
|
|
|
19
|
-
// init
|
|
20
8
|
const options = stdio.getopt({
|
|
21
9
|
maxRequests: {key: 'n', args: 1, description: 'Number of requests to perform'},
|
|
22
10
|
concurrency: {key: 'c', args: 1, description: 'Number of requests to make'},
|
|
@@ -39,156 +27,40 @@ const options = stdio.getopt({
|
|
|
39
27
|
version: {key: 'V', description: 'Show version number and exit'},
|
|
40
28
|
proxy: {args: 1, description: 'Use a proxy for requests e.g. http://localhost:8080 '},
|
|
41
29
|
rps: {args: 1, description: 'Specify the requests per second for each client'},
|
|
42
|
-
agent: {description: 'Use a keep-alive http agent (deprecated)'},
|
|
43
30
|
index: {args: 1, description: 'Replace the value of given arg with an index in the URL'},
|
|
44
|
-
quiet: {description: 'Do not log any messages'},
|
|
45
|
-
debug: {description: 'Show debug messages'},
|
|
46
31
|
insecure: {description: 'Allow self-signed certificates over https'},
|
|
47
32
|
key: {args: 1, description: 'The client key to use'},
|
|
48
|
-
cert: {args: 1, description: 'The client certificate to use'}
|
|
33
|
+
cert: {args: 1, description: 'The client certificate to use'},
|
|
34
|
+
agent: {description: 'Use a keep-alive http agent (deprecated)'},
|
|
35
|
+
quiet: {description: 'Do not log any messages (deprecated)'},
|
|
36
|
+
debug: {description: 'Show debug messages (deprecated)'}
|
|
49
37
|
});
|
|
50
|
-
if (options.version) {
|
|
51
|
-
console.log('Loadtest version: %s', packageJson.version);
|
|
52
|
-
process.exit(0);
|
|
53
|
-
}
|
|
54
|
-
// is there an url? if not, break and display help
|
|
55
|
-
if (!options.args || options.args.length < 1) {
|
|
56
|
-
console.error('Missing URL to load-test');
|
|
57
|
-
help();
|
|
58
|
-
} else if (options.args.length > 1) {
|
|
59
|
-
console.error('Too many arguments: %s', options.args);
|
|
60
|
-
help();
|
|
61
|
-
}
|
|
62
38
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
//TODO: add index Param
|
|
70
|
-
// Allow a post body string in options
|
|
71
|
-
// Ex -P '{"foo": "bar"}'
|
|
72
|
-
if (options.postBody) {
|
|
73
|
-
options.method = 'POST';
|
|
74
|
-
options.body = options.postBody;
|
|
75
|
-
}
|
|
76
|
-
if (options.postFile) {
|
|
77
|
-
options.method = 'POST';
|
|
78
|
-
options.body = readBody(options.postFile, '-p');
|
|
79
|
-
}
|
|
80
|
-
if (options.data) {
|
|
81
|
-
options.body = JSON.parse(options.data);
|
|
82
|
-
}
|
|
83
|
-
if (options.method) {
|
|
84
|
-
const acceptedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'get', 'post', 'put', 'delete', 'patch'];
|
|
85
|
-
if (acceptedMethods.indexOf(options.method) === -1) {
|
|
86
|
-
options.method = 'GET';
|
|
39
|
+
async function processAndRun(options) {
|
|
40
|
+
if (options.version) {
|
|
41
|
+
const packageJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url)))
|
|
42
|
+
console.log('Loadtest version: %s', packageJson.version);
|
|
43
|
+
process.exit(0);
|
|
87
44
|
}
|
|
88
|
-
|
|
89
|
-
if(options.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
options.method = 'PATCH';
|
|
95
|
-
options.body = options.patchBody;
|
|
96
|
-
}
|
|
97
|
-
if(options.patchFile) {
|
|
98
|
-
options.method = 'PATCH';
|
|
99
|
-
options.body = readBody(options.patchFile, '-a');
|
|
100
|
-
}
|
|
101
|
-
if(!options.method) {
|
|
102
|
-
options.method = configuration.method;
|
|
103
|
-
}
|
|
104
|
-
if(!options.body) {
|
|
105
|
-
if(configuration.body) {
|
|
106
|
-
options.body = configuration.body;
|
|
107
|
-
} else if(configuration.file) {
|
|
108
|
-
options.body = readBody(configuration.file, 'configuration.request.file');
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
options.requestsPerSecond = options.rps ? parseFloat(options.rps) : configuration.requestsPerSecond;
|
|
112
|
-
if(!options.key) {
|
|
113
|
-
options.key = configuration.key;
|
|
114
|
-
}
|
|
115
|
-
if(options.key) {
|
|
116
|
-
options.key = fs.readFileSync(options.key);
|
|
117
|
-
}
|
|
118
|
-
if(!options.cert) {
|
|
119
|
-
options.cert = configuration.cert;
|
|
120
|
-
}
|
|
121
|
-
if(options.cert) {
|
|
122
|
-
options.cert = fs.readFileSync(options.cert);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const defaultHeaders = options.headers || !configuration.headers ? {} : configuration.headers;
|
|
126
|
-
defaultHeaders['host'] = urlLib.parse(options.url).host;
|
|
127
|
-
defaultHeaders['user-agent'] = 'loadtest/' + packageJson.version;
|
|
128
|
-
defaultHeaders['accept'] = '*/*';
|
|
129
|
-
|
|
130
|
-
if (options.headers) {
|
|
131
|
-
headers.addHeaders(options.headers, defaultHeaders);
|
|
132
|
-
console.log('headers: %s, %j', typeof defaultHeaders, defaultHeaders);
|
|
133
|
-
}
|
|
134
|
-
options.headers = defaultHeaders;
|
|
135
|
-
|
|
136
|
-
if (!options.requestGenerator) {
|
|
137
|
-
options.requestGenerator = configuration.requestGenerator;
|
|
138
|
-
}
|
|
139
|
-
if (options.requestGenerator) {
|
|
140
|
-
options.requestGenerator = require(path.resolve(options.requestGenerator));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Use configuration file for other values
|
|
144
|
-
if(!options.maxRequests) {
|
|
145
|
-
options.maxRequests = configuration.maxRequests;
|
|
146
|
-
}
|
|
147
|
-
if(!options.concurrency) {
|
|
148
|
-
options.concurrency = configuration.concurrency;
|
|
149
|
-
}
|
|
150
|
-
if(!options.maxSeconds) {
|
|
151
|
-
options.maxSeconds = configuration.maxSeconds;
|
|
152
|
-
}
|
|
153
|
-
if(!options.timeout && configuration.timeout) {
|
|
154
|
-
options.timeout = configuration.timeout;
|
|
155
|
-
}
|
|
156
|
-
if(!options.contentType) {
|
|
157
|
-
options.contentType = configuration.contentType;
|
|
158
|
-
}
|
|
159
|
-
if(!options.cookies) {
|
|
160
|
-
options.cookies = configuration.cookies;
|
|
161
|
-
}
|
|
162
|
-
if(!options.secureProtocol) {
|
|
163
|
-
options.secureProtocol = configuration.secureProtocol;
|
|
164
|
-
}
|
|
165
|
-
if(!options.insecure) {
|
|
166
|
-
options.insecure = configuration.insecure;
|
|
167
|
-
}
|
|
168
|
-
if(!options.recover) {
|
|
169
|
-
options.recover = configuration.recover;
|
|
170
|
-
}
|
|
171
|
-
if(!options.proxy) {
|
|
172
|
-
options.proxy = configuration.proxy;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
loadTest.loadTest(options);
|
|
176
|
-
|
|
177
|
-
function readBody(filename, option) {
|
|
178
|
-
if (typeof filename !== 'string') {
|
|
179
|
-
console.error('Invalid file to open with %s: %s', option, filename);
|
|
45
|
+
// is there an url? if not, break and display help
|
|
46
|
+
if (!options.args || options.args.length < 1) {
|
|
47
|
+
console.error('Missing URL to load-test');
|
|
48
|
+
help();
|
|
49
|
+
} else if (options.args.length > 1) {
|
|
50
|
+
console.error('Too many arguments: %s', options.args);
|
|
180
51
|
help();
|
|
181
52
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
53
|
+
options.url = options.args[0];
|
|
54
|
+
try {
|
|
55
|
+
loadTest(options)
|
|
56
|
+
} catch(error) {
|
|
57
|
+
console.error(error.message)
|
|
58
|
+
help()
|
|
185
59
|
}
|
|
186
|
-
|
|
187
|
-
const ret = fs.readFileSync(filename, {encoding: 'utf8'}).replace("\n", "");
|
|
188
|
-
|
|
189
|
-
return ret;
|
|
190
60
|
}
|
|
191
61
|
|
|
62
|
+
await processAndRun(options)
|
|
63
|
+
|
|
192
64
|
/**
|
|
193
65
|
* Show online help.
|
|
194
66
|
*/
|
package/bin/testserver.js
CHANGED
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
3
|
+
import * as stdio from 'stdio'
|
|
4
|
+
import {startServer} from '../lib/testserver.js'
|
|
5
|
+
import {loadConfig} from '../lib/config.js'
|
|
8
6
|
|
|
9
|
-
// requires
|
|
10
|
-
const stdio = require('stdio');
|
|
11
|
-
const testServer = require('../lib/testserver');
|
|
12
|
-
const config = require('../lib/config')
|
|
13
7
|
|
|
14
|
-
// init
|
|
15
8
|
const options = stdio.getopt({
|
|
16
9
|
delay: {key: 'd', args: 1, description: 'Delay the response for the given milliseconds'},
|
|
17
10
|
error: {key: 'e', args: 1, description: 'Return an HTTP error code'},
|
|
18
11
|
percent: {key: 'p', args: 1, description: 'Return an error (default 500) only for some % of requests'},
|
|
19
12
|
});
|
|
20
|
-
const configuration =
|
|
13
|
+
const configuration = loadConfig()
|
|
21
14
|
if (options.args && options.args.length == 1) {
|
|
22
15
|
options.port = parseInt(options.args[0], 10);
|
|
23
16
|
if (!options.port) {
|
|
@@ -45,5 +38,5 @@ if(!options.percent) {
|
|
|
45
38
|
options.percent = configuration.percent
|
|
46
39
|
}
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
startServer(options);
|
|
49
42
|
|
package/index.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import {loadTest} from './lib/loadtest.js'
|
|
2
|
+
import {startServer} from './lib/testserver.js'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
* Package contains a load test script and a test server.
|
|
5
|
-
* (C) 2013 Alex Fernández.
|
|
6
|
-
*/
|
|
4
|
+
const loadtest = {loadTest, startServer}
|
|
7
5
|
|
|
6
|
+
export default loadtest
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const testserver = require('./lib/testserver.js');
|
|
12
|
-
|
|
13
|
-
// exports
|
|
14
|
-
exports.loadTest = loadtest.loadTest;
|
|
15
|
-
exports.startServer = testserver.startServer;
|
|
8
|
+
export * from './lib/loadtest.js'
|
|
9
|
+
export * from './lib/testserver.js'
|
|
16
10
|
|
package/lib/baseClient.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import * as urlLib from 'url'
|
|
2
|
+
import {addUserAgent} from './headers.js'
|
|
2
3
|
|
|
3
|
-
const urlLib = require('url');
|
|
4
|
-
const Log = require('log');
|
|
5
|
-
const headers = require('./headers.js');
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
const log = new Log('info');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class BaseClient {
|
|
5
|
+
export class BaseClient {
|
|
12
6
|
constructor(operation, params) {
|
|
13
7
|
this.operation = operation;
|
|
14
8
|
this.params = params;
|
|
@@ -22,14 +16,11 @@ class BaseClient {
|
|
|
22
16
|
return (error, result) => {
|
|
23
17
|
let errorCode = null;
|
|
24
18
|
if (error) {
|
|
25
|
-
log.debug('Connection %s failed: %s', id, error);
|
|
26
19
|
if (result) {
|
|
27
20
|
errorCode = result;
|
|
28
21
|
} else {
|
|
29
22
|
errorCode = '-1';
|
|
30
23
|
}
|
|
31
|
-
} else {
|
|
32
|
-
log.debug('Connection %s ended', id);
|
|
33
24
|
}
|
|
34
25
|
this.operation.latency.end(id, errorCode);
|
|
35
26
|
let callback;
|
|
@@ -56,28 +47,20 @@ class BaseClient {
|
|
|
56
47
|
this.options.agent = false;
|
|
57
48
|
if (this.params.body) {
|
|
58
49
|
if (typeof this.params.body == 'string') {
|
|
59
|
-
log.debug('Received string body');
|
|
60
50
|
this.generateMessage = () => this.params.body;
|
|
61
51
|
} else if (typeof this.params.body == 'object') {
|
|
62
|
-
log.debug('Received JSON body');
|
|
63
52
|
this.generateMessage = () => this.params.body;
|
|
64
53
|
} else if (typeof this.params.body == 'function') {
|
|
65
|
-
log.debug('Received function body');
|
|
66
54
|
this.generateMessage = this.params.body;
|
|
67
55
|
} else {
|
|
68
|
-
|
|
56
|
+
console.error('Unrecognized body: %s', typeof this.params.body);
|
|
69
57
|
}
|
|
70
58
|
this.options.headers['Content-Type'] = this.params.contentType || 'text/plain';
|
|
71
59
|
}
|
|
72
|
-
|
|
60
|
+
addUserAgent(this.options.headers);
|
|
73
61
|
if (this.params.secureProtocol) {
|
|
74
62
|
this.options.secureProtocol = this.params.secureProtocol;
|
|
75
63
|
}
|
|
76
|
-
log.debug('Options: %j',this.options);
|
|
77
64
|
}
|
|
78
65
|
}
|
|
79
66
|
|
|
80
|
-
module.exports = {
|
|
81
|
-
BaseClient,
|
|
82
|
-
}
|
|
83
|
-
|
package/lib/config.js
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Support for configuration file.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// requires
|
|
8
|
-
const Log = require("log");
|
|
9
|
-
const {
|
|
1
|
+
import {
|
|
10
2
|
Confinode,
|
|
11
3
|
Level,
|
|
12
4
|
anyItem,
|
|
@@ -18,21 +10,13 @@ const {
|
|
|
18
10
|
numberItem,
|
|
19
11
|
optional,
|
|
20
12
|
stringItem
|
|
21
|
-
}
|
|
13
|
+
} from 'confinode'
|
|
22
14
|
|
|
23
|
-
// globals
|
|
24
|
-
const log = new Log("info");
|
|
25
15
|
|
|
26
16
|
/**
|
|
27
17
|
* Load configuration from file.
|
|
28
18
|
*/
|
|
29
|
-
|
|
30
|
-
if (options.debug) {
|
|
31
|
-
log.level = Log.DEBUG;
|
|
32
|
-
}
|
|
33
|
-
if (options.quiet) {
|
|
34
|
-
log.level = Log.NOTICE;
|
|
35
|
-
}
|
|
19
|
+
export function loadConfig() {
|
|
36
20
|
const description = literal({
|
|
37
21
|
delay: numberItem(0),
|
|
38
22
|
error: numberItem(0),
|
|
@@ -61,7 +45,7 @@ exports.loadConfig = function(options) {
|
|
|
61
45
|
const confinode = new Confinode("loadtest", description, { logger, mode: "sync" });
|
|
62
46
|
const result = confinode.search();
|
|
63
47
|
return result ? result.configuration : {};
|
|
64
|
-
}
|
|
48
|
+
}
|
|
65
49
|
|
|
66
50
|
/**
|
|
67
51
|
* Logging function of confinode.
|
|
@@ -69,16 +53,16 @@ exports.loadConfig = function(options) {
|
|
|
69
53
|
function logger(msg) {
|
|
70
54
|
switch (msg.Level) {
|
|
71
55
|
case Level.Error:
|
|
72
|
-
|
|
56
|
+
console.error(msg.toString());
|
|
73
57
|
break;
|
|
74
58
|
case Level.Warning:
|
|
75
|
-
|
|
59
|
+
console.warn(msg.toString());
|
|
76
60
|
break;
|
|
77
61
|
case Level.Information:
|
|
78
|
-
|
|
62
|
+
console.info(msg.toString());
|
|
79
63
|
break;
|
|
80
64
|
default:
|
|
81
|
-
|
|
65
|
+
// nothing
|
|
82
66
|
}
|
|
83
67
|
}
|
|
84
68
|
|
|
@@ -99,3 +83,4 @@ class CookieDescription {
|
|
|
99
83
|
}
|
|
100
84
|
}
|
|
101
85
|
}
|
|
86
|
+
|